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

diff -urN linux-2.4.20-pre1/Documentation/Configure.help linux-2.4.20-pre2/Documentation/Configure.help
--- linux-2.4.20-pre1/Documentation/Configure.help	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/Documentation/Configure.help	Mon Aug 12 16:34:14 2002
@@ -373,6 +373,12 @@
   Select this if you have a 32-bit processor and more than 4
   gigabytes of physical RAM.
 
+HIGHMEM I/O support
+CONFIG_HIGHIO
+  If you want to be able to do I/O to high memory pages, say Y.
+  Otherwise low memory pages are used as bounce buffers causing a
+  degrade in performance.
+
 Normal floppy disk support
 CONFIG_BLK_DEV_FD
   If you want to use the floppy disk drive(s) of your PC under Linux,
@@ -531,6 +537,17 @@
 
   If unsure, say N.
 
+Per partition statistics in /proc/partitions
+CONFIG_BLK_STATS
+  If you say yes here, your kernel will keep statistical information
+  for every partition. The information includes things as numbers of
+  read and write accesses, thenumber of merged requests etc.
+
+  This is required for the full functionality of sar(8) and interesting
+  if you want to do performance tuning, by tweaking the elevator, e.g.
+
+  If unsure, say N.
+
 ATA/IDE/MFM/RLL support
 CONFIG_IDE
   If you say Y here, your kernel will be able to manage low cost mass
@@ -2490,6 +2507,17 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+skb->pkt_type packet match support
+CONFIG_IP_NF_MATCH_PKTTYPE
+  This patch allows you to match packet in accrodance
+  to its "class", eg. BROADCAST, MULTICAST, ...
+  
+  Typical usage:
+  iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
+  
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 MAC address match support
 CONFIG_IP_NF_MATCH_MAC
   MAC matching allows you to match packets based on the source
@@ -2540,6 +2568,28 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
+DSCP match support
+CONFIG_IP_NF_TARGET_DSCP
+  This option adds a `DSCP' match, which allows you to match against
+  the IPv4 header DSCP field (DSCP codepoint).
+
+  The DSCP codepoint can have any value between 0x0 and 0x4f.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+ 
+
+ECN match support
+CONFIG_IP_NF_MATCH_ECN
+  This option adds a `ECN' match, which allows you to match against
+  the IPv4 and TCP header ECN fields.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+ 
+
 TOS match support
 CONFIG_IP_NF_MATCH_TOS
   TOS matching allows you to match packets based on the Type Of
@@ -2548,6 +2598,18 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+conntrack match support
+CONFIG_IP_NF_MATCH_CONNTRACK
+  This is a general conntrack match module, a superset of the state match.
+
+  It allows matching on additional conntrack information, which is
+  useful in complex configurations, such as NAT gateways with multiple
+  internet links or tunnels.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+
 Connection state match support
 CONFIG_IP_NF_MATCH_STATE
   Connection state matching allows you to match packets based on their
@@ -2665,6 +2727,36 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+DSCP target support
+CONFIG_IP_NF_TARGET_DSCP
+  This option adds a `DSCP' target, which allows you to create rules in
+  the iptables mangle table. The selected packet has the DSCP field set
+  to the hex value provided on the command line; unlike the TOS target
+  which will only set the legal values within ip.h.
+
+  The DSCP field can be set to any value between 0x0 and 0x4f. It does
+  take into account that bits 6 and 7 are used by ECN.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+ 
+
+ECN target support
+CONFIG_IP_NF_TARGET_ECN
+  This option adds a `ECN' target, which can be used in the iptables mangle
+  table.  
+
+  You can use this target to remove the ECN bits from the IPv4 header of
+  an IP packet.  This is particularly useful, if you need to work around
+  existing ECN blackholes on the internet, but don't want to disable
+  ECN support in general.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+ 
+
 TOS target support
 CONFIG_IP_NF_TARGET_TOS
   This option adds a `TOS' target, which allows you to create rules in
@@ -2711,6 +2803,14 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+Helper match support
+CONFIG_IP_NF_MATCH_HELPER
+  Helper matching allows you to match packets in dynamic connections
+  tracked by a conntrack-helper, ie. ip_conntrack_ftp
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `Y'.
+
 TCPMSS match support
 CONFIG_IP_NF_MATCH_TCPMSS
   This option adds a `tcpmss' match, which allows you to examine the
@@ -2763,6 +2863,15 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+EUI64 address check (EXPERIMENTAL)
+CONFIG_IP6_NF_MATCH_EUI64
+  This module performs checking on the IPv6 source address
+  Compares the last 64 bits with the EUI64 (delivered
+  from the MAC address) address
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 MAC address match support
 CONFIG_IP6_NF_MATCH_MAC
   mac matching allows you to match packets based on the source
@@ -2771,6 +2880,14 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+length match support
+CONFIG_IP6_NF_MATCH_LENGTH
+  This option allows you to match the length of a packet against a
+  specific value or range of values.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 Netfilter MARK match support
 CONFIG_IP6_NF_MATCH_MARK
   Netfilter mark matching allows you to match packets based on the
@@ -10485,12 +10602,14 @@
   in case your mainboard has memory consistency issues.  If unsure,
   say N.
 
-Support for automatic channel equalization
+Support for uncommon RTL-8139 rev. K (automatic channel equalization)
 CONFIG_8139TOO_TUNE_TWISTER
-  This implements a function which might come in handy in case you are
-  using low quality on long cabling. It tries to match the transceiver
-  to the cable characteristics. This is experimental since hardly
-  documented by the manufacturer.  If unsure, say N.
+  This implements a function which might come in handy in case you
+  are using low quality on long cabling. It is required for RealTek
+  RTL-8139 revision K boards, and totally unused otherwise.  It tries
+  to match the transceiver to the cable characteristics. This is
+  experimental since hardly documented by the manufacturer.
+  If unsure, say Y.
 
 Support for older RTL-8129/8130 boards
 CONFIG_8139TOO_8129
@@ -10499,6 +10618,14 @@
   instead of an internal one.  Disabling this option will save some
   memory by making the code size smaller.  If unsure, say Y.
 
+Use older RX-reset method
+CONFIG_8139_OLD_RX_RESET
+  The 8139too driver was recently updated to contain a more rapid
+  reset sequence, in the face of severe receive errors.  This "new"
+  RX-reset method should be adequate for all boards.  But if you
+  experience problems, you can enable this option to restore the
+  old RX-reset behavior.  If unsure, say N.
+
 SiS 900/7016 PCI Fast Ethernet Adapter support
 CONFIG_SIS900
   This is a driver for the Fast Ethernet PCI network cards based on
@@ -13119,9 +13246,9 @@
   The module will be called wacom.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-Aiptek 8000U tablet support
+Aiptek 6000U/8000U tablet support
 CONFIG_USB_AIPTEK
-  Say Y here if you want to use the USB version of the Aiptek 8000U
+  Say Y here if you want to use the USB version of the Aiptek 6000U/8000U
   tablet.  Make sure to say Y to "Event interface support"
   (CONFIG_INPUT_EVDEV) as well.
 
@@ -13961,6 +14088,25 @@
   The module will be called rio500.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+CONFIG_USB_TIGL
+  If you own a Texas Instruments graphing calculator and use a 
+  TI-GRAPH LINK USB cable (aka SilverLink), then you might be 
+  interested in this driver.
+
+  If you enable this driver, you will be able to communicate with
+  your calculator through a set of device nodes under /dev.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tiglusb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+  If you don't know what the SilverLink cable is or what a Texas
+  Instruments graphing calculator is, then you probably don't need this
+  driver.
+
+  If unsure, say N.
+
 Tieman Voyager USB Braille display support
 CONFIG_USB_BRLVOYAGER
   Say Y here if you want to use the Voyager USB Braille display from
@@ -14314,12 +14460,13 @@
 
 Publish some reiserfs-specific info under /proc/fs/reiserfs
 CONFIG_REISERFS_PROC_INFO
-  Create under /proc/fs/reiserfs hierarchy of files, displaying
-  various ReiserFS statistics and internal data on the expense of
-  making your kernel or module slightly larger (+8 KB).  This also
-  increases amount of kernel memory required for each mount.  Almost
-  everyone but ReiserFS developers and people fine-tuning reiserfs or
-  tracing problems should say N.
+  Create under /proc/fs/reiserfs a hierarchy of files, displaying
+  various ReiserFS statistics and internal data at the expense of making
+  your kernel or module slightly larger (+8 KB). This also increases the
+  amount of kernel memory required for each mount by 440 bytes.
+  It isn't useful to average persons, and you probably can't measure the
+  performance cost of it.  If you are fine-tuning reiserfs, say Y,
+  otherwise say N.
 
 Second extended fs support
 CONFIG_EXT2_FS
@@ -15345,9 +15492,11 @@
 
 IBM disk label and partition support
 CONFIG_IBM_PARTITION
-  Say Y here if you would like to be able to read the hard disk
-  partition table format used by IBM DASD disks operating under CMS.
-  Otherwise, say N.
+  You have to say Y here if you would like to be able to read volume 
+  labels of IBM DASD disks. These can be ECKD DASD disks with 
+  compatible disk layout (cdl) and standard Linux disk layout (ldl), 
+  FBA DASD disks and CMS reserved minidisks.
+  Otherwise, say N and you will not be able to access these disks.
 
 ADFS file system support
 CONFIG_ADFS_FS
@@ -20259,7 +20408,7 @@
 
 Kernel support for 32-bit ELF binaries
 CONFIG_BINFMT_ELF32
-  This allows you to run 32-bit Linux/ELF binaries on your Ultra.
+  This allows you to run 32-bit Linux/ELF binaries on your machine.
   Everybody wants this; say Y.
 
 Kernel support for 32-bit (ie. SunOS) a.out binaries
@@ -20345,7 +20494,7 @@
 DBRI Lowlevel Driver
 CONFIG_SPARCAUDIO_DBRI
   This driver supports the DBRI audio interface found on the SS10,
-  SS20, Sparcbook 3, and Voyager systems.
+  SS20, LX, Sparcbook 3, and Voyager systems.
 
 Dummy Lowlevel Driver
 CONFIG_SPARCAUDIO_DUMMY
@@ -22380,7 +22529,7 @@
   IPL device on another question, that pops up, when you select
   CONFIG_IPL.
 
-IPL from a /390 tape unit
+IPL from a S/390 tape unit
 CONFIG_IPL_TAPE
   Select this option if you want to IPL the image from a Tape.
 
@@ -22389,18 +22538,22 @@
   Select this option if you are running under VM/ESA and want 
   to IPL the image from the emulated card reader.
 
-Support for DASD hard disks
-CONFIG_DASD
-  Enable this option if you want to access DASDs directly utilizing
-  S/390s channel subsystem commands. This is necessary for running
-  natively on a single image or an LPAR.
+CONFIG_PFAULT
+  Select this option, if you want to use PFAULT pseudo page fault
+  handling under VM. If running native or in LPAR, this option
+  has no effect. If your VM does not support PFAULT, PAGEEX
+  pseudo page fault handling will be used.
+  Note that VM 4.2 supports PFAULT but has a bug in its
+  implementation that causes some problems.
+  Everybody who wants to run Linux under VM != VM4.2 should select
+  this option.
 
-Enable DASD fast write
-CONFIG_DASD_FAST_IO
-  Enable fast I/O for DASDs. That means that the next I/O command
-  is already issued at interrupt time, if an I/O request is pending.
-  This option gives significant speedup of I/O, because we don't
-  schedule the bottom-halves as often as Intel.
+CONFIG_SHARED_KERNEL
+  Select this option, if you want to share the text segment of the
+  Linux kernel between different VM guests. This reduces memory
+  usage with lots of guests but greatly increases kernel size.
+  You should only select this option if you know what you are
+  doing and want to exploit this feature.
 
 Support for IBM-style disk-labels (S/390)
 CONFIG_S390_PARTITION
@@ -22409,18 +22562,40 @@
   attached to another IBM mainframe operation system (OS/390, 
   VM/ESA, VSE/ESA).
 
+Support for DASD hard disks
+CONFIG_DASD
+  Enable this option if you want to access DASDs directly utilizing
+  S/390s channel subsystem commands. This is necessary for running
+  natively on a single image or an LPAR.
+
 Support for ECKD hard disks
 CONFIG_DASD_ECKD
-  ECKD devices are the most commonly used devices. You should enable
-  this option unless you are very sure you have no ECKD device.
-
-CKD devices
-CONFIG_DASD_CKD
-  CKD devices are currently unsupported.
+  ECKD (Extended Count Key Data) devices are the most commonly used 
+  devices on S/390s. You should enable this option unless you are 
+  very sure you have no ECKD device.
+
+ECKD demand loading
+CONFIG_DASD_AUTO_ECKD
+  This option enables demand loading of the ECKD module. 
 
 Support for FBA hard disks
 CONFIG_DASD_FBA
-  FBA devices are currently unsupported.
+  Select this option if you want to use FBA (Fixed Block) devices.
+  If you are not sure what it is, say "Y".
+
+FBA demand loading
+CONFIG_DASD_AUTO_FBA
+  This option enables demand loading of the FBA module. 
+
+Support for DIAG access to CMS reserved Disks
+CONFIG_DASD_DIAG
+  Select this option if you want to use CMS reserved Disks under VM
+  with the Diagnose250 command.  If you are not running under VM or
+  unsure what it is, say "N".
+
+DIAG demand loading
+CONFIG_DASD_AUTO_DIAG
+  This option enables demand loading of the DIAG module. 
 
 Merge some code into the kernel to make the image IPLable
 CONFIG_IPLABLE
@@ -22458,6 +22633,16 @@
   Include support for using an IBM HWC line-mode terminal as the Linux
   system console.
 
+Control Program Identification
+CONFIG_HWC_CPI
+  Allows for Control Program Identification via the HWC interface,
+  i.e. provides a mean to pass an OS instance name (system name)
+  to the machine.
+
+  This option should only be selected as a module since the
+  system name has to be passed as module parameter. The module
+  will be called hwc_cpi.o.
+
 S/390 tape device support
 CONFIG_S390_TAPE
   Select this option if you want to access channel-attached tape
@@ -22466,8 +22651,9 @@
   least one of the tape interface options and one of the tape
   hardware options in order to access a tape device.
   This option is also available as a module. The module will be
-  called tape390.o and include all selected interfaces and
-  hardware drivers.
+  called tape390.o and include all selected interfaces.
+  The hardware drivers will be seperate modules.
+  If unsure, say "Y".
 
 Support for tape character devices
 CONFIG_S390_TAPE_CHAR
@@ -22488,14 +22674,23 @@
 
 Support for 3490 tape hardware
 CONFIG_S390_TAPE_3490
-  Select this option if you want to access IBM 3480 magnetic
+  Select this option if you want to access IBM 3490 magnetic
   tape subsystems and 100% compatibles.
+  This option is also available as a module. The module will be
+  called tape3490.o. If CONFIG_S390_TAPE is selected as a module,
+  this hardware driver cannot be built-in but is only available
+  as a module.
   It is safe to say "Y" here.
 
 Support for 3480 tape hardware
 CONFIG_S390_TAPE_3480
-  Select this option if you want to access IBM 3490 magnetic
+  Select this option if you want to access IBM 3480 magnetic
   tape subsystems and 100% compatibles.
+  This option is also available as a module. The module will be
+  called tape3480.o. If CONFIG_S390_TAPE is selected as a module,
+  this hardware driver cannot be built-in but is only available
+  as a module.
+  It is safe to say "Y" here.
 
 CTC device support
 CONFIG_CTC
@@ -22506,12 +22701,6 @@
   available.  This option is also available as a module which will be
   called ctc.o.  If you do not know what it is, it's safe to say "Y".
 
-Support for DIAG access to CMS reserved Disks
-CONFIG_DASD_DIAG
-  Select this option if you want to use CMS reserved Disks under VM
-  with the Diagnose250 command.  If you are not running under VM or
-  unsure what it is, say "N".
-
 XPRAM disk support
 CONFIG_BLK_DEV_XPRAM
   Select this option if you want to use your expanded storage on S/390
@@ -22534,6 +22723,20 @@
   vehicle networking under VM or VIF.  This option is also available
   as a module which will be called iucv.o. If unsure, say "Y".
 
+Process warning machine checks
+CONFIG_MACHCHK_WARNING
+  Select this option if you want the machine check handler on IBM S/390 or 
+  zSeries to process warning machine checks (e.g. on power failures). 
+  If unsure, say "Y".
+
+Use chscs for Common I/O
+CONFIG_CHSC
+  Select this option if you want the s390 common I/O layer to use information
+  obtained by channel subsystem calls. This will enable Linux to process link
+  failures and resource accessibility events. Moreover, if you have procfs
+  enabled, you'll be able to toggle chpids logically offline and online. Even
+  if you don't understand what this means, you should say "Y".
+
 Kernel support for 31 bit ELF binaries
 CONFIG_S390_SUPPORT
   Select this option if you want to enable your system kernel to
@@ -22996,6 +23199,11 @@
   It is recommended to be used on a NetWinder, but it is not a
   necessity.
 
+Check for stack overflows
+CONFIG_DEBUG_STACKOVERFLOW
+  This option make do_IRQ() check for enough stack space beeing left.
+  This is safe to enable.
+
 Debug high memory support
 CONFIG_DEBUG_HIGHMEM
   This options enables addition error checking for high memory systems.
@@ -23524,6 +23732,18 @@
   used by IrTTY.  To activate support for Parallax dongles you will
   have to start irattach like this "irattach -d litelink".
 
+Microchip MCP2120 dongle
+CONFIG_MCP2120_DONGLE
+  Say Y here if you want to build support for the Microchip MCP2120
+  dongle.  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The MCP2120 dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY.  To activate support for MCP2120 dongles you will
+  have to insert "irattach -d mcp2120" in the /etc/irda/drivers script.
+
+  You must build this dongle yourself.  For more information see:
+  <http://www.eyetap.org/~tangf/irda_sir_linux.html>
+
 Old Belkin dongle
 CONFIG_OLD_BELKIN_DONGLE
   Say Y here if you want to build support for the Adaptec Airport 1000
@@ -23531,6 +23751,30 @@
   and read <file:Documentation/modules.txt>.  The module will be
   called old_belkin.o.  Some information is contained in the comments
   at the top of <file:drivers/net/irda/old_belkin.c>.
+ 
+ACTiSYS IR-200L dongle (Experimental)
+CONFIG_ACT200L_DONGLE
+  Say Y here if you want to build support for the ACTiSYS IR-200L
+  dongle. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The ACTiSYS IR-200L dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY. To activate support for ACTiSYS IR-200L dongles
+  you will have to start irattach like this: "irattach -d act200l".
+
+Mobile Action MA600 dongle (Experimental)
+CONFIG_MA600_DONGLE
+  Say Y here if you want to build support for the Mobile Action MA600
+  dongle.  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The MA600 dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  tested on IrCOMM.  To activate support for MA600 dongles you will
+  have to insert "irattach -d ma600" in the /etc/irda/drivers script.
+  Note: irutils 0.9.15 requires no modification. irutils 0.9.9 needs
+  modification. For more information, download the following tar gzip
+  file.
+
+  There is a pre-compiled module on
+  <http://engsvr.ust.hk/~eetwl95/download/ma600-2.4.x.tar.gz>
 
 VME (Motorola and BVM) support
 CONFIG_VME
diff -urN linux-2.4.20-pre1/Documentation/DocBook/kernel-hacking.tmpl linux-2.4.20-pre2/Documentation/DocBook/kernel-hacking.tmpl
--- linux-2.4.20-pre1/Documentation/DocBook/kernel-hacking.tmpl	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/Documentation/DocBook/kernel-hacking.tmpl	Mon Aug 12 16:34:14 2002
@@ -1091,18 +1091,17 @@
    <title>Initializing structure members</title>
 
    <para>
-    The preferred method of initializing structures is to use the
-    gcc Labeled Elements extension, eg:
+    The preferred method of initializing structures is to use
+    designated initialisers, as defined by ISO C99, eg:
    </para>
    <programlisting>
 static struct block_device_operations opt_fops = {
-        open:                   opt_open,
-        release:                opt_release,
-        ioctl:                  opt_ioctl,
-        check_media_change:     opt_media_change,
+        .open               = opt_open,
+        .release            = opt_release,
+        .ioctl              = opt_ioctl,
+        .check_media_change = opt_media_change,
 };
    </programlisting>
-
    <para>
     This makes it easy to grep for, and makes it clear which
     structure fields are set.  You should do this because it looks
diff -urN linux-2.4.20-pre1/Documentation/SubmittingPatches linux-2.4.20-pre2/Documentation/SubmittingPatches
--- linux-2.4.20-pre1/Documentation/SubmittingPatches	Sun Dec  3 17:48:18 2000
+++ linux-2.4.20-pre2/Documentation/SubmittingPatches	Mon Aug 12 16:34:14 2002
@@ -161,7 +161,7 @@
 When sending patches to Linus, always follow step #6.
 
 Large changes are not appropriate for mailing lists, and some
-maintainers.  If your patch, uncompressed, exceeds 40Kb in size,
+maintainers.  If your patch, uncompressed, exceeds 40 kB in size,
 it is preferred that you store your patch on an Internet-accessible
 server, and provide instead a URL (link) pointing to your patch.
 
diff -urN linux-2.4.20-pre1/Documentation/filesystems/00-INDEX linux-2.4.20-pre2/Documentation/filesystems/00-INDEX
--- linux-2.4.20-pre1/Documentation/filesystems/00-INDEX	Wed Jun 20 11:10:27 2001
+++ linux-2.4.20-pre2/Documentation/filesystems/00-INDEX	Mon Aug 12 16:34:14 2002
@@ -6,6 +6,8 @@
 	- info and mount options for the Acorn Advanced Disc Filing System.
 affs.txt
 	- info and mount options for the Amiga Fast File System.
+befs.txt
+	- info for the BeOS file system (BFS)
 bfs.txt
 	- info for the SCO UnixWare Boot Filesystem (BFS).
 coda.txt
diff -urN linux-2.4.20-pre1/Documentation/ide.txt linux-2.4.20-pre2/Documentation/ide.txt
--- linux-2.4.20-pre1/Documentation/ide.txt	Fri Sep  7 09:28:38 2001
+++ linux-2.4.20-pre2/Documentation/ide.txt	Mon Aug 12 16:34:14 2002
@@ -306,6 +306,9 @@
  "idex=serialize"	: do not overlap operations on idex and ide(x^1)
  "idex=reset"		: reset interface after probe
  "idex=dma"		: automatically configure/use DMA if possible.
+ "idex=nohighio"	: don't use i/o to high memory addresses on this
+			 	interface. i/o to memory locations higher
+				than ~860MiB will be bounced.
 
  The following are valid ONLY on ide0,
  and the defaults for the base,ctl ports must not be altered.
diff -urN linux-2.4.20-pre1/Documentation/networking/00-INDEX linux-2.4.20-pre2/Documentation/networking/00-INDEX
--- linux-2.4.20-pre1/Documentation/networking/00-INDEX	Thu Feb  8 16:32:44 2001
+++ linux-2.4.20-pre2/Documentation/networking/00-INDEX	Mon Aug 12 16:34:14 2002
@@ -44,6 +44,10 @@
 	- the Digi International RightSwitch SE-X Ethernet driver
 dmfe.txt
 	- info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver.
+e100.txt
+	- info on Intel's EtherExpress PRO/100 line of 10/100 boards
+e1000.txt
+	- info on Intel's E1000 line of gigabit ethernet boards
 eql.txt
 	- serial IP load balancing
 ethertap.txt
diff -urN linux-2.4.20-pre1/Documentation/networking/8139too.txt linux-2.4.20-pre2/Documentation/networking/8139too.txt
--- linux-2.4.20-pre1/Documentation/networking/8139too.txt	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/Documentation/networking/8139too.txt	Mon Aug 12 16:34:14 2002
@@ -185,9 +185,22 @@
 Change History
 --------------
 
-Version 0.9.23 - January 16, 2002
+Version 0.9.26 - August 9, 2002
 
-* New, compile-time conditional for testing better RX reset
+* Fix MII ioctl phy id corruption.
+* Fix big-endian multicast bug.
+* Support register dumps via ethtool.
+* Fix several uses of 'len' after potential skb free, in dev->hard_start_xmit
+* Replace several "magic numbers" with their proper representation
+  constants in linux/mii.h.
+* Support ethtool media interface via generic kernel MII API
+* Export NIC-specific statistics via ethtool.
+* Proper support for RTL8139 rev K. (can be disabled via
+  compile-time conditional)
+* Add PCI ids for new 8139 boards.
+* Use ethernet crc via generic linux/crc32.h kernel API.
+* Better RX reset.  Old rx-reset method still available via
+  a compile-time conditional.
 * Only account specific RX errors if rx_status is !OK
 
 
diff -urN linux-2.4.20-pre1/Documentation/networking/NAPI_HOWTO.txt linux-2.4.20-pre2/Documentation/networking/NAPI_HOWTO.txt
--- linux-2.4.20-pre1/Documentation/networking/NAPI_HOWTO.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/Documentation/networking/NAPI_HOWTO.txt	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,749 @@
+HISTORY:
+February 16/2002 -- revision 0.2.1:
+COR typo corrected
+February 10/2002 -- revision 0.2:
+some spell checking ;->
+January 12/2002 -- revision 0.1
+This is still work in progress so may change.
+To keep up to date please watch this space.
+
+Introduction to NAPI
+====================
+
+NAPI is a proven (www.cyberus.ca/~hadi/usenix-paper.tgz) technique
+to improve network performance on Linux. For more details please
+read that paper.
+NAPI provides a "inherent mitigation" which is bound by system capacity
+as can be seen from the following data collected by Robert on Gigabit 
+ethernet (e1000):
+
+ Psize    Ipps       Tput     Rxint     Txint    Done     Ndone
+ ---------------------------------------------------------------
+   60    890000     409362        17     27622        7     6823
+  128    758150     464364        21      9301       10     7738
+  256    445632     774646        42     15507       21    12906
+  512    232666     994445    241292     19147   241192     1062
+ 1024    119061    1000003    872519     19258   872511        0
+ 1440     85193    1000003    946576     19505   946569        0
+ 
+
+Legend:
+"Ipps" stands for input packets per second. 
+"Tput" == packets out of total 1M that made it out.
+"txint" == transmit completion interrupts seen
+"Done" == The number of times that the poll() managed to pull all
+packets out of the rx ring. Note from this that the lower the
+load the more we could clean up the rxring
+"Ndone" == is the converse of "Done". Note again, that the higher
+the load the more times we couldnt clean up the rxring.
+
+Observe that:
+when the NIC receives 890Kpackets/sec only 17 rx interrupts are generated. 
+The system cant handle the processing at 1 interrupt/packet at that load level. 
+At lower rates on the other hand, rx interrupts go up and therefore the
+interrupt/packet ratio goes up (as observable from that table). So there is
+possibility that under low enough input, you get one poll call for each
+input packet caused by a single interrupt each time. And if the system 
+cant handle interrupt per packet ratio of 1, then it will just have to 
+chug along ....
+
+
+0) Prerequisites:
+==================
+A driver MAY continue using the old 2.4 technique for interfacing
+to the network stack and not benefit from the NAPI changes.
+NAPI additions to the kernel do not break backward compatibility.
+NAPI, however, requires the following features to be available:
+
+A) DMA ring or enough RAM to store packets in software devices.
+
+B) Ability to turn off interrupts or maybe events that send packets up 
+the stack.
+
+NAPI processes packet events in what is known as dev->poll() method.
+Typically, only packet receive events are processed in dev->poll(). 
+The rest of the events MAY be processed by the regular interrupt handler 
+to reduce processing latency (justified also because there are not that 
+many of them).
+Note, however, NAPI does not enforce that dev->poll() only processes 
+receive events. 
+Tests with the tulip driver indicated slightly increased latency if
+all of the interrupt handler is moved to dev->poll(). Also MII handling
+gets a little trickier.
+The example used in this document is to move the receive processing only
+to dev->poll(); this is shown with the patch for the tulip driver.
+For an example of code that moves all the interrupt driver to 
+dev->poll() look at the ported e1000 code.
+
+There are caveats that might force you to go with moving everything to 
+dev->poll(). Different NICs work differently depending on their status/event 
+acknowledgement setup. 
+There are two types of event register ACK mechanisms.
+	I)  what is known as Clear-on-read (COR).
+	when you read the status/event register, it clears everything!
+	The natsemi and sunbmac NICs are known to do this.
+	In this case your only choice is to move all to dev->poll()
+
+	II) Clear-on-write (COW)
+	 i) you clear the status by writting a 1 in the bit-location you want.
+		These are the majority of the NICs and work the best with NAPI.
+		Put only receive events in dev->poll(); leave the rest in
+		the old interrupt handler.
+	 ii) whatever you write in the status register clears every thing ;->
+		Cant seem to find any supported by Linux which do this. If
+		someone knows such a chip email us please.
+		Move all to dev->poll()
+
+C) Ability to detect new work correctly.
+NAPI works by shutting down event interrupts when theres work and
+turning them on when theres none. 
+New packets might show up in the small window while interrupts were being 
+re-enabled (refer to appendix 2).  A packet might sneak in during the period 
+we are enabling interrupts. We only get to know about such a packet when the 
+next new packet arrives and generates an interrupt. 
+Essentially, there is a small window of opportunity for a race condition
+which for clarity we'll refer to as the "rotting packet".
+
+This is a very important topic and appendix 2 is dedicated for more 
+discussion.
+
+Locking rules and environmental guarantees
+==========================================
+
+-Guarantee: Only one CPU at any time can call dev->poll(); this is because
+only one CPU can pick the initial interrupt and hence the initial
+netif_rx_schedule(dev);
+- The core layer invokes devices to send packets in a round robin format.
+This implies receive is totaly lockless because of the guarantee only that 
+one CPU is executing it.
+-  contention can only be the result of some other CPU accessing the rx
+ring. This happens only in close() and suspend() (when these methods
+try to clean the rx ring); 
+****guarantee: driver authors need not worry about this; synchronization 
+is taken care for them by the top net layer.
+-local interrupts are enabled (if you dont move all to dev->poll()). For 
+example link/MII and txcomplete continue functioning just same old way. 
+This improves the latency of processing these events. It is also assumed that 
+the receive interrupt is the largest cause of noise. Note this might not 
+always be true. 
+[according to Manfred Spraul, the winbond insists on sending one 
+txmitcomplete interrupt for each packet (although this can be mitigated)].
+For these broken drivers, move all to dev->poll().
+
+For the rest of this text, we'll assume that dev->poll() only
+processes receive events.
+
+new methods introduce by NAPI
+=============================
+
+a) netif_rx_schedule(dev)
+Called by an IRQ handler to schedule a poll for device
+
+b) netif_rx_schedule_prep(dev)
+puts the device in a state which allows for it to be added to the
+CPU polling list if it is up and running. You can look at this as
+the first half of  netif_rx_schedule(dev) above; the second half
+being c) below.
+
+c) __netif_rx_schedule(dev)
+Add device to the poll list for this CPU; assuming that _prep above
+has already been called and returned 1.
+
+d) netif_rx_reschedule(dev, undo)
+Called to reschedule polling for device specifically for some
+deficient hardware. Read Appendix 2 for more details.
+
+e) netif_rx_complete(dev)
+
+Remove interface from the CPU poll list: it must be in the poll list
+on current cpu. This primitive is called by dev->poll(), when
+it completes its work. The device cannot be out of poll list at this
+call, if it is then clearly it is a BUG(). You'll know ;->
+
+All these above nethods are used below. So keep reading for clarity.
+
+Device driver changes to be made when porting NAPI
+==================================================
+
+Below we describe what kind of changes are required for NAPI to work.
+
+1) introduction of dev->poll() method 
+=====================================
+
+This is the method that is invoked by the network core when it requests
+for new packets from the driver. A driver is allowed to send upto
+dev->quota packets by the current CPU before yielding to the network
+subsystem (so other devices can also get opportunity to send to the stack).
+
+dev->poll() prototype looks as follows:
+int my_poll(struct net_device *dev, int *budget)
+
+budget is the remaining number of packets the network subsystem on the
+current CPU can send up the stack before yielding to other system tasks.
+*Each driver is responsible for decrementing budget by the total number of
+packets sent.
+	Total number of packets cannot exceed dev->quota.
+
+dev->poll() method is invoked by the top layer, the driver just sends if it 
+can to the stack the packet quantity requested.
+
+more on dev->poll() below after the interrupt changes are explained.
+
+2) registering dev->poll() method
+===================================
+
+dev->poll should be set in the dev->probe() method. 
+e.g:
+dev->open = my_open;
+.
+.
+/* two new additions */
+/* first register my poll method */
+dev->poll = my_poll;
+/* next register my weight/quanta; can be overriden in /proc */
+dev->weight = 16;
+.
+.
+dev->stop = my_close;
+
+
+
+3) scheduling dev->poll()
+=============================
+This involves modifying the interrupt handler and the code
+path which takes the packet off the NIC and sends them to the 
+stack.
+
+it's important at this point to introduce the classical D Becker 
+interrupt processor:
+
+------------------
+static void
+netdevice_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct my_private *tp = (struct my_private *)dev->priv;
+
+	int work_count = my_work_count;
+        status = read_interrupt_status_reg();
+        if (status == 0)
+                return;         /* Shared IRQ: not us */
+        if (status == 0xffff)
+                return;         /* Hot unplug */
+        if (status & error)
+		do_some_error_handling()
+        
+	do {
+		acknowledge_ints_ASAP();
+
+		if (status & link_interrupt) {
+			spin_lock(&tp->link_lock);
+			do_some_link_stat_stuff();
+			spin_unlock(&tp->link_lock);
+		}
+		
+		if (status & rx_interrupt) {
+			receive_packets(dev);
+		}
+
+		if (status & rx_nobufs) {
+			make_rx_buffs_avail();
+		}
+			
+		if (status & tx_related) {
+			spin_lock(&tp->lock);
+			tx_ring_free(dev);
+			if (tx_died)
+				restart_tx();
+			spin_unlock(&tp->lock);
+		}
+
+		status = read_interrupt_status_reg();
+
+	} while (!(status & error) || more_work_to_be_done);
+
+}
+
+----------------------------------------------------------------------
+
+We now change this to what is shown below to NAPI-enable it:
+
+----------------------------------------------------------------------
+static void
+netdevice_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct my_private *tp = (struct my_private *)dev->priv;
+
+        status = read_interrupt_status_reg();
+        if (status == 0)
+                return;         /* Shared IRQ: not us */
+        if (status == 0xffff)
+                return;         /* Hot unplug */
+        if (status & error)
+		do_some_error_handling();
+        
+	do {
+/************************ start note *********************************/		
+		acknowledge_ints_ASAP();  // dont ack rx and rxnobuff here
+/************************ end note *********************************/		
+
+		if (status & link_interrupt) {
+			spin_lock(&tp->link_lock);
+			do_some_link_stat_stuff();
+			spin_unlock(&tp->link_lock);
+		}
+/************************ start note *********************************/		
+		if (status & rx_interrupt || (status & rx_nobuffs)) {
+			if (netif_rx_schedule_prep(dev)) {
+
+				/* disable interrupts caused 
+			         *	by arriving packets */
+				disable_rx_and_rxnobuff_ints();
+				/* tell system we have work to be done. */
+				__netif_rx_schedule(dev);
+			} else {
+				printk("driver bug! interrupt while in poll\n");
+				/* FIX by disabling interrupts  */
+				disable_rx_and_rxnobuff_ints();
+			}
+		}
+/************************ end note note *********************************/		
+			
+		if (status & tx_related) {
+			spin_lock(&tp->lock);
+			tx_ring_free(dev);
+
+			if (tx_died)
+				restart_tx();
+			spin_unlock(&tp->lock);
+		}
+
+		status = read_interrupt_status_reg();
+
+/************************ start note *********************************/		
+	} while (!(status & error) || more_work_to_be_done(status));
+/************************ end note note *********************************/		
+
+}
+
+---------------------------------------------------------------------
+
+
+We note several things from above:
+
+I) Any interrupt source which is caused by arriving packets is now
+turned off when it occurs. Depending on the hardware, there could be
+several reasons that arriving packets would cause interrupts; these are the
+interrupt sources we wish to avoid. The two common ones are a) a packet 
+arriving (rxint) b) a packet arriving and finding no DMA buffers available
+(rxnobuff) .
+This means also acknowledge_ints_ASAP() will not clear the status
+register for those two items above; clearing is done in the place where 
+proper work is done within NAPI; at the poll() and refill_rx_ring() 
+discussed further below.
+netif_rx_schedule_prep() returns 1 if device is in running state and
+gets successfully added to the core poll list. If we get a zero value
+we can _almost_ assume are already added to the list (instead of not running. 
+Logic based on the fact that you shouldnt get interrupt if not running)
+We rectify this by disabling rx and rxnobuf interrupts.
+
+II) that receive_packets(dev) and make_rx_buffs_avail() may have dissapeared.
+These functionalities are still around actually......
+
+infact, receive_packets(dev) is very close to my_poll() and 
+make_rx_buffs_avail() is invoked from my_poll()
+
+4) converting receive_packets() to dev->poll()
+===============================================
+
+We need to convert the classical D Becker receive_packets(dev) to my_poll()
+
+First the typical receive_packets() below:
+-------------------------------------------------------------------
+
+/* this is called by interrupt handler */
+static void receive_packets (struct net_device *dev)
+{
+
+	struct my_private *tp = (struct my_private *)dev->priv;
+	rx_ring = tp->rx_ring;
+	cur_rx = tp->cur_rx;
+	int entry = cur_rx % RX_RING_SIZE;
+	int received = 0;
+	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+
+	while (rx_ring_not_empty) {
+		u32 rx_status;
+		unsigned int rx_size;
+		unsigned int pkt_size;
+		struct sk_buff *skb;
+                /* read size+status of next frame from DMA ring buffer */
+		/* the number 16 and 4 are just examples */
+                rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+                rx_size = rx_status >> 16;
+                pkt_size = rx_size - 4;
+
+		/* process errors */
+                if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
+                    (!(rx_status & RxStatusOK))) {
+                        netdrv_rx_err (rx_status, dev, tp, ioaddr);
+                        return;
+                }
+
+                if (--rx_work_limit < 0)
+                        break;
+
+		/* grab a skb */
+                skb = dev_alloc_skb (pkt_size + 2);
+                if (skb) {
+			.
+			.
+			netif_rx (skb);
+			.
+			.
+                } else {  /* OOM */
+			/*seems very driver specific ... some just pass
+			whatever is on the ring already. */
+                }
+
+		/* move to the next skb on the ring */
+		entry = (++tp->cur_rx) % RX_RING_SIZE;
+		received++ ;
+
+        }
+
+	/* store current ring pointer state */
+        tp->cur_rx = cur_rx;
+
+        /* Refill the Rx ring buffers if they are needed */
+	refill_rx_ring();
+	.
+	.
+
+}
+-------------------------------------------------------------------
+We change it to a new one below; note the additional parameter in
+the call.
+
+-------------------------------------------------------------------
+
+/* this is called by the network core */
+static void my_poll (struct net_device *dev, int *budget)
+{
+
+	struct my_private *tp = (struct my_private *)dev->priv;
+	rx_ring = tp->rx_ring;
+	cur_rx = tp->cur_rx;
+	int entry = cur_rx % RX_BUF_LEN;
+	/* maximum packets to send to the stack */
+/************************ note note *********************************/		
+	int rx_work_limit = dev->quota;
+
+/************************ end note note *********************************/		
+    do {  // outer beggining loop starts here
+
+	clear_rx_status_register_bit();
+
+	while (rx_ring_not_empty) {
+		u32 rx_status;
+		unsigned int rx_size;
+		unsigned int pkt_size;
+		struct sk_buff *skb;
+                /* read size+status of next frame from DMA ring buffer */
+		/* the number 16 and 4 are just examples */
+                rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+                rx_size = rx_status >> 16;
+                pkt_size = rx_size - 4;
+
+		/* process errors */
+                if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
+                    (!(rx_status & RxStatusOK))) {
+                        netdrv_rx_err (rx_status, dev, tp, ioaddr);
+                        return;
+                }
+
+/************************ note note *********************************/		
+                if (--rx_work_limit < 0) { /* we got packets, but no quota */
+			/* store current ring pointer state */
+			tp->cur_rx = cur_rx;
+
+			/* Refill the Rx ring buffers if they are needed */
+			refill_rx_ring(dev);
+                        goto not_done;
+		}
+/**********************  end note **********************************/
+
+		/* grab a skb */
+                skb = dev_alloc_skb (pkt_size + 2);
+                if (skb) {
+			.
+			.
+/************************ note note *********************************/		
+			netif_receive_skb (skb);
+/**********************  end note **********************************/
+			.
+			.
+                } else {  /* OOM */
+			/*seems very driver specific ... common is just pass
+			whatever is on the ring already. */
+                }
+
+		/* move to the next skb on the ring */
+		entry = (++tp->cur_rx) % RX_RING_SIZE;
+		received++ ;
+
+        }
+
+	/* store current ring pointer state */
+        tp->cur_rx = cur_rx;
+
+        /* Refill the Rx ring buffers if they are needed */
+	refill_rx_ring(dev);
+	
+	/* no packets on ring; but new ones can arrive since we last 
+	   checked  */
+	status = read_interrupt_status_reg();
+	if (rx status is not set) {
+                        /* If something arrives in this narrow window,
+			an interrupt will be generated */
+                        goto done;
+	}
+	/* done! at least thats what it looks like ;->
+	if new packets came in after our last check on status bits
+	they'll be caught by the while check and we go back and clear them 
+	since we havent exceeded our quota */
+    } while (rx_status_is_set); 
+
+done:
+
+/************************ note note *********************************/		
+        dev->quota -= received;
+        *budget -= received;
+
+        /* If RX ring is not full we are out of memory. */
+        if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+                goto oom;
+
+	/* we are happy/done, no more packets on ring; put us back
+	to where we can start processing interrupts again */
+        netif_rx_complete(dev);
+	enable_rx_and_rxnobuf_ints();
+
+       /* The last op happens after poll completion. Which means the following:
+        * 1. it can race with disabling irqs in irq handler (which are done to 
+	* schedule polls)
+        * 2. it can race with dis/enabling irqs in other poll threads
+        * 3. if an irq raised after the begining of the outer  beginning 
+        * loop(marked in the code above), it will be immediately
+        * triggered here.
+        *
+        * Summarizing: the logic may results in some redundant irqs both
+        * due to races in masking and due to too late acking of already
+        * processed irqs. The good news: no events are ever lost.
+        */
+
+        return 0;   /* done */
+
+not_done:
+        if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
+            tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+                refill_rx_ring(dev);
+
+        if (!received) {
+                printk("received==0\n");
+                received = 1;
+        }
+        dev->quota -= received;
+        *budget -= received;
+        return 1;  /* not_done */
+
+oom:
+        /* Start timer, stop polling, but do not enable rx interrupts. */
+	start_poll_timer(dev);
+        return 0;  /* we'll take it from here so tell core "done"*/
+
+/************************ End note note *********************************/		
+}
+-------------------------------------------------------------------
+
+From above we note that:
+0) rx_work_limit = dev->quota 
+1) refill_rx_ring() is in charge of clearing the bit for rxnobuff when
+it does the work.
+2) We have a done and not_done state.
+3) instead of netif_rx() we call netif_receive_skb() to pass the skb.
+4) we have a new way of handling oom condition
+5) A new outer for (;;) loop has been added. This serves the purpose of
+ensuring that if a new packet has come in, after we are all set and done,
+and we have not exceeded our quota that we continue sending packets up.
+ 
+
+-----------------------------------------------------------
+Poll timer code will need to do the following:
+
+a) 
+
+        if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
+            tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 
+                refill_rx_ring(dev);
+
+        /* If RX ring is not full we are still out of memory.
+	   Restart the timer again. Else we re-add ourselves 
+           to the master poll list.
+         */
+
+        if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+                restart_timer();
+
+	else netif_rx_schedule(dev);  /* we are back on the poll list */
+	
+5) dev->close() and dev->suspend() issues
+==========================================
+The driver writter neednt worry about this. The top net layer takes
+care of it.
+
+6) Adding new Stats to /proc 
+=============================
+In order to debug some of the new features, we introduce new stats
+that need to be collected.
+TODO: Fill this later.
+
+APPENDIX 1: discussion on using ethernet HW FC
+==============================================
+Most chips with FC only send a pause packet when they run out of Rx buffers.
+Since packets are pulled off the DMA ring by a softirq in NAPI,
+if the system is slow in grabbing them and we have a high input
+rate (faster than the system's capacity to remove packets), then theoretically
+there will only be one rx interrupt for all packets during a given packetstorm.
+Under low load, we might have a single interrupt per packet.
+FC should be programmed to apply in the case when the system cant pull out
+packets fast enough i.e send a pause only when you run out of rx buffers.
+Note FC in itself is a good solution but we have found it to not be
+much of a commodity feature (both in NICs and switches) and hence falls
+under the same category as using NIC based mitigation. Also experiments
+indicate that its much harder to resolve the resource allocation
+issue (aka lazy receiving that NAPI offers) and hence quantify its usefullness
+proved harder. In any case, FC works even better with NAPI but is not
+necessary.
+
+
+APPENDIX 2: the "rotting packet" race-window avoidance scheme 
+=============================================================
+
+There are two types of associations seen here
+
+1) status/int which honors level triggered IRQ
+
+If a status bit for receive or rxnobuff is set and the corresponding 
+interrupt-enable bit is not on, then no interrupts will be generated. However, 
+as soon as the "interrupt-enable" bit is unmasked, an immediate interrupt is 
+generated.  [assuming the status bit was not turned off].
+Generally the concept of level triggered IRQs in association with a status and
+interrupt-enable CSR register set is used to avoid the race.
+
+If we take the example of the tulip:
+"pending work" is indicated by the status bit(CSR5 in tulip).
+the corresponding interrupt bit (CSR7 in tulip) might be turned off (but
+the CSR5 will continue to be turned on with new packet arrivals even if
+we clear it the first time)
+Very important is the fact that if we turn on the interrupt bit on when
+status is set that an immediate irq is triggered.
+ 
+If we cleared the rx ring and proclaimed there was "no more work
+to be done" and then went on to do a few other things;  then when we enable
+interrupts, there is a possibility that a new packet might sneak in during
+this phase. It helps to look at the pseudo code for the tulip poll
+routine:
+
+--------------------------
+        do {
+                ACK;
+                while (ring_is_not_empty()) {
+                        work-work-work
+                        if quota is exceeded: exit, no touching irq status/mask
+                }
+                /* No packets, but new can arrive while we are doing this*/
+                CSR5 := read
+                if (CSR5 is not set) {
+                        /* If something arrives in this narrow window here,
+                        *  where the comments are ;-> irq will be generated */
+                        unmask irqs;
+                        exit poll;
+                }
+        } while (rx_status_is_set);
+------------------------
+
+CSR5 bit of interest is only the rx status. 
+If you look at the last if statement: 
+you just finished grabbing all the packets from the rx ring .. you check if
+status bit says theres more packets just in ... it says none; you then
+enable rx interrupts again; if a new packet just came in during this check,
+we are counting that CSR5 will be set in that small window of opportunity
+and that by re-enabling interrupts, we would actually triger an interrupt
+to register the new packet for processing.
+
+[The above description nay be very verbose, if you have better wording 
+that will make this more understandable, please suggest it.]
+
+2) non-capable hardware
+
+These do not generally respect level triggered IRQs. Normally,
+irqs may be lost while being masked and the only way to leave poll is to do
+a double check for new input after netif_rx_complete() is invoked
+and re-enable polling (after seeing this new input).
+
+Sample code:
+
+---------
+	.
+	.
+restart_poll:
+	while (ring_is_not_empty()) {
+		work-work-work
+		if quota is exceeded: exit, not touching irq status/mask
+	}
+	.
+	.
+	.
+	enable_rx_interrupts()
+	netif_rx_complete(dev);
+	if (ring_has_new_packet() && netif_rx_reschedule(dev, received)) {
+		disable_rx_and_rxnobufs()
+		goto restart_poll
+	} while (rx_status_is_set);
+---------
+		
+Basically netif_rx_complete() removes us from the poll list, but because a
+new packet which will never be caught due to the possibility of a race
+might come in, we attempt to re-add ourselves to the poll list. 
+
+
+
+--------------------------------------------------------------------
+
+relevant sites:
+==================
+ftp://robur.slu.se/pub/Linux/net-development/NAPI/
+
+
+--------------------------------------------------------------------
+TODO: Write net-skeleton.c driver.
+-------------------------------------------------------------
+
+Authors:
+========
+Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+Jamal Hadi Salim <hadi@cyberus.ca>
+Robert Olsson <Robert.Olsson@data.slu.se>
+
+Acknowledgements:
+================
+People who made this document better:
+
+Lennert Buytenhek <buytenh@gnu.org>
+Andrew Morton  <akpm@zip.com.au>
+Manfred Spraul <manfred@colorfullife.com>
+Donald Becker <becker@scyld.com>
+Jeff Garzik 
diff -urN linux-2.4.20-pre1/Documentation/networking/e100.txt linux-2.4.20-pre2/Documentation/networking/e100.txt
--- linux-2.4.20-pre1/Documentation/networking/e100.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/Documentation/networking/e100.txt	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,272 @@
+Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
+==============================================================
+
+April 9, 2002
+
+
+Contents
+========
+
+- In This Release
+- Supported Adapters
+- Command Line Parameters
+- CPU Cycle Saver
+- Additional Configurations
+- Support
+
+
+In This Release
+===============
+
+This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family of
+Adapters, version 2.0.x.  This driver includes support for Itanium(TM)-based 
+systems.
+
+New for this release:
+
+   - Additional ethtool functionality, including link status test and EEPROM 
+     read/write. A third-party application can use the ethtool interface to 
+     get and set driver parameters.
+
+   - Support for Zero copy on 82550-based adapters. This feature provides 
+     faster data throughput and significant CPU usage improvement in systems 
+     that use the relevant system call (sendfile(2)).
+
+   - Support for large MTU-enabling interface (1504 bytes) with kernel's 
+     VLAN module
+
+   - Support for polling on RX
+
+   - Support for Wake On LAN* on 82550 and 82559-based adapters
+
+
+Supported Adapters
+==================
+
+The following Intel network adapters are compatible with the drivers 
+in this release:
+
+Controller  Adapter Name                            Board IDs
+----------  ------------                            ---------
+
+82558       PRO/100+ PCI Adapter                    668081-xxx, 689661-xxx
+
+82558       PRO/100+ Management Adapter             691334-xxx, 701738-xxx,
+                                                    721383-xxx
+
+82558       PRO/100+ Dual Port Server Adapter       714303-xxx, 711269-xxx, 
+                                                    A28276-xxx
+
+82558       PRO/100+ PCI Server Adapter             710550-xxx
+
+82550       PRO/100 S Server Adapter                752438-xxx (82550)
+82559                                               A56831-xxx, A10563-xxx,
+                                                    A12171-xxx, A12321-xxx, 
+                                                    A12320-xxx, A12170-xxx
+                                                    748568-xxx (82559)
+                                                    748565-xxx (82559)
+
+
+82550       PRO/100 S Desktop Adapter               751767-xxx (82550)
+82559                                               748592-xxx, A12167-xxx, 
+                                                    A12318-xxx, A12317-xxx, 
+                                                    A12165-xxx
+                                                    748569-xxx (82559)
+
+
+
+82559       PRO/100+ Server Adapter                 729757-xxx
+
+82559       PRO/100 S Management Adapter            748566-xxx, 748564-xxx
+
+82550       PRO/100 S Dual Port Server Adapter      A56831-xxx
+
+82551       PRO/100 M Desktop Adapter               A80897-xxx
+
+            PRO/100 S Advanced Management Adapter   747842-xxx, 745171-xxx
+
+CNR         PRO/100 VE Desktop Adapter              A10386-xxx, A10725-xxx, 
+                                                    A23801-xxx, A19716-xxx
+
+
+            PRO/100 VM Desktop Adapter              A14323-xxx, A19725-xxx, 
+                                                    A23801-xxx, A22220-xxx, 
+                                                    A23796-xxx
+   
+
+To verify that your adapter is supported, find the board ID number on the 
+adapter. Look for a label that has a barcode and a number in the format 
+123456-001 (six digits hyphen three digits). Match this to the list of 
+numbers above.
+
+For more information on how to identify your adapter, go to the Adapter & 
+Driver ID Guide at:
+
+  http://support.intel.com/support/network/adapter/pro100/21397.htm
+
+For the latest Intel PRO/100 network driver for Linux, see:
+
+  http://appsr.intel.com/scripts-df/support_intel.asp
+
+
+Command Line Parameters
+=======================
+
+The following parameters are used by entering them on the command line with 
+the modprobe or insmod command. For example, with two Intel PRO/100 PCI 
+adapters, entering:
+	
+     modprobe e100 TxDescriptors=32,128
+
+loads the e100 driver with 32 TX resources for the first adapter and 128 TX 
+resources for the second adapter. This configuration favors the second 
+adapter. The driver supports up to 16 network adapters concurrently.
+
+NOTE: Giving any command line option the value "-1" causes the driver to use 
+      the appropriate default value for that option, as if no value was 
+      specified.
+
+
+BundleMax
+Valid Range: 0x1-0xFFFF
+Default Value: 6
+   This parameter holds the maximum number of packets in a bundle. Suggested 
+   values range from 2 to 10. See "CPU Cycle Saver."
+
+BundleSmallFr
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 0
+   The value 1 (on) causes small packets (less than 128 bytes) to be bundled. 
+   See "CPU Cycle Saver."
+
+e100_speed_duplex
+Valid Range: 0-4 (1=10half;2=10full;3=100half;4=100full)
+Default Value: 0
+   The default value of 0 is set to auto-negotiate if the link partner is set
+   to auto-negotiate. If the link partner is forced, e100_speed_duplex 
+   defaults to half-duplex. 
+   Example usage: insmod e100.o e100_speed_duplex=4,4 (for two adapters)
+
+flow_control
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 0
+   This parameter controls the automatic generation(Tx) and response(Rx) to 
+   Ethernet PAUSE frames. flow_control should NOT be set to 1 when the e100 
+   adapter is connected to an interface that does not support Ethernet PAUSE 
+   frames and when the e100_speed_duplex parameter is NOT set to zero. 
+
+IntDelay
+Valid Range: 0-0xFFFF (0=off)
+Default Value: 1536
+   This parameter holds the number of time units (in adapter terminology)
+   until the adapter generates an interrupt. The recommended value for 
+   IntDelay is 0x600 (upon initialization). Suggested values range from 
+   0x200h to 0x800. See "CPU Cycle Saver."
+
+IFS
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 1
+  Inter Frame Spacing (IFS) aims to reduce the number of Ethernet frame
+  collisions by altering the time between frame transmissions. When IFS is 
+  enabled the driver tries to find an optimal IFS value. However, some 
+  switches function better when IFS is disabled.
+
+PollingMaxWork
+Valid Range: 1-1024 (max number of RxDescriptors)
+Default Value: Specified number of RxDescriptors
+  This value specifies the maximum number of receive packets that are 
+  processed on a single polling call. This parameter is invalid if 
+  RxCongestionControl is set to 0.
+
+RxCongestionControl
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 1
+  1 enables polling mode. When the link is congested, the driver can decide 
+  to handle received packets by polling them, instead of waiting until 
+  interrupts occur.
+
+RxDescriptors
+Valid Range: 8-1024
+Default Value: 64
+   This parameter defines the number of receive descriptors allocated by 
+   the driver. Increasing this value allows the driver to buffer more 
+   incoming packets before the driver is required to service an interrupt. 
+   The maximum value for Itanium-based systems is 64.
+
+TxDescriptors
+Valid Range: 19-1024
+Default Value: 64
+   This value is the number of transmit descriptors allocated by the driver. 
+   Increasing this value allows the protocol stack to queue more transmits at
+   the driver level. The maximum value for Itanium-based systems is 64.
+
+ucode (not available for 82557-based adapters)
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 0 for 82558-based adapters
+               1 for 82559(and higher)-based adapters
+   On uploads the micro code to the adapter, which enables CPU Cycle Saver. 
+   See the section "CPU Cycle Saver" below.
+   Example usage: insmod e100.o ucode=0  (does not reduce CPU usage)
+
+XsumRX
+Valid Range: 0-1 (0=off, 1=on)
+Default Value: 1
+   On allows Rx checksum offloading for TCP/UDP packets. Requires that the 
+   hardware support this feature.
+
+
+CPU Cycle Saver
+================
+
+CPU Cycle Saver reduces CPU utilization by reducing the number of interrupts 
+that the adapter generates.
+
+When CPU Cycle Saver is turned off, the adapter generates one interrupt for 
+every frame that is received. This means that the operating system stops what
+it is doing and switches to the network driver in order to process the 
+receive.
+
+When CPU Cycle Saver is on, the adapter does not generate an interrupt for 
+every frame it receives. Instead, it waits until it receives several frames 
+before generating an interrupt. This reduces the amount of time spent 
+switching to and from the driver. 
+
+CPU Cycle Saver consists of these arguments: IntDelay, BundleMax and 
+BundleSmallFr. When IntDelay is increased, the adapter waits longer for 
+frames to arrive before generating the interrupt. By increasing BundleMax, 
+the network adapter waits for the number of frames specified to arrive before 
+generating the interrupt. When BundleSmallFr is disabled, the adapter does 
+not bundle packets that are smaller than 128 bytes. Such small packets are 
+often, but not always, control packets that are better served immediately.
+
+For most users, it is recommended that CPU Cycle Saver be used with the 
+default values specified in the Command Line Parameters section. However, in 
+some cases, performance problems may occur with CPU Cycle Saver. If such 
+problems are observed, we recommend turning off this feature by setting 
+ucode=0.
+
+
+Support
+=======
+
+For general information and support, go to the Intel support website at:
+
+    http://support.intel.com
+
+If an issue is identified with the released source code on the supported
+kernel with a supported adapter, email the specific information related to 
+the issue to linux.nics@intel.com.
+
+
+License
+=======
+
+This software program is released under the terms of a license agreement 
+between you ('Licensee') and Intel. Do not use or load this software or any 
+associated materials (collectively, the 'Software') until you have carefully 
+read the full terms and conditions of the LICENSE located in this software 
+package. By loading or using the Software, you agree to the terms of this 
+Agreement. If you do not agree with the terms of this Agreement, do not 
+install or use the Software.
+
+* Other names and brands may be claimed as the property of others.
diff -urN linux-2.4.20-pre1/Documentation/networking/e1000.txt linux-2.4.20-pre2/Documentation/networking/e1000.txt
--- linux-2.4.20-pre1/Documentation/networking/e1000.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/Documentation/networking/e1000.txt	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,272 @@
+Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
+===============================================================
+
+June 11, 2002
+
+
+Contents
+========
+
+- In This Release
+- Supported Adapters
+- Command Line Parameters
+- Speed and Duplex Configuration
+- Additional Configurations
+- Known Issues
+- Support
+
+
+In This Release
+===============
+
+This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
+of Adapters, version 4.2.x.  This driver includes support for 
+Itanium(TM)-based systems.
+
+This release version includes the following:
+
+   - Support for the ethtool 1.5 interface. A third-party application can use
+     the ethtool interface to get and set driver parameters.
+
+   - Zero copy. This feature provides faster data throughput. Enabled by
+     default in supporting kernels. It is not supported on the Intel(R)
+     PRO/1000 Gigabit Server Adapter.
+
+New features include:
+
+   - Support for the 82545 and 82546-based adapters listed below
+
+   - Wake on LAN* support via ethtool for 82540, 82544, 82545, and 82546-
+     based adapters
+
+   - Adaptive IFS for increased performance at half duplex
+
+
+
+Supported Adapters
+==================
+
+The following Intel network adapters are compatible with the drivers in this
+release:
+
+   Controller  Adapter Name                         Board IDs
+   ----------  ------------                         ---------
+
+   82542       PRO/1000 Gigabit Server Adapter      700262-xxx, 717037-xxx
+
+   82543       PRO/1000 F Server Adapter            738640-xxx, A38888-xxx
+
+   82543       PRO/1000 T Server Adapter            A19845-xxx, A33948-xxx
+
+   82544       PRO/1000 XT Server Adapter           A51580-xxx
+
+   82544       PRO/1000 XF Server Adapter           A50484-xxx
+
+   82544       PRO/1000 T Desktop Adapter           A62947-xxx
+
+   82540       PRO/1000 MT Desktop Adapter          A78408-xxx
+
+   82545       PRO/1000 MT Server Adapter           A92165-xxx
+
+   82546       PRO/1000 MT Dual Port Server Adapter A92111-xxx
+
+   82545       PRO/1000 MF Server Adapter           A91622-xxx
+
+   82545       PRO/1000 MF Server Adapter(LX)       A91624-xxx
+
+   82546       PRO/1000 MF Dual Port Server Adapter A91620-xxx
+
+
+To verify your Intel adapter is supported, find the board ID number on the
+adapter. Look for a label that has a barcode and a number in the format of
+123456-001 (six digits hyphen three digits). Match this to the list of
+numbers above.
+
+For more information on how to identify your adapter, go to the Adapter &
+Driver ID Guide at:
+
+    http://support.intel.com/support/network/adapter/pro100/21397.htm
+
+For the latest Intel network drivers for Linux, go to:
+
+    http://appsr.intel.com/scripts-df/support_intel.asp
+
+
+Command Line Parameters
+=======================
+
+If the driver is built as a module, the following optional parameters are 
+used by entering them on the command line with the modprobe or insmod command. 
+For example, with two PRO/1000 PCI adapters, entering:
+
+    insmod e1000 TxDescriptors=80,128
+
+loads the e1000 driver with 80 TX resources for the first adapter and 128 TX
+resources for the second adapter.
+
+For more information about the AutoNeg, Duplex, and Speed parameters, see the
+"Speed and Duplex Configuration" section in this document.
+
+
+AutoNeg (adapters using copper connections only)
+Valid Range: 0x01-0x0F, 0x20-0x2F
+Default Value: 0x2F
+    This parameter is a bit mask that specifies which speed and duplex
+    settings the board advertises. When this parameter is used, the Speed and
+    Duplex parameters must not be specified.
+
+Duplex (adapters using copper connections only)
+Valid Range: 0-2 (0=auto-negotiate, 1=half, 2=full)
+Default Value: 0
+    Defines the direction in which data is allowed to flow. Can by either one
+    or two-directional. If both Duplex and the link partner are set to auto-
+    negotiate, the board auto-detects the correct duplex. If the link partner
+    is forced (either full or half), Duplex defaults to half-duplex.
+
+FlowControl
+Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx)
+Default: Read flow control settings from the EEPROM
+    This parameter controls the automatic generation(Tx) and response(Rx) to
+    Ethernet PAUSE frames.
+
+RxDescriptors
+Valid Range: 80-256 for 82542 and 82543-based adapters
+             80-4096 for 82540, 82544, 82545, and 82546-based adapters
+Default Value: 80
+    This value is the number of receive descriptors allocated by the driver.
+    Increasing this value allows the driver to buffer more incoming packets.
+    Each descriptor is 16 bytes.  A receive buffer is also allocated for each
+    descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending
+    on the MTU setting. The maximum MTU size is 16110.
+
+RxIntDelay
+Valid Range: 0-65535 (0=off)
+Default Value: 0 (82542, 82543, and 82544-based adapters)
+               128 (82540, 82545, and 82546-based adapters)
+    This value delays the generation of receive interrupts in units of 1.024
+    microseconds.  Receive interrupt reduction can improve CPU efficiency if
+    properly tuned for specific network traffic. Increasing this value adds
+    extra latency to frame reception and can end up decreasing the throughput
+    of TCP traffic. If the system is reporting dropped receives, this value
+    may be set too high, causing the driver to run out of available receive
+    descriptors.
+
+    CAUTION: When setting RxIntDelay to a value other than 0, adapters based
+             on the Intel 82543 and 82544 LAN controllers may hang (stop
+             transmitting) under certain network conditions. If this occurs a
+             message is logged in the system event log. In addition, the
+             controller is automatically reset, restoring the network
+             connection. To eliminate the potential for the hang ensure that
+             RxIntDelay is set to 0.
+
+Speed (adapters using copper connections only)
+Valid Settings: 0, 10, 100, 1000
+Default Value: 0 (auto-negotiate at all supported speeds)
+    Speed forces the line speed to the specified value in megabits per second
+    (Mbps). If this parameter is not specified or is set to 0 and the link
+    partner is set to auto-negotiate, the board will auto-detect the correct
+    speed. Duplex must also be set when Speed is set to either 10 or 100.
+
+TxDescriptors
+Valid Range: 80-256 for 82542 and 82543-based adapters
+             80-4096 for 82540, 82544, 82545, and 82546-based adapters
+Default Value: 256
+    This value is the number of transmit descriptors allocated by the driver.
+    Increasing this value allows the driver to queue more transmits. Each
+    descriptor is 16 bytes.
+
+XsumRX (not available on the PRO/1000 Gigabit Server Adapter)
+Valid Range: 0-1
+Default Value: 1
+    A value of '1' indicates that the driver should enable IP checksum
+    offload for received packets (both UDP and TCP) to the adapter hardware.
+
+
+Speed and Duplex Configuration
+==============================
+
+Three keywords are used to control the speed and duplex configuration. These
+keywords are Speed, Duplex, and AutoNeg.
+
+If the board uses a fiber interface, these keywords are ignored, and the
+fiber interface board only links at 1000 Mbps full-duplex.
+
+For copper-based boards, the keywords interact as follows:
+
+  The default operation is auto-negotiate. The board advertises all supported
+  speed and duplex combinations, and it links at the highest common speed and
+  duplex mode IF the link partner is set to auto-negotiate.
+
+  If Speed = 1000, limited auto-negotiation is enabled and only 1000 Mbps is
+  advertised (The 1000BaseT spec requires auto-negotiation.)
+
+  If Speed = 10 or 100, then both Speed and Duplex must be set. Auto-
+  negotiation is disabled, and the AutoNeg parameter is ignored. Partner MUST
+  also be forced.
+
+The AutoNeg parameter is used when more control is required over the auto-
+negotiation process.  When this parameter is used, Speed and Duplex must not
+be specified.  This parameter is a bitmap that specifies which speed and
+duplex settings are advertised to the link partner.
+
+Bit            7      6      5       4       3      2      1       0
+Speed (Mbps)   N/A    N/A    1000    N/A     100    100    10      10
+Duplex                       Full            Full   Half   Full    Half
+
+Note that setting AutoNeg does not guarantee that the board will link at the
+highest specified speed or duplex mode, but the board will link at the
+highest possible speed/duplex of the link partner IF the link partner is also
+set to auto-negotiate. If the link partner is forced speed/duplex, the
+adapter MUST be forced to the same speed/duplex.
+
+
+Additional Configurations
+=========================
+
+  Jumbo Frames
+  ------------
+
+  The driver supports Jumbo Frames for all adapters except 82542-based
+  adapters.  Jumbo Frames support is enabled by changing the MTU to a value
+  larger than the default of 1500.  Use the ifconfig command to increase the
+  MTU size. For example:
+
+        ifconfig ethx mtu 9000 up
+
+
+Known Issues
+============
+
+  Jumbo Frames System Requirement
+  -------------------------------
+
+  Memory allocation failures have been observed on Linux systems with 64 MB
+  of RAM or less that are running Jumbo Frames. If you are using Jumbo
+  Frames, your system may require more than the advertised minimum
+  requirement of 64 MB of system memory.
+
+
+Support
+=======
+
+For general information and support, go to the Intel support website at:
+
+    http://support.intel.com
+
+If an issue is identified with the released source code on the supported
+kernel with a supported adapter, email the specific information related to
+the issue to linux.nics@intel.com.
+
+
+License
+=======
+
+This software program is released under the terms of a license agreement
+between you ('Licensee') and Intel. Do not use or load this software or any
+associated materials (collectively, the 'Software') until you have carefully
+read the full terms and conditions of the LICENSE located in this software
+package. By loading or using the Software, you agree to the terms of this
+Agreement. If you do not agree with the terms of this Agreement, do not
+install or use the Software.
+
+* Other names and brands may be claimed as the property of others.
diff -urN linux-2.4.20-pre1/Documentation/parisc/00-INDEX linux-2.4.20-pre2/Documentation/parisc/00-INDEX
--- linux-2.4.20-pre1/Documentation/parisc/00-INDEX	Tue Dec  5 12:29:38 2000
+++ linux-2.4.20-pre2/Documentation/parisc/00-INDEX	Mon Aug 12 16:34:14 2002
@@ -1,10 +1,10 @@
 00-INDEX
 	- this file.
 IODC.txt
-	- Documentation IODC
+	- Documentation for IODC
 debugging
 	- some debugging hints for real-mode code
-mm
-	- Documentation on parisc mm status
+unwritten
+	- list of unwritten / incomplete functions
 registers
 	- current/planned usage of registers
diff -urN linux-2.4.20-pre1/Documentation/parisc/registers linux-2.4.20-pre2/Documentation/parisc/registers
--- linux-2.4.20-pre1/Documentation/parisc/registers	Fri Sep 14 14:04:06 2001
+++ linux-2.4.20-pre2/Documentation/parisc/registers	Mon Aug 12 16:34:14 2002
@@ -25,8 +25,8 @@
 CR27 (TR 3)			Thread descriptor pointer
 CR28 (TR 4)			not used
 CR29 (TR 5)			not used
-CR30 (TR 6)			current / 0
-CR31 (TR 7)			Temporary register, used in various places
+CR30 (TR 6)			current
+CR31 (TR 7)			interrupt stack base
 
 	Space Registers (kernel mode)
 
diff -urN linux-2.4.20-pre1/Documentation/usb/silverlink.txt linux-2.4.20-pre2/Documentation/usb/silverlink.txt
--- linux-2.4.20-pre1/Documentation/usb/silverlink.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/Documentation/usb/silverlink.txt	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,76 @@
+-------------------------------------------------------------------------
+Readme for Linux device driver for the Texas Instruments SilverLink cable
+-------------------------------------------------------------------------
+
+Author: Romain Liévin & Julien Blache
+Homepage: http://lpg.ticalc.org/prj_usb
+
+INTRODUCTION:
+
+This is a driver for the TI-GRAPH LINK USB (aka SilverLink) cable, a cable 
+designed by TI for connecting their TI8x/9x calculators to a computer 
+(PC or Mac usually).
+
+If you need more information, please visit the 'SilverLink drivers' homepage 
+at the above URL.
+
+WHAT YOU NEED:
+
+A TI calculator of course and a program capable to communicate with your 
+calculator.
+TiLP will work for sure (since I am his developer !). yal92 may be able to use
+it by changing tidev for tiglusb (may require some hacking...).
+
+HOW TO USE IT:
+
+You must have first compiled USB support, support for your specific USB host
+controller (UHCI or OHCI).
+
+Next, (as root) from your appropriate modules directory (lib/modules/2.5.XX):
+
+       insmod usb/usbcore.o
+       insmod usb/usb-uhci.o  <OR>  insmod usb/ohci-hcd.o
+       insmod tiglusb.o
+
+If it is not already there (it usually is), create the device:
+
+       mknod /dev/tiglusb0 c 115 16
+
+You will have to set permissions on this device to allow you to read/write
+from it:
+
+       chmod 666 /dev/tiglusb0
+       
+Now you are ready to run a linking program such as TiLP. Be sure to configure 
+it properly (RTFM).
+       
+MODULE PARAMETERS:
+
+  You can set these with:  insmod tiglusb NAME=VALUE
+  There is currently no way to set these on a per-cable basis.
+
+  NAME: timeout
+  TYPE: integer
+  DEFAULT: 15
+  DESC: Timeout value in tenth of seconds. If no data is available once this 
+       time has expired then the driver will return with a timeout error.
+
+QUIRKS:
+
+The following problem seems to be specific to the link cable since it appears 
+on all platforms (Linux, Windows, Mac OS-X). 
+
+In some very particular cases, the driver returns with success but
+without any data. The application should retry a read operation at least once.
+
+HOW TO CONTACT US:
+
+You can email me at roms@lpg.ticalc.org. Please prefix the subject line
+with "TIGLUSB: " so that I am certain to notice your message.
+You can also mail JB at jb@jblache.org: he has written the first release of 
+this driver but he better knows the Mac OS-X driver.
+
+CREDITS:
+
+The code is based on dabusb.c, printer.c and scanner.c !
+The driver has been developed independantly of Texas Instruments.
diff -urN linux-2.4.20-pre1/Documentation/video4linux/bttv/CARDLIST linux-2.4.20-pre2/Documentation/video4linux/bttv/CARDLIST
--- linux-2.4.20-pre1/Documentation/video4linux/bttv/CARDLIST	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/Documentation/video4linux/bttv/CARDLIST	Mon Aug 12 16:34:14 2002
@@ -3,41 +3,41 @@
   card=1 - MIRO PCTV
   card=2 - Hauppauge (bt848)
   card=3 - STB
-  card=4 - Intel
+  card=4 - Intel Create and Share PCI/ Smart Video Recorder III
   card=5 - Diamond DTV2000
   card=6 - AVerMedia TVPhone
   card=7 - MATRIX-Vision MV-Delta
-  card=8 - FlyVideo II (Bt848) LR26
-  card=9 - IXMicro TurboTV
+  card=8 - Lifeview FlyVideo II (Bt848) LR26
+  card=9 - IMS/IXmicro TurboTV
   card=10 - Hauppauge (bt878)
   card=11 - MIRO PCTV pro
-  card=12 - ADS Technologies Channel Surfer TV
+  card=12 - ADS Technologies Channel Surfer TV (bt848)
   card=13 - AVerMedia TVCapture 98
   card=14 - Aimslab Video Highway Xtreme (VHX)
   card=15 - Zoltrix TV-Max
-  card=16 - Pixelview PlayTV (bt878)
+  card=16 - Prolink Pixelview PlayTV (bt878)
   card=17 - Leadtek WinView 601
   card=18 - AVEC Intercapture
-  card=19 - LifeView FlyKit w/o Tuner
+  card=19 - Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)
   card=20 - CEI Raffles Card
-  card=21 - Lucky Star Image World ConferenceTV
-  card=22 - Phoebe Tv Master + FM (CPH050)
+  card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
+  card=22 - Askey CPH050/ Phoebe Tv Master + FM
   card=23 - Modular Technology MM205 PCTV, bt878
-  card=24 - [many vendors] CPH05X/06X (bt878)
-  card=25 - Terratec/Vobis TV-Boostar
-  card=26 - Newer Hauppauge WinCam (bt878)
-  card=27 - MAXI TV Video PCI2
+  card=24 - Askey CPH05X/06X (bt878) [many vendors]
+  card=25 - Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar
+  card=26 - Hauppauge WinCam newer (bt878)
+  card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
   card=28 - Terratec TerraTV+
   card=29 - Imagenation PXC200
-  card=30 - FlyVideo 98
-  card=31 - iProTV
-  card=32 - Intel Create and Share PCI
+  card=30 - Lifeview FlyVideo 98 LR50
+  card=31 - Formac iProTV
+  card=32 - Intel Create and Share PCI/ Smart Video Recorder III
   card=33 - Terratec TerraTValue
   card=34 - Leadtek WinFast 2000
-  card=35 - Flyvideo 98 (LR50Q) / Chronos Video Shuttle II
-  card=36 - Flyvideo 98FM (LR50Q) / Typhoon TView TV/FM Tuner
-  card=37 - PixelView PlayTV pro
-  card=38 - TView99 CPH06X
+  card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II
+  card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner
+  card=37 - Prolink PixelView PlayTV pro
+  card=38 - Askey CPH06X TView99
   card=39 - Pinnacle PCTV Studio/Rave
   card=40 - STB2
   card=41 - AVerMedia TVPhone 98
@@ -47,45 +47,47 @@
   card=45 - MATRIX-Vision MV-Delta 2
   card=46 - Zoltrix Genie TV/FM
   card=47 - Terratec TV/Radio+
-  card=48 - Dynalink Magic TView 
-  card=49 - GV-BCTV3
+  card=48 - Askey CPH03x/ Dynalink Magic TView
+  card=49 - IODATA GV-BCTV3/PCI
   card=50 - Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP
   card=51 - Eagle Wireless Capricorn2 (bt878A)
   card=52 - Pinnacle PCTV Studio Pro
   card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS
-  card=54 - Lifetec LT 9415 TV (LR90 Rev.F)
-  card=55 - BESTBUY Easy TV (CPH031)
-  card=56 - FlyVideo '98/FM
+  card=54 - Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]
+  card=55 - Askey CPH031/ BESTBUY Easy TV
+  card=56 - Lifeview FlyVideo 98FM LR50
   card=57 - GrandTec 'Grand Video Capture' (Bt848)
-  card=58 - Phoebe TV Master Only (No FM) CPH060
-  card=59 - TV Capturer (CPH03X)
+  card=58 - Askey CPH060/ Phoebe TV Master Only (No FM)
+  card=59 - Askey CPH03x TV Capturer
   card=60 - Modular Technology MM100PCTV
   card=61 - AG Electronics GMV1
-  card=62 - BESTBUY Easy TV (bt878)
+  card=62 - Askey CPH061/ BESTBUY Easy TV (bt878)
   card=63 - ATI TV-Wonder
   card=64 - ATI TV-Wonder VE
-  card=65 - FlyVideo 2000S
+  card=65 - Lifeview FlyVideo 2000S LR90
   card=66 - Terratec TValueRadio
-  card=67 - GV-BCTV4/PCI
+  card=67 - IODATA GV-BCTV4/PCI
   card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)
   card=69 - Active Imaging AIMMS
-  card=70 - PV-BT878P+
-  card=71 - Flyvideo 98EZ (capture only)
-  card=72 - Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
+  card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C)
+  card=71 - Lifeview FlyVideo 98EZ (capture only) LR51
+  card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
   card=73 - Sensoray 311
   card=74 - RemoteVision MX (RV605)
   card=75 - Powercolor MTV878/ MTV878R/ MTV878F
   card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)
   card=77 - GrandTec Multi Capture Card (Bt878)
-  card=78 - AOPEN VA1000
+  card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF
+  card=79 - DSP Design TCVIDEO
+  card=80 - Hauppauge WinTV PVR
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
-  type=1 - Philips PAL_I
-  type=2 - Philips NTSC
-  type=3 - Philips SECAM
+  type=1 - Philips PAL_I (FI1246 and compatibles)
+  type=2 - Philips NTSC (FI1236 and compatibles)
+  type=3 - Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)
   type=4 - NoTuner
-  type=5 - Philips PAL
+  type=5 - Philips PAL_BG (FI1216 and compatibles)
   type=6 - Temic NTSC (4032 FY5)
   type=7 - Temic PAL_I (4062 FY5)
   type=8 - Temic NTSC (4036 FY5)
@@ -103,7 +105,7 @@
   type=20 - Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)
   type=21 - Temic NTSC (4039 FR5)
   type=22 - Temic PAL/SECAM multi (4046 FM5)
-  type=23 - Philips PAL_DK
+  type=23 - Philips PAL_DK (FI1256 and compatibles)
   type=24 - Philips PAL/SECAM multi (FQ1216ME)
   type=25 - LG PAL_I+FM (TAPC-I001D)
   type=26 - LG PAL_I (TAPC-I701D)
@@ -118,3 +120,5 @@
   type=35 - Temic PAL_DK/SECAM_L (4012 FY5)
   type=36 - Temic NTSC (4136 FY5)
   type=37 - LG PAL (newer TAPC series)
+  type=38 - Philips PAL/SECAM multi (FM1216ME MK3)
+  type=39 - LG NTSC (newer TAPC series)
diff -urN linux-2.4.20-pre1/Documentation/video4linux/bttv/Cards linux-2.4.20-pre2/Documentation/video4linux/bttv/Cards
--- linux-2.4.20-pre1/Documentation/video4linux/bttv/Cards	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/Documentation/video4linux/bttv/Cards	Mon Aug 12 16:34:14 2002
@@ -1,3 +1,8 @@
+
+Gunther Mayer's bttv card gallery (graphical version of this text file :-)
+is available at: http://mayerg.gmxhome.de/bttv/bttv-gallery.html
+
+
 Suppported cards:
 
 
@@ -91,10 +96,9 @@
 - sound decoder: TDA9800, MSP34xx (stereo cards) 
 
 
-CPH-Series (CPH050, ...)
-------------------------
-Developed by TelSignal(?), OEMed by many vendors (Askey, Typhoon, 
-  Anubis, Dynalink)
+Askey CPH-Series
+----------------
+Developed by TelSignal(?), OEMed by many vendors (Typhoon, Anubis, Dynalink)
 
   Card series:
     CPH01x: BT848 capture only
@@ -149,9 +153,13 @@
       LR50 Rev.Q = Flyvideo 98 (w/eeprom and PCI subsystem ID)
            Rev.W = Flyvideo 98 (no eeprom)
       LR51 Rev.E = Flyvideo 98 EZ (capture only)
-      LR90       = Flyvideo 2000 series
+      LR90       = Flyvideo 2000 (Bt878)
+		   Flyvideo 2000S (Bt878) w/Stereo TV (Package incl. LR91 daughterboard)
       LR91       = Stereo daughter card for LR90
       LR97       = Flyvideo DVBS
+      LR99 Rev.E = Low profile card for OEM integration (only internal audio!) bt878
+      LR136	 = Flyvideo 2100/3100 (Low profile, SAA7130/SAA7134)
+      LR137      = Flyvideo DV2000/DV3000 (SAA7130/SAA7134 + IEEE1394)
       LR138 Rev.C= Flyvideo 2000 (SAA7130)
 	        or Flyvideo 3000 (SAA7134) w/Stereo TV
 		   These exist in variations w/FM and w/Remote sometimes denoted
@@ -162,15 +170,14 @@
       Their Bt8x8 cards are listed as discontinued.
       Flyvideo 2000S was probably sold as Flyvideo 3000 in some contries(Europe?).
       The new Flyvideo 2000/3000 are SAA7130/SAA7134 based. 
-      Flyvideo 2100/3100 are half-sized cards (for system integrators etc.)
 
   "Flyvideo II" had been the name for the 848 cards, nowadays (in Germany)
   this name is re-used for LR50 Rev.W.
   The Lifeview website mentioned Flyvideo III at some time, but such a card
-  has never been seen. 
+  has not yet been seen (perhaps it was the german name for LR90 [stereo]).
   These cards are sold by many OEMs too.
 
-  FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821)
+  FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) {Germany}
 
 
 Typhoon TV card series:
@@ -190,7 +197,12 @@
   50686 "TV Tuner"                       = KNC1 TV Station
   50687 "TV Tuner stereo"                = KNC1 TV Station pro
   50688 "TV Tuner RDS" (black package)   = KNC1 TV Station RDS
+  50689  TV SAT DVB-S CARD CI PCI (SAA7146AH)
   50692 "TV/FM Tuner" (small PCB)
+  50694  TV TUNER CARD RDS (PHILIPS CHIPSET SAA7134HL)
+  50696  TV TUNER STEREO (PHILIPS CHIPSET SAA7134HL, MK3ME Tuner)
+  50804  PC-SAT TV/Audio Karte = Techni-PC-Sat (ZORAN 36120PQC, Tuner:Alps)
+  50866  TVIEW SAT RECEIVER+ADR
   50868 "TV/FM Tuner Pal I" (variant of 50682)
   50999 "TV/FM Tuner Secam" (variant of 50682)
 
@@ -207,16 +219,31 @@
 
 Prolink
 -------
-   Pixelview Play TV Pro:
-     PV-BT878P+rev.9B (Play TV Pro w/FM w/NICAM)
-     PV-BT878P+rev.8X 
-     PV-BT878P+rev.4C (Play TV Pro) 
-     PV-BT878P+rev.4E (Play TV Pak) 
-     PV-BT878P+rev.2F 
-     PV-BT878TV 
-
-   PixelView Play TV 
-     PV-BT848P+
+   TV cards:
+   PixelView Play TV pro - (Model: PV-BT878P+ REV 8E)
+   PixelView Play TV pro - (Model: PV-BT878P+ REV 9D)
+   PixelView Play TV pro - (Model: PV-BT878P+ REV 4C / 8D / 10A )
+   PixelView Play TV - (Model: PV-BT848P+)
+   878TV - (Model: PV-BT878TV)
+
+   Multimedia TV packages (card + software pack):
+   PixelView Play TV Theater - (Model: PV-M4200) =  PixelView Play TV pro + Software
+   PixelView Play TV PAK -     (Model: PV-BT878P+ REV 4E)
+   PixelView Play TV/VCR -     (Model: PV-M3200 REV 4C / 8D / 10A ) 
+   PixelView Studio PAK -      (Model:    M2200 REV 4C / 8D / 10A )
+   PixelView PowerStudio PAK - (Model: PV-M3600 REV 4E)
+   PixelView DigitalVCR PAK -  (Model: PV-M2400 REV 4C / 8D / 10A )
+
+   Further Cards:
+   PV-BT878P+rev.9B (Play TV Pro, opt. w/FM w/NICAM)
+   PV-BT878P+rev.2F
+   PV-BT878P Rev.1D (bt878, capture only)
+   
+   Video Conferencing:
+   PixelView Meeting PAK - (Model: PV-BT878P)
+   PixelView Meeting PAK Lite - (Model: PV-BT878P)
+   PixelView Meeting PAK plus - (Model: PV-BT878P+rev 4C/8D/10A)
+   PixelView Capture - (Model: PV-BT848P)
 
 Dynalink
 --------
@@ -235,7 +262,7 @@
 Tekram
 ------
    VideoCap C205 (Bt848)
-   VideoCap C210 (Zoran ZR36120 +Philips)
+   VideoCap C210 (zr36120 +Philips)
    CaptureTV M200 (ISA)
    CaptureTV M205 (Bt848)
 
@@ -257,8 +284,10 @@
    TV-Station FM (+Radio)
    TV-Station RDS (+RDS)
 
-PV951 cards:
-------------
+   newer Cards have saa7134, but model name stayed the same?
+
+Provideo PV951 
+--------------
   These are sold as:
    Boeder TV-FM Video Capture Card
    Titanmedia Supervision TV-2400
@@ -270,12 +299,14 @@
 Highscreen
 ----------
    TV Karte = LR50 Rev.S
-   TV-Boostar = Terratec Terra TV+ Version 1.0 (Bt848, TDA9821) "ceb105.pcb"
+   TV-Boostar = Terratec Terra TV+ Version 1.0 (Bt848, tda9821) "ceb105.pcb"
 
 Zoltrix
 -------
+   Face to Face Capture (Bt848 capture only) (PCB "VP-2848")
    Face To Face TV MAX (Bt848) (PCB "VP-8482 Rev1.3")
    Genie TV (Bt878) (PCB "VP-8790 Rev 2.1")
+   Genie Wonder Pro
 
 AVerMedia
 ---------
@@ -302,21 +333,24 @@
 
 Aimslab
 -------
+   Video Highway or "Video Highway TR200" (ISA)
    Video Highway Xtreme (aka "VHX") (Bt848, FM w/ TEA5757)
 
-IXMicro
+IXMicro (former: IMS=Integrated Micro Solutions)
 -------
    IXTV BT848
    IXTV BT878
    TurboTV (Bt848)
 
 Lifetec/Medion/Tevion/Aldi
--------
-   LT9415/MD9415 = LR90 Rev. F
+--------------------------
+   LT9306/MD9306 = CPH061
+   LT9415/MD9415 = LR90 Rev.F or Rev.G
           MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
+          MD9717 = KNC One (Rev D4, saa7134)
 
 Modular Technologies (www.modulartech.com) UK
---------------------
+---------------------------------------------
    MM100 PCTV (Bt848)
    MM205 PCTV (Bt878)
    MM210 PCTV (Bt878) (Galaxy TV)
@@ -326,19 +360,28 @@
    Terra TV+ Version 1.0 (Bt848), "ceb105.PCB" printed on the PCB, TDA9821
    Terra TV+ Version 1.1 (Bt878), "LR74 Rev.E" printed on the PCB, TDA9821
    Terra TValueRadio,             "LR102 Rev.C" printed on the PCB
-   Terra TV/Radio+ Version 1.0,   "80-CP2830100-0" TTTV3 printed on the PCB, i
+   Terra TV/Radio+ Version 1.0,   "80-CP2830100-0" TTTV3 printed on the PCB,
 				     "CPH010-E83" on the back, SAA6588T, TDA9873H
    Terra TValue Version BT878,    "80-CP2830110-0 TTTV4" printed on the PCB, 
 				     "CPH011-D83" on back
    Terra TValue Version 1.0       "ceb105.PCB" (really identical to Terra TV+ Version 1.0)
+   Terra Active Radio Upgrade (tea5757h, saa6588t)
 
    LR74 is a newer PCB revision of ceb105 (both incl. connector for Active Radio Upgrade)
 
+   Cinergy 400 (saa7134), "E877 11(S)", "PM820092D" printed on PCB
 
 Technisat
 ---------
-   Mediafocus I (ZR36120/ZR36125)
-   Mediafocus II (SAA7146)
+   Discos ADR PC-Karte ISA (no TV!)
+   Discos ADR PC-Karte PCI (probably no TV?)
+   Techni-PC-Sat (Sat. analog)
+         Rev 1.2 (zr36120, vpx3220, stv0030, saa5246, BSJE3-494A)
+   Mediafocus I (zr36120/zr36125, drp3510, Sat. analog + ADR Radio)
+   Mediafocus II (saa7146, Sat. analog)
+         SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
+   SkyStar 1 DVB  (AV7110)
+   SkyStar 2 DVB  (B2C2) (=Sky2PC)
 
 Siemens
 -------
@@ -359,34 +402,262 @@
    Mirovideo PCTV (Bt848)
    Mirovideo PCTV SE (Bt848)
    Mirovideo PCTV Pro (Bt848 + Daughterboard)
-   Studio PCTV Rave (Bt878 w/o infrared)
-   Studio PCTV
-   Studio PCTV Pro (Bt878 stereo w/ FM)
+   Studio PCTV Rave (Bt878 package w/o infrared)
+   Studio PCTV      (Bt878)
+   Studio PCTV Pro  (Bt878 stereo w/ FM)
 
+   M(J)PEG capture and playback:
    DC1+ (ISA)
-   DC10  (zr36057 + zr36060 + saa7110 + adv7176)
-   DC10+ (zr36067 + zr36060 + saa7110 + adv7176)
-   DC20
-   DC30
-   DC30+ (zr36067 + zr36050 + zr36016 + vpx3220 + adv7176)
+   DC10  (zr36057,     zr36060,      saa7110, adv7176)
+   DC10+ (zr36067,     zr36060,      saa7110, adv7176)
+   DC20  (ql16x24b,zr36050, zr36016, saa7110, saa7187 ...)
+   DC30  (zr36057, zr36050, zr36016, vpx3220, adv7176, ad1843, tea6415, miro FST97A1)
+   DC30+ (zr36067, zr36050, zr36016, vpx3220, adv7176)
+   DC50  (zr36067, zr36050, zr36016, saa7112, adv7176 (2 pcs.?), ad1843, miro FST97A1, Lattice ???)
 
 Lenco
 -----
    MXR-9565 (=Technisat Mediafocus?)
-   MXR-9571 (Bt848)
+   MXR-9571 (Bt848) (=CPH031?)
    MXR-9575
-   MXR-9477 (Bt878)
-   MXTV-9578CP (= Prolink PV-BT878P+4E)
+   MXR-9577 (Bt878) (=Prolink 878TV Rev.3x)
+   MXTV-9578CP (Bt878) (= Prolink PV-BT878P+4E)
 
 Iomega
 ------
-   Buz (Zoran zr36067 + zr36060 + SAA7111 + SAA7185)
+   Buz (zr36067, zr36060, saa7111, saa7185)
 
 LML
 ---
-   LML33 (zr36067 + zr36060 + bt819+ bt856)
+   LML33 (zr36067, zr36060, bt819, bt856)
 
 Grandtec
 --------
    Grand Video Capture (Bt848)
    Multi Capture Card  (Bt878)
+
+Koutech
+-------
+   KW-606 (Bt848)
+   KW-607 (Bt848 capture only)
+   KW-606RSF
+   KW-607A (capture only)
+   KW-608 (Zoran capture only)
+ 
+IODATA (jp)
+------
+   GV-BCTV/PCI
+   GV-BCTV2/PCI
+   GV-BCTV3/PCI
+   GV-BCTV4/PCI
+   GV-VCP/PCI (capture only)
+   GV-VCP2/PCI (capture only)
+
+Canopus (jp)
+-------
+   WinDVR	= Kworld "KW-TVL878RF"
+
+www.sigmacom.co.kr 
+------------------
+   Sigma Cyber TV II 
+
+www.sasem.co.kr
+---------------
+   Litte OnAir TV
+
+hama 
+----
+   TV/Radio-Tuner Card, PCI (Model 44677) = CPH051
+
+Sigma Designs
+-------------
+   Hollywood plus (em8300, em9010, adv7175), (PCB "M340-10") MPEG DVD decoder
+
+Formac
+------
+   iProTV (Card for iMac Mezzanine slot, Bt848+SCSI)
+   ProTV (Bt848)
+   ProTV II = ProTV Stereo (Bt878)
+
+ATI
+---
+   TV-Wonder
+   TV-Wonder VE
+
+Diamond Multimedia
+------------------
+   DTV2000 (Bt848, tda9875)
+
+Aopen
+-----
+   VA1000 Plus (w/ Stereo)
+   VA1000 Lite
+   VA1000 (=LR90)
+
+Intel
+-----
+   Smart Video Recorder (ISA full-length)
+   Smart Video Recorder pro (ISA half-length)
+   Smart Video Recorder III (Bt848)
+
+STB
+---
+   TV PCI (Temic4032FY5, tda9850??)
+   other variants?
+
+Videologic
+----------
+   Captivator Pro/TV (ISA?)
+   Captivator PCI/VC (Bt848 bundled with camera) (capture only)
+
+Technotrend
+------------
+   TT-SAT PCI (PCB "Sat-PCI Rev.:1.3.1"; zr36125, vpx3225d, stc0056a, Tuner:BSKE6-155A
+   TT-DVB-Sat
+   TT-DVB-C PCI
+
+Teles
+-----
+   DVB-s (Rev. 2.2, BSRV2-301A, data only?)
+
+Remote Vision
+-------------
+   MX RV605 (Bt848 capture only)
+
+Boeder
+------
+   PC ChatCam (Model 68252) (Bt848 capture only)
+   Tv/Fm Capture Card  (Model 68404) = PV951
+
+Media-Surfer  (esc-kathrein.de)
+-------------------------------
+   Sat-Surfer (ISA)
+   Sat-Surfer PCI = Techni-PC-Sat
+   Cable-Surfer 1
+   Cable-Surfer 2
+   Cable-Surfer PCI (zr36120)
+   Audio-Surfer (ISA Radio card)
+
+Jetway (www.jetway.com.tw)
+--------------------------
+   JW-TV 878M 
+   JW-TV 878  = KWorld KW-TV878RF
+
+Galaxis
+-------
+   Galaxis DVB Card S CI
+   Galaxis DVB Card C CI
+   Galaxis DVB Card S
+   Galaxis DVB Card C
+
+Hauppauge
+---------
+   many many WinTV models ...
+   WinTV DVBs
+   WinTV NOVA
+   WinTV NOVA-CI
+   WinTV-Nexus-s
+
+Matrix-Vision
+-------------
+   MATRIX-Vision MV-Delta
+   MATRIX-Vision MV-Delta 2
+   MVsigma-SLC (Bt848)
+
+Conceptronic (.net)
+------------
+   TVCON FM,  TV card w/ FM = CPH05x
+
+BestData
+--------
+   HCC100 = VCC100rev1 + camera
+   VCC100 rev1 (bt848)
+   VCC100 rev2 (bt878)
+
+Gallant  (www.gallantcom.com) www.minton.com.tw
+-----------------------------------------------
+   Intervision IV-510 (capture only bt8x8)
+   Intervision IV-550 (bt8x8)
+   Intervision IV-100 (zoran)
+   Intervision IV-1000 (bt8x8)
+   
+Asonic (www.asonic.com.cn) (website down)
+-----------------------------------------
+   SkyEye tv 878
+
+Hoontech
+--------
+   878TV/FM
+
+Teppro (www.itcteppro.com.tw)
+-----------------------------
+   ITC PCITV (Card Ver 1.0) "Teppro TV1/TVFM1 Card"
+   ITC PCITV (Card Ver 2.0)
+   ITC PCITV (Card Ver 3.0) = "PV-BT878P+ (REV.9D)"
+   ITC PCITV (Card Ver 4.0)
+   TEPPRO IV-550 (For BT848 Main Chip)
+   ITC DSTTV (bt878, satellite)
+   ITC VideoMaker (saa7146, StreamMachine sm2110, tvtuner) "PV-SM2210P+ (REV:1C)"
+
+Kworld (www.kworld.com.tw)
+--------------------------
+   KWORLD KW-TV878RF-Pro TV Capture with FM Radio
+   KWORLD KW-TV878R-Pro TV
+   KWORLD KW-TVL878RF  (low profile)
+   KWORLD KW-TV878R TV Capture (No FM Radio)
+   KWORLD KW-TV878RF TV
+
+JTT/ Justy Corp.http://www.justy.co.jp/ (www.jtt.com.jp website down)
+---------------------------------------------------------------------
+   JTT-02 (JTT TV) "TV watchmate pro" (bt848) 
+
+ADS www.adstech.com
+-------------------
+   Channel Surfer TV ( CHX-950 ) 
+   Channel Surfer TV+FM ( CHX-960FM )
+
+AVEC www.prochips.com
+---------------------
+   AVEC Intercapture (bt848, tea6320)
+
+NoBrand
+-------
+   TV Excel = Australian Name for "PV-BT878P+ 8E" or so
+
+Mach www.machspeed.com
+----
+   Mach TV 878
+
+Eline www.eline-net.com/
+-----
+   Eline Vision TVMaster / TVMaster FM (ELV-TVM/ ELV-TVM-FM) = LR26  (bt878)
+   Eline Vision TVMaster-2000 (ELV-TVM-2000, ELV-TVM-2000-FM)= LR138 (saa713x)
+
+Spirit http://www.spiritmodems.com.au/
+------
+   Spirit TV Tuner/Video Capture Card (bt848)
+
+Boser www.boser.com.tw
+-----
+   HS-878 Mini PCI Capture Add-on Card
+   HS-879 Mini PCI 3D Audio and Capture Add-on Card (w/ ES1938 Solo-1)
+
+Satelco
+-------
+   TV-FM =KNC1 saa7134
+
+Sensoray www.sensoray.com
+--------
+   Sensoray 311 (PC/104 bus)
+   Sensoray 611 (PCI)
+
+CEI (Chartered Electronics Industries Pte Ltd [CEI] [FCC ID HBY])
+---
+  TV Tuner  -  HBY-33A-RAFFLES  Brooktree Bt848KPF + Philips
+  TV Tuner MG9910  -  HBY33A-TVO  CEI + Philips SAA7110 + OKI M548262 + ST STV8438CV
+  Primetime TV (ISA)
+   acquired by Singapore Technologies
+   now operating as Chartered Semiconductor Manufacturing
+   Manufacturer of video cards is listed as:
+   Cogent Electronics Industries [CEI]
+
diff -urN linux-2.4.20-pre1/Documentation/video4linux/bttv/Insmod-options linux-2.4.20-pre2/Documentation/video4linux/bttv/Insmod-options
--- linux-2.4.20-pre1/Documentation/video4linux/bttv/Insmod-options	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/Documentation/video4linux/bttv/Insmod-options	Mon Aug 12 16:34:14 2002
@@ -29,7 +29,7 @@
 		irq_debug=0/1	irq handler debug messages.
 				default is 0 (off).
 		gbuffers=2-32	number of capture buffers for mmap'ed capture.
-				default is 2.
+				default is 4.
 		gbufsize=	size of capture buffers. default and
 				maximum value is 0x208000 (~2MB)
 		no_overlay=0	Enable overlay on broken hardware.  There
diff -urN linux-2.4.20-pre1/Documentation/video4linux/bttv/README linux-2.4.20-pre2/Documentation/video4linux/bttv/README
--- linux-2.4.20-pre1/Documentation/video4linux/bttv/README	Sun Aug  5 13:15:05 2001
+++ linux-2.4.20-pre2/Documentation/video4linux/bttv/README	Mon Aug 12 16:34:14 2002
@@ -58,6 +58,9 @@
 		the helper modules.
 MAKEDEV:	a script to create the special files for v4l
 CARDLIST:	List of all supported cards
+Cards:		more detailed descriptions of known TV cards:
+		OEM name variants, used i2c chips, ...
+		also includes non-bttv cards.
 
 Loading just the bttv modules isn't enouth for most cards.  The
 drivers for the i2c tuner/sound chips must also be loaded.  bttv tries
@@ -73,6 +76,12 @@
 video but no sound you've very likely specified the wrong (or no)
 card type.  A list of supported cards is in CARDLIST.
 
+For the WinTV/PVR you need one firmware file from the driver CD:
+hcwamc.rbf.  The file is in the pvr45xxx.exe archive (self-extracting
+zip file, unzip can unpack it).  Put it into the /etc/pvr directory or
+use the firm_altera=<path> insmod option to point the driver to the
+location of the file.
+
 If your card isn't listed in CARDLIST or if you have trouble making
 audio work, you should read the Sound-FAQ.
 
diff -urN linux-2.4.20-pre1/Documentation/video4linux/bttv/README.freeze linux-2.4.20-pre2/Documentation/video4linux/bttv/README.freeze
--- linux-2.4.20-pre1/Documentation/video4linux/bttv/README.freeze	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/Documentation/video4linux/bttv/README.freeze	Mon Aug 12 16:34:14 2002
@@ -46,6 +46,11 @@
 the PCI bus. The bt848/878 chips have a few workarounds for known
 incompatibilities, see README.quirks.
 
+Some folks report that increasing the pci latency helps too,
+althrought I'm not sure whenever this really fixes the problems or
+only makes it less likely to happen.  Both bttv and btaudio have a
+insmod option to set the PCI latency of the device.
+
 Some mainboard have problems to deal correctly with multiple devices
 doing DMA at the same time.  bttv + ide seems to cause this sometimes,
 if this is the case you likely see freezes only with video and hard disk
@@ -56,6 +61,9 @@
 other
 -----
 
+If you use some binary-only yunk (like nvidia module) try to reproduce
+the problem without.
+
 IRQ sharing is known to cause problems in some cases.  It works just
 fine in theory and many configurations.  Neverless it might be worth a
 try to shuffle around the PCI cards to give bttv another IRQ or make
@@ -63,3 +71,4 @@
 VGA cards seems to cause trouble sometimes.  I've also seen funny
 effects with bttv sharing the IRQ with the ACPI bridge (and
 apci-enabled kernel).
+
diff -urN linux-2.4.20-pre1/Documentation/video4linux/bttv/Tuners linux-2.4.20-pre2/Documentation/video4linux/bttv/Tuners
--- linux-2.4.20-pre1/Documentation/video4linux/bttv/Tuners	Wed Oct 17 14:19:20 2001
+++ linux-2.4.20-pre2/Documentation/video4linux/bttv/Tuners	Mon Aug 12 16:34:14 2002
@@ -1,3 +1,16 @@
+1) Tuner Programming
+====================
+There are some flavors of Tuner programming APIs.
+These differ mainly by the bandswitch byte.
+
+    L= LG_API       (VHF_LO=0x01, VHF_HI=0x02, UHF=0x08, radio=0x04)
+    P= PHILIPS_API  (VHF_LO=0xA0, VHF_HI=0x90, UHF=0x30, radio=0x04)
+    T= TEMIC_API    (VHF_LO=0x02, VHF_HI=0x04, UHF=0x01)
+    A= ALPS_API     (VHF_LO=0x14, VHF_HI=0x12, UHF=0x11)
+    M= PHILIPS_MK3  (VHF_LO=0x01, VHF_HI=0x02, UHF=0x04, radio=0x19)
+
+2) Tuner Manufacturers
+======================
 
 SAMSUNG Tuner identification: (e.g. TCPM9091PD27)
   TCP [ABCJLMNQ] 90[89][125] [DP] [ACD] 27 [ABCD]
@@ -10,6 +23,7 @@
    M= BG+I+DK
    N= NTSC 
    Q= BG+I+DK+LL
+ [89]: ?
  [125]:
    2: No FM
    5: With FM
@@ -23,43 +37,49 @@
  [ABCD]:
    3-wire/I2C tuning, 2-band/3-band
 
+ These Tuners are PHILIPS_API compatible.
+
 Philips Tuner identification: (e.g. FM1216MF)
-  F[IRMQ]12[1345]{MF|ME|MP}
-  [IRMQ]:
-   I: Tuner Series
-   R: Tuner + Radio IF
-   M: Tuner + FM
-   Q,MR: specials
+  F[IRMQ]12[1345]6{MF|ME|MP}
+  F[IRMQ]:
+   FI12x6: Tuner Series
+   FR12x6: Tuner + Radio IF
+   FM12x6: Tuner + FM
+   FQ12x6: special
+   FMR12x6: special
    TD15xx: Digital Tuner ATSC
-  [1345]
-   1: PAL BG
-   3: NTSC
-   4: PAL I
-   5: Pal DK
+  12[1345]6:
+   1216: PAL BG
+   1236: NTSC
+   1246: PAL I
+   1256: Pal DK
   {MF|ME|MP}
-   MF: w/ Secam
-   ME: BD DK I LL
-   MP: BG DK I
+   MF: BG LL w/ Secam (Multi France)
+   ME: BG DK I LL   (Multi Europe)
+   MP: BG DK I      (Multi PAL)
    MR: BG DK M (?)
    MG: BG DKI M (?)
+  MK2 series PHILIPS_API, most tuners are compatible to this one !
+  MK3 series introduced in 2002 w/ PHILIPS_MK3_API
 
 Temic Tuner identification: (.e.g 4006FH5)
    4[01][0136][269]F[HYNR]5
-    40x2: Tuner (5V/33V), different I2C programming from Philips !
+    40x2: Tuner (5V/33V), TEMIC_API.
     40x6: Tuner 5V
     41xx: Tuner compact
     40x9: Tuner+FM compact
    [0136]
-    0: PAL BG
-    1: Pal DK, Secam LL
-    3: NTSC
-    6: PAL I
+    xx0x: PAL BG
+    xx1x: Pal DK, Secam LL
+    xx3x: NTSC
+    xx6x: PAL I
    F[HYNR]5
     FH5: Pal BG
     FY5: others
     FN5: multistandard
     FR5: w/ FM radio
    3X xxxx: order number with specific connector
+  Note: Only 40x2 series has TEMIC_API, all newer tuners have PHILIPS_API.
 
 LG Innotek Tuner:
   TPI8NSR11 : NTSC J/M    (TPI8NSR01 w/FM)  (P,210/497)
@@ -76,13 +96,20 @@
   TADC-H002F: NTSC (L,175/410?; 2-B, C-W+11, W+12-69)
   TADC-M201D: PAL D/K+B/G+I (L,143/425)  (sound control at I2C address 0xc8)
   TADC-T003F: NTSC Taiwan  (L,175/410?; 2-B, C-W+11, W+12-69)
-
-  (API,Lo-Hi-takeover/Hi-UHF-takeover)
-   I2C APIs:
-    L= LG programming (VHF_LO=0x01, VHF_HI=0x02, UHF=0x08, radio=0x04)
-    P= Philips progr. (VHF_LO=0xA0, VHF_HI=0x90, UHF=0x30, radio=0x04)
-    T= Temic progr.   (VHF_LO=0x02, VHF_HI=0x04, UHF=0x01)
   Suffix: 
     P= Standard phono female socket
     D= IEC female socket
     F= F-connector
+
+Other Tuners:
+TCL2002MB-1 : PAL BG + DK       =TUNER_LG_PAL_NEW_TAPC
+TCL2002MB-1F: PAL BG + DK w/FM  =PHILIPS_PAL
+TCL2002MI-2 : PAL I		= ??
+
+ALPS Tuners:
+   Most are LG_API compatible
+   TSCH6 has ALPS_API (TSCH5 ?)
+   TSBE1 has extra API 05,02,08 Control_byte=0xCB Source:(1)
+
+Lit.
+(1) conexant100029b-PCI-Decoder-ApplicationNote.pdf
diff -urN linux-2.4.20-pre1/Documentation/video4linux/meye.txt linux-2.4.20-pre2/Documentation/video4linux/meye.txt
--- linux-2.4.20-pre1/Documentation/video4linux/meye.txt	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/Documentation/video4linux/meye.txt	Mon Aug 12 16:34:14 2002
@@ -86,7 +86,7 @@
 
 	MEYEIOC_SYNC
 		Takes as an argument the buffer number you want to sync.
-		This ioctl blocks untils the buffer is filled and ready
+		This ioctl blocks until the buffer is filled and ready
 		for the application to use. It returns the buffer size.
 
 	MEYEIOC_STILLCAPT
@@ -106,7 +106,7 @@
 		
 	- mjpeg hardware playback doesn't work (depends on overlay...)
 
-	- rewrite the driver to use some commun video4linux API for snapshot
+	- rewrite the driver to use some common video4linux API for snapshot
 	  and mjpeg capture. Unfortunately, video4linux1 does not permit it,
 	  the BUZ API seems to be targeted to TV cards only. The video4linux 2
 	  API may be an option, if it goes into the kernel (maybe 2.5 
diff -urN linux-2.4.20-pre1/MAINTAINERS linux-2.4.20-pre2/MAINTAINERS
--- linux-2.4.20-pre1/MAINTAINERS	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/MAINTAINERS	Mon Aug 12 16:34:14 2002
@@ -1545,6 +1545,13 @@
 M:	hch@infradead.org
 S:	Maintained
 
+TI GRAPH LINK USB (SilverLink) CABLE DRIVER
+P:      Romain Lievin
+M:      roms@lpg.ticalc.org
+P:      Julien Blache
+M:      jb@technologeek.org
+S:      Maintained
+
 TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
 P:	Stephane Dalton
 M:	sdalton@videotron.ca
diff -urN linux-2.4.20-pre1/Makefile linux-2.4.20-pre2/Makefile
--- linux-2.4.20-pre1/Makefile	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/Makefile	Mon Aug 12 16:34:14 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 20
-EXTRAVERSION = -pre1
+EXTRAVERSION = -pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -170,7 +170,7 @@
 DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
 DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o
 DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
-DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.o
+DRIVERS-$(CONFIG_PPC32) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o
 DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
@@ -369,7 +369,7 @@
 TAGS: dummy
 	{ find include/asm-${ARCH} -name '*.h' -print ; \
 	find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print ; \
-	find $(SUBDIRS) init arch/${ARCH} -name '*.[chS]' ; } | grep -v SCCS | etags -
+	find $(SUBDIRS) init arch/${ARCH} -name '*.[chS]' ; } | grep -v SCCS | grep -v '\.svn' | etags -
 
 # Exuberant ctags works better with -I
 tags: dummy
@@ -487,7 +487,7 @@
 
 dep-files: scripts/mkdep archdep include/linux/version.h
 	scripts/mkdep -- init/*.c > .depend
-	scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
+	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
 ifdef CONFIG_MODVERSIONS
 	$(MAKE) update-modverfile
diff -urN linux-2.4.20-pre1/arch/alpha/config.in linux-2.4.20-pre2/arch/alpha/config.in
--- linux-2.4.20-pre1/arch/alpha/config.in	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/alpha/config.in	Mon Aug 12 16:34:14 2002
@@ -250,9 +250,9 @@
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   bool 'Discontiguous Memory Support' CONFIG_DISCONTIGMEM
+   bool 'Discontiguous Memory Support (EXPERIMENTAL)' CONFIG_DISCONTIGMEM
    if [ "$CONFIG_DISCONTIGMEM" = "y" ]; then
-      bool ' NUMA Support' CONFIG_NUMA
+      bool ' NUMA Support (EXPERIMENTAL)' CONFIG_NUMA
    fi
 fi
 
@@ -360,7 +360,7 @@
 mainmenu_option next_comment
 comment 'Old CD-ROM drivers (not SCSI, not IDE)'
 
-bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
+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
@@ -423,3 +423,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/alpha/kernel/traps.c linux-2.4.20-pre2/arch/alpha/kernel/traps.c
--- linux-2.4.20-pre1/arch/alpha/kernel/traps.c	Tue Nov 20 15:49:31 2001
+++ linux-2.4.20-pre2/arch/alpha/kernel/traps.c	Mon Aug 12 16:34:14 2002
@@ -167,6 +167,11 @@
 	dik_show_trace(sp);
 }
 
+void dump_stack(void)
+{
+	show_stack(NULL);
+}
+
 void
 die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15)
 {
diff -urN linux-2.4.20-pre1/arch/arm/config.in linux-2.4.20-pre2/arch/arm/config.in
--- linux-2.4.20-pre1/arch/arm/config.in	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/arm/config.in	Mon Aug 12 16:34:14 2002
@@ -417,7 +417,7 @@
 fi
 
 source drivers/pci/Config.in
-bool 'Support hot-pluggable devices' CONFIG_HOTPLUG
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
 if [ "$CONFIG_HOTPLUG" = "y" ]; then
    source drivers/pcmcia/Config.in
 else
@@ -503,7 +503,7 @@
    mainmenu_option next_comment
    comment 'Network device support'
 
-   bool 'Network device support?' CONFIG_NETDEVICES
+   bool 'Network device support' CONFIG_NETDEVICES
    if [ "$CONFIG_NETDEVICES" = "y" ]; then
       source drivers/net/Config.in
    fi
@@ -530,7 +530,7 @@
 mainmenu_option next_comment
 comment 'SCSI support'
 
-tristate 'SCSI support?' CONFIG_SCSI
+tristate 'SCSI support' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
    source drivers/scsi/Config.in
@@ -618,7 +618,7 @@
    mainmenu_option next_comment
    comment 'Sound'
 
-   tristate 'Sound support' CONFIG_SOUND
+   tristate 'Sound card support' CONFIG_SOUND
    if [ "$CONFIG_SOUND" != "n" ]; then
       source drivers/sound/Config.in
    fi
@@ -655,3 +655,5 @@
 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
+
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/cris/config.in linux-2.4.20-pre2/arch/cris/config.in
--- linux-2.4.20-pre1/arch/cris/config.in	Mon Feb 25 11:37:52 2002
+++ linux-2.4.20-pre2/arch/cris/config.in	Mon Aug 12 16:34:14 2002
@@ -253,4 +253,6 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+
+source lib/Config.in
 endmenu
diff -urN linux-2.4.20-pre1/arch/cris/drivers/usb-host.c linux-2.4.20-pre2/arch/cris/drivers/usb-host.c
--- linux-2.4.20-pre1/arch/cris/drivers/usb-host.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.20-pre2/arch/cris/drivers/usb-host.c	Mon Aug 12 16:34:14 2002
@@ -193,17 +193,17 @@
 static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
 static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
 
-static urb_t *URB_List[NBR_OF_EP_DESC];
+static struct urb *URB_List[NBR_OF_EP_DESC];
 static kmem_cache_t *usb_desc_cache;
 static struct usb_bus *etrax_usb_bus;
 
 #ifdef USB_DEBUG_DESC
-static void dump_urb (purb_t purb);
+static void dump_urb (struct urb *urb);
 #endif
 static void init_rx_buffers(void);
-static int etrax_rh_unlink_urb (urb_t *urb);
-static void etrax_rh_send_irq(urb_t *urb);
-static void etrax_rh_init_int_timer(urb_t *urb);
+static int etrax_rh_unlink_urb (struct urb *urb);
+static void etrax_rh_send_irq(struct urb *urb);
+static void etrax_rh_init_int_timer(struct urb *urb);
 static void etrax_rh_int_timer_do(unsigned long ptr);
 
 static void etrax_usb_setup_epid(int epid, char devnum, char endpoint,
@@ -214,13 +214,13 @@
 static void etrax_usb_free_epid(int epid);
 static void cleanup_sb(USB_SB_Desc_t *sb);
 
-static void etrax_usb_do_ctrl_hw_add(urb_t *urb, int epid, char maxlen);
-static void etrax_usb_do_bulk_hw_add(urb_t *urb, int epid, char maxlen);
+static void etrax_usb_do_ctrl_hw_add(struct urb *urb, int epid, char maxlen);
+static void etrax_usb_do_bulk_hw_add(struct urb *urb, int epid, char maxlen);
 
-static int etrax_usb_submit_ctrl_urb(urb_t *urb);
+static int etrax_usb_submit_ctrl_urb(struct urb *urb);
 
-static int etrax_usb_submit_urb(urb_t *urb);
-static int etrax_usb_unlink_urb(urb_t *urb);
+static int etrax_usb_submit_urb(struct urb *urb);
+static int etrax_usb_unlink_urb(struct urb *urb);
 static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
 static int etrax_usb_allocate_dev(struct usb_device *usb_dev);
 static int etrax_usb_deallocate_dev(struct usb_device *usb_dev);
@@ -229,7 +229,7 @@
 static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
 static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs);
 
-static int etrax_rh_submit_urb (urb_t *urb);
+static int etrax_rh_submit_urb (struct urb *urb);
 
 static int etrax_usb_hc_init(void);
 static void etrax_usb_hc_cleanup(void);
@@ -244,24 +244,24 @@
 };
 
 #ifdef USB_DEBUG_DESC
-static void dump_urb(purb_t purb)
+static void dump_urb(struct urb *urb)
 {
-	printk("\nurb                   :0x%08X\n", purb);
-	printk("next                  :0x%08X\n", purb->next);
-	printk("dev                   :0x%08X\n", purb->dev);
-	printk("pipe                  :0x%08X\n", purb->pipe);
-	printk("status                :%d\n", purb->status);
-	printk("transfer_flags        :0x%08X\n", purb->transfer_flags);
-	printk("transfer_buffer       :0x%08X\n", purb->transfer_buffer);
-	printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk("actual_length         :%d\n", purb->actual_length);
-	printk("setup_packet          :0x%08X\n", purb->setup_packet);
-	printk("start_frame           :%d\n", purb->start_frame);
-	printk("number_of_packets     :%d\n", purb->number_of_packets);
-	printk("interval              :%d\n", purb->interval);
-	printk("error_count           :%d\n", purb->error_count);
-	printk("context               :0x%08X\n", purb->context);
-	printk("complete              :0x%08X\n\n", purb->complete);
+	printk("\nurb                   :0x%08X\n", urb);
+	printk("next                  :0x%08X\n", urb->next);
+	printk("dev                   :0x%08X\n", urb->dev);
+	printk("pipe                  :0x%08X\n", urb->pipe);
+	printk("status                :%d\n", urb->status);
+	printk("transfer_flags        :0x%08X\n", urb->transfer_flags);
+	printk("transfer_buffer       :0x%08X\n", urb->transfer_buffer);
+	printk("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+	printk("actual_length         :%d\n", urb->actual_length);
+	printk("setup_packet          :0x%08X\n", urb->setup_packet);
+	printk("start_frame           :%d\n", urb->start_frame);
+	printk("number_of_packets     :%d\n", urb->number_of_packets);
+	printk("interval              :%d\n", urb->interval);
+	printk("error_count           :%d\n", urb->error_count);
+	printk("context               :0x%08X\n", urb->context);
+	printk("complete              :0x%08X\n\n", urb->complete);
 }
 
 static void dump_in_desc(USB_IN_Desc_t *in)
@@ -425,7 +425,7 @@
 }
 
 
-static int etrax_usb_unlink_intr_urb(urb_t *urb)
+static int etrax_usb_unlink_intr_urb(struct urb *urb)
 {
 	USB_EP_Desc_t *tmp_ep;
 	USB_EP_Desc_t *first_ep;
@@ -511,7 +511,7 @@
 	} while (tmp_ep != first_ep);
 }
 
-static int etrax_usb_submit_intr_urb(urb_t *urb)
+static int etrax_usb_submit_intr_urb(struct urb *urb)
 {
 	USB_EP_Desc_t *tmp_ep;
 	USB_EP_Desc_t *first_ep;
@@ -641,7 +641,7 @@
 
 static void handle_intr_transfer_attn(int epid, int status)
 {
-	urb_t *old_urb;
+	struct urb *old_urb;
 
 	DBFENTER;
 
@@ -694,7 +694,7 @@
 	DBFEXIT;
 }
 
-static int etrax_rh_unlink_urb (urb_t *urb)
+static int etrax_rh_unlink_urb (struct urb *urb)
 {
 	etrax_hc_t *hc;
 	
@@ -711,7 +711,7 @@
 	return 0;
 }
 
-static void etrax_rh_send_irq(urb_t *urb)
+static void etrax_rh_send_irq(struct urb *urb)
 {
 	__u16 data = 0;
 	etrax_hc_t *hc = urb->dev->bus->hcpriv;
@@ -744,7 +744,7 @@
 /*	DBFEXIT; */
 }
 
-static void etrax_rh_init_int_timer(urb_t *urb)
+static void etrax_rh_init_int_timer(struct urb *urb)
 {
 	etrax_hc_t *hc;
 	
@@ -763,12 +763,12 @@
 
 static void etrax_rh_int_timer_do(unsigned long ptr)
 {
-	urb_t *urb;
+	struct urb *urb;
 	etrax_hc_t *hc;
 	
 /*	DBFENTER; */
 	
-	urb = (urb_t*)ptr;
+	urb = (struct urb*)ptr;
 	hc = urb->dev->bus->hcpriv;
 	
 	if (hc->rh.send) {
@@ -910,7 +910,7 @@
 	return -1;
 }
 
-static int etrax_usb_submit_bulk_urb(urb_t *urb)
+static int etrax_usb_submit_bulk_urb(struct urb *urb)
 {
 	int epid;
 	char devnum;
@@ -919,7 +919,7 @@
 	char out_traffic;
 	char slow;
 
-	urb_t *tmp_urb;
+	struct urb *tmp_urb;
 	
 	unsigned long flags;
 	
@@ -969,7 +969,7 @@
 	return 0;
 }
 
-static void etrax_usb_do_bulk_hw_add(urb_t *urb, int epid, char maxlen)
+static void etrax_usb_do_bulk_hw_add(struct urb *urb, int epid, char maxlen)
 {
 	USB_SB_Desc_t *sb_desc_1;
 
@@ -1086,7 +1086,7 @@
 
 static void handle_bulk_transfer_attn(int epid, int status)
 {
-	urb_t *old_urb;
+	struct urb *old_urb;
 	etrax_urb_priv_t *hc_priv;
 	unsigned long flags;
 
@@ -1166,7 +1166,7 @@
 
 /* ---------------------------------------------------------------------------- */
 
-static int etrax_usb_submit_ctrl_urb(urb_t *urb)
+static int etrax_usb_submit_ctrl_urb(struct urb *urb)
 {
 	int epid;
 	char devnum;
@@ -1175,7 +1175,7 @@
 	char out_traffic;
 	char slow;
 
-	urb_t *tmp_urb;
+	struct urb *tmp_urb;
 	
 	unsigned long flags;
 	
@@ -1225,7 +1225,7 @@
 	return 0;
 }
 
-static void etrax_usb_do_ctrl_hw_add(urb_t *urb, int epid, char maxlen)
+static void etrax_usb_do_ctrl_hw_add(struct urb *urb, int epid, char maxlen)
 {
 	USB_SB_Desc_t *sb_desc_1;
 	USB_SB_Desc_t *sb_desc_2;
@@ -1364,7 +1364,7 @@
 	DBFEXIT;
 }
 
-static int etrax_usb_submit_urb(urb_t *urb)
+static int etrax_usb_submit_urb(struct urb *urb)
 {
 	etrax_hc_t *hc;
 	int rval = -EINVAL;
@@ -1411,7 +1411,7 @@
 	return rval;
 }
 
-static int etrax_usb_unlink_urb(urb_t *urb)
+static int etrax_usb_unlink_urb(struct urb *urb)
 {
 	etrax_hc_t *hc = urb->dev->bus->hcpriv;
 	int epid;
@@ -1455,8 +1455,8 @@
 	cli();
 	
 	for (epid = 0; epid < 32; epid++) {
-		urb_t *u = URB_List[epid];
-		urb_t *prev = NULL;
+		struct urb *u = URB_List[epid];
+		struct urb *prev = NULL;
 		int pos = 0;
 
 		for (; u; u = u->next) {
@@ -1557,7 +1557,7 @@
 static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
 {
 	int epid = 0;
-	urb_t *urb;
+	struct urb *urb;
 	etrax_urb_priv_t *urb_priv;
 		
 	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
@@ -1655,7 +1655,7 @@
 
 static void handle_control_transfer_attn(int epid, int status)
 {
-	urb_t *old_urb;
+	struct urb *old_urb;
 	etrax_urb_priv_t *hc_priv;	
 
 	DBFENTER;
@@ -1981,12 +1981,12 @@
 	DBFEXIT;
 }
 
-static int etrax_rh_submit_urb(urb_t *urb)
+static int etrax_rh_submit_urb(struct urb *urb)
 {
 	struct usb_device *usb_dev = urb->dev;
 	etrax_hc_t *hc = usb_dev->bus->hcpriv;
 	unsigned int pipe = urb->pipe;
-	devrequest *cmd = (devrequest *) urb->setup_packet;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	void *data = urb->transfer_buffer;
 	int leni = urb->transfer_buffer_length;
 	int len = 0;
@@ -2010,10 +2010,10 @@
 		return 0;
 	}
 
-	bmRType_bReq = cmd->requesttype | cmd->request << 8;
-	wValue = le16_to_cpu(cmd->value);
-	wIndex = le16_to_cpu(cmd->index);
-	wLength = le16_to_cpu(cmd->length);
+	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+	wValue = le16_to_cpu(cmd->wValue);
+	wIndex = le16_to_cpu(cmd->wIndex);
+	wLength = le16_to_cpu(cmd->wLength);
 
 	dbg_rh("bmRType_bReq : 0x%04X (%d)", bmRType_bReq, bmRType_bReq);
 	dbg_rh("wValue       : 0x%04X (%d)", wValue, wValue);
diff -urN linux-2.4.20-pre1/arch/cris/kernel/traps.c linux-2.4.20-pre2/arch/cris/kernel/traps.c
--- linux-2.4.20-pre1/arch/cris/kernel/traps.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.20-pre2/arch/cris/kernel/traps.c	Mon Aug 12 16:34:14 2002
@@ -230,8 +230,12 @@
 #endif	
 }
 
-/* This is normally the 'Oops' routine */
+void dump_stack(void)
+{
+	show_stack(NULL);
+}
 
+/* This is normally the 'Oops' routine */
 void 
 die_if_kernel(const char * str, struct pt_regs * regs, long err)
 {
diff -urN linux-2.4.20-pre1/arch/i386/boot/compressed/misc.c linux-2.4.20-pre2/arch/i386/boot/compressed/misc.c
--- linux-2.4.20-pre1/arch/i386/boot/compressed/misc.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/i386/boot/compressed/misc.c	Mon Aug 12 16:34:14 2002
@@ -9,6 +9,8 @@
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
 
+#define STANDALONE
+
 #include <linux/linkage.h>
 #include <linux/vmalloc.h>
 #include <linux/tty.h>
@@ -124,10 +126,6 @@
 static int vidport;
 static int lines, cols;
 
-#ifdef CONFIG_MULTIQUAD
-static void * const xquad_portio = NULL;
-#endif
-
 #include "../../../../lib/inflate.c"
 
 static void *malloc(int size)
diff -urN linux-2.4.20-pre1/arch/i386/config.in linux-2.4.20-pre2/arch/i386/config.in
--- linux-2.4.20-pre1/arch/i386/config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/arch/i386/config.in	Mon Aug 12 16:34:14 2002
@@ -53,6 +53,7 @@
    define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
    define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 else
    define_bool CONFIG_X86_WP_WORKS_OK y
    define_bool CONFIG_X86_INVLPG y
@@ -68,12 +69,14 @@
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586TSC" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -81,6 +84,7 @@
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586MMX" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -89,6 +93,7 @@
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M686" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -97,6 +102,7 @@
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_PPRO_FENCE y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -104,6 +110,7 @@
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MPENTIUM4" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 7
@@ -111,6 +118,7 @@
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MK6" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -125,11 +133,13 @@
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MELAN" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 4
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MCYRIXIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -141,12 +151,14 @@
 if [ "$CONFIG_MCRUSOE" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_TSC y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MWINCHIPC6" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_OOSTORE y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MWINCHIP2" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -154,6 +166,7 @@
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_OOSTORE y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MWINCHIP3D" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -161,6 +174,7 @@
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_OOSTORE y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 
 bool 'Machine Check Exception' CONFIG_X86_MCE
@@ -176,14 +190,19 @@
 	"off    CONFIG_NOHIGHMEM \
 	 4GB    CONFIG_HIGHMEM4G \
 	 64GB   CONFIG_HIGHMEM64G" off
-if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
+if [ "$CONFIG_HIGHMEM4G" = "y" -o "$CONFIG_HIGHMEM64G" = "y" ]; then
    define_bool CONFIG_HIGHMEM y
+else
+   define_bool CONFIG_HIGHMEM n
 fi
 if [ "$CONFIG_HIGHMEM64G" = "y" ]; then
-   define_bool CONFIG_HIGHMEM y
    define_bool CONFIG_X86_PAE y
 fi
 
+if [ "$CONFIG_HIGHMEM" = "y" ]; then
+   bool 'HIGHMEM I/O support' CONFIG_HIGHIO
+fi
+
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 bool 'Symmetric multi-processing support' CONFIG_SMP
@@ -200,8 +219,6 @@
    bool 'Multiquad NUMA system' CONFIG_MULTIQUAD
 fi
 
-bool 'ISA bus support' CONFIG_ISA
-
 if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
    define_bool CONFIG_HAVE_DEC_LOCK y
 fi
@@ -219,6 +236,7 @@
    define_bool CONFIG_X86_VISWS_APIC y
    define_bool CONFIG_X86_LOCAL_APIC y
    define_bool CONFIG_PCI y
+   define_bool CONFIG_ISA n
 else
    if [ "$CONFIG_SMP" = "y" ]; then
       define_bool CONFIG_X86_IO_APIC y
@@ -237,6 +255,7 @@
          define_bool CONFIG_PCI_DIRECT y
       fi
    fi
+   bool 'ISA bus support' CONFIG_ISA
 fi
 
 source drivers/pci/Config.in
@@ -368,14 +387,14 @@
 endmenu
 
 if [ "$CONFIG_ISA" = "y" ]; then
-mainmenu_option next_comment
-comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+    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
+    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
 fi
 
 #
@@ -420,6 +439,7 @@
 
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
 if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW
    bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
    bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
    bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
@@ -429,3 +449,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/i386/kernel/apic.c linux-2.4.20-pre2/arch/i386/kernel/apic.c
--- linux-2.4.20-pre1/arch/i386/kernel/apic.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/i386/kernel/apic.c	Mon Aug 12 16:34:14 2002
@@ -1050,7 +1050,7 @@
 /*
  * Local APIC timer interrupt. This is the most natural way for doing
  * local interrupts, but local timer interrupts can be emulated by
- * broadcast interrupts too. [in case the hw doesnt support APIC timers]
+ * broadcast interrupts too. [in case the hw doesn't support APIC timers]
  *
  * [ if a single-CPU system runs an SMP kernel then we call the local
  *   interrupt as well. Thus we cannot inline the local irq ... ]
@@ -1130,7 +1130,7 @@
 	   6: Received illegal vector
 	   7: Illegal register address
 	*/
-	printk (KERN_ERR "APIC error on CPU%d: %02lx(%02lx)\n",
+	printk (KERN_INFO "APIC error on CPU%d: %02lx(%02lx)\n",
 	        smp_processor_id(), v , v1);
 }
 
diff -urN linux-2.4.20-pre1/arch/i386/kernel/apm.c linux-2.4.20-pre2/arch/i386/kernel/apm.c
--- linux-2.4.20-pre1/arch/i386/kernel/apm.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/i386/kernel/apm.c	Mon Aug 12 16:34:14 2002
@@ -847,6 +847,7 @@
 			case 1: apm_idle_done = 1;
 				break;
 			default: /* BIOS refused */
+				break;
 			}
 		}
 		if (original_pm_idle)
@@ -862,14 +863,6 @@
 		apm_do_busy();
 }
 
-#ifdef CONFIG_SMP
-static int apm_magic(void * unused)
-{
-	while (1)
-		schedule();
-}
-#endif
-
 /**
  *	apm_power_off	-	ask the BIOS to power off
  *
@@ -897,10 +890,11 @@
 	 */
 #ifdef CONFIG_SMP
 	/* Some bioses don't like being called from CPU != 0 */
-	while (cpu_number_map(smp_processor_id()) != 0) {
-		kernel_thread(apm_magic, NULL,
-			CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+	if (cpu_number_map(smp_processor_id()) != 0) {
+		current->cpus_allowed = 1;
 		schedule();
+		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
+			BUG();
 	}
 #endif
 	if (apm_info.realmode_power_off)
@@ -1661,6 +1655,21 @@
 	strcpy(current->comm, "kapmd");
 	sigfillset(&current->blocked);
 
+#ifdef CONFIG_SMP
+	/* 2002/08/01 - WT
+	 * This is to avoid random crashes at boot time during initialization
+	 * on SMP systems in case of "apm=power-off" mode. Seen on ASUS A7M266D.
+	 * Some bioses don't like being called from CPU != 0.
+	 * Method suggested by Ingo Molnar.
+	 */
+	if (cpu_number_map(smp_processor_id()) != 0) {
+		current->cpus_allowed = 1;
+		schedule();
+		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
+			BUG();
+	}
+#endif
+	
 	if (apm_info.connection_version == 0) {
 		apm_info.connection_version = apm_info.bios.version;
 		if (apm_info.connection_version > 0x100) {
@@ -1707,7 +1716,7 @@
 		}
 	}
 
-	if (debug && (smp_num_cpus == 1)) {
+	if (debug) {
 		error = apm_get_power_status(&bx, &cx, &dx);
 		if (error)
 			printk(KERN_INFO "apm: power status not available\n");
diff -urN linux-2.4.20-pre1/arch/i386/kernel/dmi_scan.c linux-2.4.20-pre2/arch/i386/kernel/dmi_scan.c
--- linux-2.4.20-pre1/arch/i386/kernel/dmi_scan.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/i386/kernel/dmi_scan.c	Mon Aug 12 16:34:14 2002
@@ -190,7 +190,6 @@
  *	KT7 series. On these it seems the newer BIOS has fixed them. The
  *	rule needs to be improved to match specific BIOS revisions with
  *	corruption problems
- */ 
  
 static __init int disable_ide_dma(struct dmi_blacklist *d)
 {
@@ -204,6 +203,7 @@
 #endif	
 	return 0;
 }
+ */ 
 
 /* 
  * Reboot options and system auto-detection code provided by
diff -urN linux-2.4.20-pre1/arch/i386/kernel/io_apic.c linux-2.4.20-pre2/arch/i386/kernel/io_apic.c
--- linux-2.4.20-pre1/arch/i386/kernel/io_apic.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/i386/kernel/io_apic.c	Mon Aug 12 16:34:14 2002
@@ -716,7 +716,7 @@
 	entry.vector = vector;
 
 	/*
-	 * The timer IRQ doesnt have to know that behind the
+	 * The timer IRQ doesn't have to know that behind the
 	 * scene we have a 8259A-master in AEOI mode ...
 	 */
 	irq_desc[0].handler = &ioapic_edge_irq_type;
@@ -1586,7 +1586,7 @@
 	printk(" failed.\n");
 
 	if (nmi_watchdog) {
-		printk(KERN_WARNING "timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n");
+		printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
 		nmi_watchdog = 0;
 	}
 
diff -urN linux-2.4.20-pre1/arch/i386/kernel/irq.c linux-2.4.20-pre2/arch/i386/kernel/irq.c
--- linux-2.4.20-pre1/arch/i386/kernel/irq.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.20-pre2/arch/i386/kernel/irq.c	Mon Aug 12 16:34:14 2002
@@ -577,6 +577,20 @@
 	irq_desc_t *desc = irq_desc + irq;
 	struct irqaction * action;
 	unsigned int status;
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+	long esp;
+
+	/* Debugging check for stack overflow: is there less than 1KB free? */
+	__asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191));
+	if (unlikely(esp < (sizeof(struct task_struct) + 1024))) {
+		extern void show_stack(unsigned long *);
+
+		printk("do_IRQ: stack overflow: %ld\n",
+			esp - sizeof(struct task_struct));
+		__asm__ __volatile__("movl %%esp,%0" : "=r" (esp));
+		show_stack((void *)esp);
+	}
+#endif
 
 	kstat.irqs[cpu][irq]++;
 	spin_lock(&desc->lock);
diff -urN linux-2.4.20-pre1/arch/i386/kernel/mpparse.c linux-2.4.20-pre2/arch/i386/kernel/mpparse.c
--- linux-2.4.20-pre1/arch/i386/kernel/mpparse.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/arch/i386/kernel/mpparse.c	Mon Aug 12 16:34:14 2002
@@ -817,7 +817,7 @@
 
 /*
  * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesnt have a BIOS(-configuration table).
+ * sense, but it doesn't have a BIOS(-configuration table).
  * No problem for Linux.
  */
 void __init find_visws_smp(void)
diff -urN linux-2.4.20-pre1/arch/i386/kernel/setup.c linux-2.4.20-pre2/arch/i386/kernel/setup.c
--- linux-2.4.20-pre1/arch/i386/kernel/setup.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/arch/i386/kernel/setup.c	Mon Aug 12 16:34:14 2002
@@ -171,10 +171,14 @@
 extern int root_mountflags;
 extern char _text, _etext, _edata, _end;
 
+static int have_cpuid_p(void) __init;
+
 static int disable_x86_serial_nr __initdata = 1;
 static int disable_x86_fxsr __initdata = 0;
 static int disable_x86_ht __initdata = 0;
 
+extern int blk_nohighio;
+
 int enable_acpi_smp_table;
 
 #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
@@ -871,13 +875,17 @@
 void __init setup_arch(char **cmdline_p)
 {
 	unsigned long bootmap_size, low_mem_size;
-	unsigned long start_pfn, max_pfn, max_low_pfn;
+	unsigned long start_pfn, max_low_pfn;
 	int i;
 
 #ifdef CONFIG_VISWS
 	visws_get_board_type_and_rev();
 #endif
 
+#ifndef CONFIG_HIGHIO
+	blk_nohighio = 1;
+#endif
+
  	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
  	drive_info = DRIVE_INFO;
  	screen_info = SCREEN_INFO;
@@ -1206,6 +1214,14 @@
 __setup("notsc", tsc_setup);
 #endif
 
+static int __init highio_setup(char *str)
+{
+	printk("i386: disabling HIGHMEM block I/O\n");
+	blk_nohighio = 1;
+	return 1;
+}
+__setup("nohighio", highio_setup);
+
 static int __init get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
@@ -1534,7 +1550,7 @@
  * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
  * order to identify the Cyrix CPU model after we're out of setup.c
  *
- * Actually since bugs.h doesnt even reference this perhaps someone should
+ * Actually since bugs.h doesn't even reference this perhaps someone should
  * fix the documentation ???
  */
 static unsigned char Cx86_dir0_msb __initdata = 0;
@@ -2270,29 +2286,26 @@
 
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
-#ifndef CONFIG_M686
-	static int f00f_workaround_enabled = 0;
-#endif
-	char *p = NULL;
 	unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+	char *p = NULL;
+#ifndef CONFIG_X86_F00F_WORKS_OK
+	static int f00f_workaround_enabled = 0;
 
-#ifndef CONFIG_M686
 	/*
 	 * All current models of Pentium and Pentium with MMX technology CPUs
 	 * have the F0 0F bug, which lets nonpriviledged users lock up the system.
 	 * Note that the workaround only should be initialized once...
 	 */
 	c->f00f_bug = 0;
-	if ( c->x86 == 5 ) {
+	if (c->x86 == 5) {
 		c->f00f_bug = 1;
-		if ( !f00f_workaround_enabled ) {
+		if (!f00f_workaround_enabled) {
 			trap_init_f00f_bug();
 			printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
 			f00f_workaround_enabled = 1;
 		}
 	}
-#endif
-
+#endif /* CONFIG_X86_F00F_WORKS_OK */
 
 	if (c->cpuid_level > 1) {
 		/* supports eax=2  call */
@@ -2415,7 +2428,7 @@
 			if (smp_num_siblings != NR_SIBLINGS) {
 				printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
 				smp_num_siblings = 1;
-				goto too_many_siblings;
+				return;
 			}
 			tmp = smp_num_siblings;
 			while ((tmp & 1) == 0) {
@@ -2437,7 +2450,6 @@
 		}
 
 	}
-too_many_siblings:
 #endif
 }
 
diff -urN linux-2.4.20-pre1/arch/i386/kernel/smp.c linux-2.4.20-pre2/arch/i386/kernel/smp.c
--- linux-2.4.20-pre1/arch/i386/kernel/smp.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/i386/kernel/smp.c	Mon Aug 12 16:34:14 2002
@@ -66,7 +66,7 @@
  *	an L1cache=Writethrough or L1cache=off option.
  *
  *		B stepping CPUs may hang. There are hardware work arounds
- *	for this. We warn about it in case your board doesnt have the work
+ *	for this. We warn about it in case your board doesn't have the work
  *	arounds. Basically thats so I can tell anyone with a B stepping
  *	CPU and SMP problems "tough".
  *
diff -urN linux-2.4.20-pre1/arch/i386/kernel/traps.c linux-2.4.20-pre2/arch/i386/kernel/traps.c
--- linux-2.4.20-pre1/arch/i386/kernel/traps.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/i386/kernel/traps.c	Mon Aug 12 16:34:14 2002
@@ -40,9 +40,9 @@
 
 #include <asm/smp.h>
 #include <asm/pgalloc.h>
+#include <asm/fixmap.h>
 
 #ifdef CONFIG_X86_VISWS_APIC
-#include <asm/fixmap.h>
 #include <asm/cobalt.h>
 #include <asm/lithium.h>
 #endif
@@ -186,6 +186,14 @@
 	show_trace(esp);
 }
 
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+	show_stack(0);
+}
+
 void show_registers(struct pt_regs *regs)
 {
 	int i;
@@ -758,35 +766,17 @@
 
 #endif /* CONFIG_MATH_EMULATION */
 
-#ifndef CONFIG_M686
+#ifndef CONFIG_X86_F00F_WORKS_OK
 void __init trap_init_f00f_bug(void)
 {
-	unsigned long page;
-	pgd_t * pgd;
-	pmd_t * pmd;
-	pte_t * pte;
-
-	/*
-	 * Allocate a new page in virtual address space, 
-	 * move the IDT into it and write protect this page.
-	 */
-	page = (unsigned long) vmalloc(PAGE_SIZE);
-	pgd = pgd_offset(&init_mm, page);
-	pmd = pmd_offset(pgd, page);
-	pte = pte_offset(pmd, page);
-	__free_page(pte_page(*pte));
-	*pte = mk_pte_phys(__pa(&idt_table), PAGE_KERNEL_RO);
-	/*
-	 * Not that any PGE-capable kernel should have the f00f bug ...
-	 */
-	__flush_tlb_all();
-
 	/*
 	 * "idt" is magic - it overlaps the idt_descr
 	 * variable so that updating idt will automatically
 	 * update the idt descriptor..
 	 */
-	idt = (struct desc_struct *)page;
+	__set_fixmap(FIX_F00F, __pa(&idt_table), PAGE_KERNEL_RO);
+	idt = (struct desc_struct *)__fix_to_virt(FIX_F00F);
+
 	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
 }
 #endif
diff -urN linux-2.4.20-pre1/arch/ia64/config.in linux-2.4.20-pre2/arch/ia64/config.in
--- linux-2.4.20-pre1/arch/ia64/config.in	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/ia64/config.in	Mon Aug 12 16:34:14 2002
@@ -75,15 +75,15 @@
 
 if [ "$CONFIG_IA64_SGI_SN1" = "y" ] || [ "$CONFIG_IA64_SGI_SN2" = "y" ]; then
 	define_bool CONFIG_IA64_SGI_SN y
-	bool '  Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG n
+	bool '  Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG
 	bool '  Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN_SIM
 	bool '  Enable autotest (llsc). Option to run cache test instead of booting' \
-			CONFIG_IA64_SGI_AUTOTEST n
+			CONFIG_IA64_SGI_AUTOTEST
 	define_bool CONFIG_DEVFS_FS y
 	if [ "$CONFIG_DEVFS_FS" = "y" ]; then
-	  bool '    Enable DEVFS Debug Code' CONFIG_DEVFS_DEBUG n
+	  bool '    Enable DEVFS Debug Code' CONFIG_DEVFS_DEBUG
 	fi
-	bool '  Enable protocol mode for the L1 console' CONFIG_SERIAL_SGI_L1_PROTOCOL y
+	bool '  Enable protocol mode for the L1 console' CONFIG_SERIAL_SGI_L1_PROTOCOL
 	define_bool CONFIG_DISCONTIGMEM y
 	define_bool CONFIG_IA64_MCA y
 	define_bool CONFIG_NUMA y
@@ -195,7 +195,7 @@
 mainmenu_option next_comment
 comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
 
-bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
+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
@@ -239,6 +239,8 @@
 
 source drivers/usb/Config.in
 
+source lib/Config.in
+
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    source net/bluetooth/Config.in
 fi
diff -urN linux-2.4.20-pre1/arch/ia64/sn/fakeprom/README linux-2.4.20-pre2/arch/ia64/sn/fakeprom/README
--- linux-2.4.20-pre1/arch/ia64/sn/fakeprom/README	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-pre2/arch/ia64/sn/fakeprom/README	Mon Aug 12 16:34:14 2002
@@ -71,7 +71,7 @@
     1GB*<dn>, where dn is the digit number. The amount of memory
     is 8MB*2**<d>. (If <d> = 0, the memory size is 0).
 
-    SN1 doesnt support dimms this small but small memory systems 
+    SN1 doesn't support dimms this small but small memory systems 
     boot faster on Medusa.
 
 
diff -urN linux-2.4.20-pre1/arch/m68k/config.in linux-2.4.20-pre2/arch/m68k/config.in
--- linux-2.4.20-pre1/arch/m68k/config.in	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/m68k/config.in	Mon Aug 12 16:34:14 2002
@@ -141,7 +141,7 @@
    fi
    dep_tristate '  Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
    if [ "$CONFIG_PRINTER" != "n" ]; then
-      bool '    Support IEEE1284 status readback' CONFIG_PARPORT_1284
+      bool '    IEEE 1284 transfer modes' CONFIG_PARPORT_1284
    fi
 fi
 
@@ -539,7 +539,7 @@
 mainmenu_option next_comment
 comment 'Sound support'
 
-tristate 'Sound support' CONFIG_SOUND
+tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
    source drivers/sound/dmasound/Config.in
 fi
@@ -565,3 +565,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/mips/au1000/common/usbdev.c linux-2.4.20-pre2/arch/mips/au1000/common/usbdev.c
--- linux-2.4.20-pre1/arch/mips/au1000/common/usbdev.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/mips/au1000/common/usbdev.c	Mon Aug 12 16:34:14 2002
@@ -866,7 +866,7 @@
 
 // SETUP packet request parser
 static void
-process_setup (struct usb_serial* serial, devrequest* setup)
+process_setup (struct usb_serial* serial, struct usb_ctrlrequest* setup)
 {
 	int desc_len, strnum;
 
@@ -874,7 +874,7 @@
 
 	switch (setup->request) {
 	case USB_REQ_SET_ADDRESS:
-		serial->address = le16_to_cpu(setup->value);
+		serial->address = le16_to_cpu(setup->wValue);
 		dbg(__FUNCTION__ ": our address=%d", serial->address);
 		if (serial->address > 127 || serial->state == CONFIGURED) {
 			// usb spec doesn't tell us what to do, so just go to
@@ -887,8 +887,8 @@
 			serial->state = DEFAULT;
 		break;
 	case USB_REQ_GET_DESCRIPTOR:
-		desc_len = le16_to_cpu(setup->length);
-		switch (le16_to_cpu(setup->value) >> 8) {
+		desc_len = le16_to_cpu(setup->wLength);
+		switch (le16_to_cpu(setup->wValue) >> 8) {
 		case USB_DT_DEVICE:
 			// send device descriptor!
 			desc_len = desc_len > serial->dev_desc->bLength ?
@@ -901,7 +901,7 @@
 			// If the config descr index in low-byte of
 			// setup->value	is valid, send config descr,
 			// otherwise stall ep0.
-			if ((le16_to_cpu(setup->value) & 0xff) == 0) {
+			if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
 				// send config descriptor!
 				if (desc_len <= USB_DT_CONFIG_SIZE) {
 					dbg("sending partial config desc, size=%d",
@@ -943,7 +943,7 @@
 		case USB_DT_STRING:
 			// If the string descr index in low-byte of setup->value
 			// is valid, send string descr, otherwise stall ep0.
-			strnum = le16_to_cpu(setup->value) & 0xff;
+			strnum = le16_to_cpu(setup->wValue) & 0xff;
 			if (strnum >= 0 && strnum < 6) {
 				struct usb_string_descriptor *desc =
 				    serial->str_desc[strnum];
@@ -957,7 +957,7 @@
 			break;
 		default:	// Invalid request
 			dbg("invalid get desc=%d, stalled",
-			    le16_to_cpu(setup->value) >> 8);
+			    le16_to_cpu(setup->wValue) >> 8);
 			endpoint_stall(&serial->ep_ctrl);	// Stall endpoint 0
 			break;
 		}
@@ -967,7 +967,7 @@
 		break;
 	case USB_REQ_GET_INTERFACE:
 		// interface must be zero.
-		if ((le16_to_cpu(setup->index) & 0xff) ||
+		if ((le16_to_cpu(setup->wIndex) & 0xff) ||
 		    serial->state == ADDRESS) {
 			// FIXME: respond with "request error". how?
 		} else if (serial->state == CONFIGURED) {
@@ -981,9 +981,9 @@
 		if (serial->state == ADDRESS) {
 			// FIXME: respond with "request error". how?
 		} else if (serial->state == CONFIGURED) {
-			serial->interface = le16_to_cpu(setup->index) & 0xff;
+			serial->interface = le16_to_cpu(setup->wIndex) & 0xff;
 			serial->alternate_setting =
-			    le16_to_cpu(setup->value) & 0xff;
+			    le16_to_cpu(setup->wValue) & 0xff;
 			// interface and alternate_setting must be zero
 			if (serial->interface || serial->alternate_setting) {
 				// FIXME: respond with "request error". how?
@@ -992,7 +992,7 @@
 		break;
 	case USB_REQ_SET_CONFIGURATION:
 		// set active config to low-byte of serial.value
-		serial->configuration = le16_to_cpu(setup->value) & 0xff;
+		serial->configuration = le16_to_cpu(setup->wValue) & 0xff;
 		dbg("set config, config=%d", serial->configuration);
 		if (!serial->configuration && serial->state > DEFAULT)
 			serial->state = ADDRESS;
@@ -1009,7 +1009,7 @@
 		break;
 	case USB_REQ_GET_STATUS:
 		// FIXME: looks like the h/w handles this one
-		switch (setup->requesttype) {
+		switch (setup->bRequestType) {
 		case 0x80:	// Device
 			// FIXME: send device status
 			break;
@@ -1027,16 +1027,16 @@
 	case USB_REQ_CLEAR_FEATURE:
 		switch (setup->requesttype) {
 		case 0x00:	// Device
-			if ((le16_to_cpu(setup->value) & 0xff) == 1)
+			if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
 				serial->remote_wakeup_en = 0;
 			else
 				endpoint_stall(&serial->ep_ctrl);
 			break;
 		case 0x02:	// End Point
-			if ((le16_to_cpu(setup->value) & 0xff) == 0) {
+			if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
 				endpoint_t *ep =
 				    epnum_to_ep(serial,
-						    le16_to_cpu(setup->index) & 0xff);
+						    le16_to_cpu(setup->wIndex) & 0xff);
 
 				endpoint_unstall(ep);
 				endpoint_reset_datatoggle(ep);
@@ -1046,18 +1046,18 @@
 		}
 		break;
 	case USB_REQ_SET_FEATURE:
-		switch (setup->requesttype) {
+		switch (setup->bRequestType) {
 		case 0x00:	// Device
-			if ((le16_to_cpu(setup->value) & 0xff) == 1)
+			if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
 				serial->remote_wakeup_en = 1;
 			else
 				endpoint_stall(&serial->ep_ctrl);
 			break;
 		case 0x02:	// End Point
-			if ((le16_to_cpu(setup->value) & 0xff) == 0) {
+			if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
 				endpoint_t *ep =
 				    epnum_to_ep(serial,
-						    le16_to_cpu(setup->index) & 0xff);
+						    le16_to_cpu(setup->wIndex) & 0xff);
 
 				endpoint_stall(ep);
 			} else
@@ -1100,14 +1100,14 @@
 	
 		// SETUP packet received ?
 		//if (cs & USBDEV_CS_SU) { FIXME: uncomment!
-			if (pkt->size == sizeof(devrequest)) {
-				devrequest setup;
+			if (pkt->size == sizeof(struct usb_ctrlrequest)) {
+				struct usb_ctrlrequest setup;
 			if ((cs & (USBDEV_CS_NAK | USBDEV_CS_ACK)) ==
 			    USBDEV_CS_ACK)
 					dbg("got SETUP");
 				else
 					dbg("got NAK SETUP, cs=%08x", cs);
-			memcpy(&setup, pkt->bufptr, sizeof(devrequest));
+			memcpy(&setup, pkt->bufptr, sizeof(struct usb_ctrlrequest));
 				process_setup(serial, &setup);
 			//} else  FIXME: uncomment!
 			//dbg(__FUNCTION__ ": wrong size SETUP received");
diff -urN linux-2.4.20-pre1/arch/mips/config.in linux-2.4.20-pre2/arch/mips/config.in
--- linux-2.4.20-pre1/arch/mips/config.in	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/mips/config.in	Mon Aug 12 16:34:14 2002
@@ -632,3 +632,5 @@
    bool 'Run uncached' CONFIG_MIPS_UNCACHED
 fi
 endmenu
+
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/mips/dec/wbflush.c linux-2.4.20-pre2/arch/mips/dec/wbflush.c
--- linux-2.4.20-pre1/arch/mips/dec/wbflush.c	Fri Oct  5 12:06:51 2001
+++ linux-2.4.20-pre2/arch/mips/dec/wbflush.c	Mon Aug 12 16:34:14 2002
@@ -97,7 +97,7 @@
 }
 
 /*
- * The DS500/2x0 doesnt need to write back the WB.
+ * The DS500/2x0 doesn't need to write back the WB.
  */
 static void wbflush_kn03(void)
 {
diff -urN linux-2.4.20-pre1/arch/mips64/config.in linux-2.4.20-pre2/arch/mips64/config.in
--- linux-2.4.20-pre1/arch/mips64/config.in	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/mips64/config.in	Mon Aug 12 16:34:14 2002
@@ -336,3 +336,5 @@
    bool 'Run uncached' CONFIG_MIPS_UNCACHED
 fi
 endmenu
+
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/mips64/kernel/irq.c linux-2.4.20-pre2/arch/mips64/kernel/irq.c
--- linux-2.4.20-pre1/arch/mips64/kernel/irq.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/mips64/kernel/irq.c	Mon Aug 12 16:34:14 2002
@@ -48,7 +48,7 @@
 {
 	/*
 	 * 'what should we do if we get a hw irq event on an illegal vector'.
-	 * each architecture has to answer this themselves, it doesnt deserve
+	 * each architecture has to answer this themselves, it doesn't deserve
 	 * a generic callback i think.
 	 */
 	printk("unexpected interrupt %d\n", irq);
diff -urN linux-2.4.20-pre1/arch/mips64/math-emu/ieee754.c linux-2.4.20-pre2/arch/mips64/math-emu/ieee754.c
--- linux-2.4.20-pre1/arch/mips64/math-emu/ieee754.c	Mon Jul  2 13:56:41 2001
+++ linux-2.4.20-pre2/arch/mips64/math-emu/ieee754.c	Mon Aug 12 16:34:14 2002
@@ -3,7 +3,7 @@
  *
  * BUGS
  * not much dp done
- * doesnt generate IEEE754_INEXACT
+ * doesn't generate IEEE754_INEXACT
  *
  */
 /*
diff -urN linux-2.4.20-pre1/arch/parisc/Makefile linux-2.4.20-pre2/arch/parisc/Makefile
--- linux-2.4.20-pre1/arch/parisc/Makefile	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/Makefile	Mon Aug 12 16:34:14 2002
@@ -17,12 +17,28 @@
 # Mike Shaver, Helge Deller and Martin K. Petersen
 #
 
+ifdef CONFIG_PARISC64
+LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux64.lds $(LDFLAGS)
+CROSS_COMPILE := hppa64-linux-
+UTS_MACHINE := parisc64
+#CFLAGS += -b hppa64-linux
+
+else
+LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux.lds $(LDFLAGS)
+MACHINE	:= $(subst 64,,$(shell uname -m))
+ifneq (${MACHINE},parisc)
+# cross compilation
+CROSS_COMPILE := hppa-linux-
+endif
+endif
+
+OFFSET_H := $(TOPDIR)/include/asm-parisc/offset.h
 FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align 
 
 CPP=$(CC) -E
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 LDFLAGS =
-LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux.lds $(LDFLAGS)
+
 
 CFLAGS_PIPE := -pipe
 CFLAGS_NSR  := -fno-strength-reduce
@@ -32,25 +48,48 @@
 # enable them by default.
 CFLAGS += -mno-space-regs -mfast-indirect-calls
 
-# If we become able to compile for specific platforms, this should be
-# conditional on that.
-CFLAGS += -mschedule=7200
-
 # No fixed-point multiply
 CFLAGS += -mdisable-fpregs
 
-HEAD = arch/parisc/kernel/head.o 
+# Without this, "ld -r" results in .text sections that are too big
+# (> 0x40000) for branches to reach stubs.
+CFLAGS += -ffunction-sections
+
+# select which processor to optimise for
+ifdef CONFIG_PA7100
+CFLAGS += -march=1.1 -mschedule=7100
+endif
+
+ifdef CONFIG_PA7200
+CFLAGS += -march=1.1 -mschedule=7200
+endif
+
+ifdef CONFIG_PA7100LC
+CFLAGS += -march=1.1 -mschedule=7100LC
+endif
+
+ifdef CONFIG_PA8X00
+CFLAGS += -march=2.0 -mschedule=8000
+endif
+
+ASFLAGS := -D__ASSEMBLY__ -traditional
+
+HEAD := arch/parisc/kernel/head.o 
 
 SUBDIRS := $(SUBDIRS) $(addprefix arch/parisc/, tools kernel mm lib hpux)
 CORE_FILES :=  $(addprefix arch/parisc/, kernel/pdc_cons.o kernel/process.o \
 	lib/lib.a mm/mm.o kernel/kernel.o hpux/hpux.o) \
 	$(CORE_FILES) arch/parisc/kernel/init_task.o
+CLEAN_FILES := $(CLEAN_FILES) arch/parisc/tools/offset.[hs] 
+
+ifdef CONFIG_PARISC64
+HEAD := arch/parisc/kernel/head64.o
+endif
+
 LIBS := `$(CC) -print-libgcc-file-name` $(TOPDIR)/arch/parisc/lib/lib.a $(LIBS) 
 
-ifdef CONFIG_MATH_EMULATION
 SUBDIRS := $(SUBDIRS) arch/parisc/math-emu
-DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.a
-endif
+DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.o
 
 ifdef CONFIG_KWDB
 SUBDIRS := $(SUBDIRS) arch/parisc/kdb
@@ -67,7 +106,7 @@
 	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/mm
 
 palo: vmlinux
-	export TOPDIR=`pwd`; export CONFIG_STI_CONSOLE=$(CONFIG_STI_CONSOLE); \
+	export TOPDIR=`pwd`; \
 	unset STRIP LDFLAGS CPP CPPFLAGS AFLAGS CFLAGS CC LD; cd ../palo && make lifimage
 
 Image: palo
@@ -84,8 +123,14 @@
 
 install: 
 
+archmrproper:
+	rm -f $(OFFSET_H)
+
 archclean:
 
-archmrproper:
+archdep: $(OFFSET_H)
+
+$(OFFSET_H): include/linux/version.h
+	$(MAKE) -C $(TOPDIR)/arch/$(ARCH)/tools all
 
-archdep:
+.PHONY: $(OFFSET_H)
diff -urN linux-2.4.20-pre1/arch/parisc/config.in linux-2.4.20-pre2/arch/parisc/config.in
--- linux-2.4.20-pre1/arch/parisc/config.in	Tue Apr 17 17:19:25 2001
+++ linux-2.4.20-pre2/arch/parisc/config.in	Mon Aug 12 16:34:14 2002
@@ -52,7 +52,7 @@
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
-  bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+  bool 'Set version information on all module symbols' CONFIG_MODVERSIONS
   bool 'Kernel module loader' CONFIG_KMOD
 fi
 endmenu
@@ -208,3 +208,4 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/parisc/defconfig linux-2.4.20-pre2/arch/parisc/defconfig
--- linux-2.4.20-pre1/arch/parisc/defconfig	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/defconfig	Mon Aug 12 16:34:14 2002
@@ -1,8 +1,10 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 CONFIG_PARISC=y
 # CONFIG_UID16 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 
 #
 # Code maturity level options
@@ -10,44 +12,70 @@
 CONFIG_EXPERIMENTAL=y
 
 #
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor type
+#
+# CONFIG_PA7100 is not set
+# CONFIG_PA7200 is not set
+# CONFIG_PA7100LC is not set
+# CONFIG_PA8X00 is not set
+# CONFIG_PA11 is not set
+
+#
 # General options
 #
 # CONFIG_SMP is not set
+CONFIG_CHASSIS_LCD_LED=y
 # CONFIG_KWDB is not set
-CONFIG_GSC=y
 CONFIG_IOMMU_CCIO=y
+CONFIG_GSC=y
 CONFIG_GSC_LASI=y
+CONFIG_GSC_WAX=y
+CONFIG_EISA=y
+CONFIG_ISA=y
 CONFIG_PCI=y
 CONFIG_GSC_DINO=y
 CONFIG_PCI_LBA=y
 CONFIG_IOSAPIC=y
 CONFIG_IOMMU_SBA=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
+CONFIG_SUPERIO=y
+CONFIG_PCI_NAMES=y
 
 #
 # General setup
 #
+CONFIG_HOTPLUG=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_BINFMT_SOM=y
+CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_SOM=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PM is not set
 
 #
 # Parallel port support
 #
 CONFIG_PARPORT=y
-# CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_CML1=y
+# CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_PC_PCMCIA is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
 CONFIG_PARPORT_GSC=y
+# CONFIG_PARPORT_SUNBPP is not set
 # CONFIG_PARPORT_OTHER is not set
 # CONFIG_PARPORT_1284 is not set
 
@@ -60,33 +88,54 @@
 # 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_LOOP=y
 # 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=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID5=y
+# 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_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
+CONFIG_FILTER=y
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+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=y
 # 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_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
@@ -106,36 +155,181 @@
 # 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=y
+# 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_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 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=y
+# CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=y
 # 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_LASI=y
-CONFIG_SCSI_ZALON=y
+# 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_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_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_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_LASI700=y
+CONFIG_53C700_MEM_MAPPED=y
+CONFIG_53C700_LE_ON_BE=y
+CONFIG_53C700_USE_CONSISTENT=y
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
 CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_ZALON=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
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_SCSI_PCMCIA is not set
 
 #
 # Network device support
 #
 CONFIG_NETDEVICES=y
-CONFIG_LASI_82596=y
 
 #
 # ARCnet devices
@@ -145,12 +339,18 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_NET_SB1000 is not set
+# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+CONFIG_LASI_82596=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE 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
@@ -165,23 +365,31 @@
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_DE4X5 is not set
 CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO 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_RTL8129 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_8139_NEW_RX_RESET 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_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_NET_POCKET is not set
 
@@ -189,6 +397,9 @@
 # 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
@@ -217,12 +428,27 @@
 # CONFIG_WAN is not set
 
 #
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA 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=y
+
+#
 # Character devices
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_GSC_PS2=y
-CONFIG_HIL=y
 CONFIG_SERIAL=y
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_SERIAL_GSC=y
@@ -243,12 +469,45 @@
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE 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=y
+# CONFIG_INPUT_SERPORT is not set
 
 #
 # Joysticks
 #
-# CONFIG_JOYSTICK 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
 
 #
@@ -271,27 +530,67 @@
 # CONFIG_DRM is not set
 
 #
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+
+#
+# HIL support
+#
+CONFIG_HIL=y
+# CONFIG_HIL_KBD_BASIC is not set
+
+#
+#  HIL driver core support
+#
+CONFIG_HP_SDC=y
+# CONFIG_HP_SDC_RTC is not set
+CONFIG_HIL_MLC=y
+CONFIG_HP_SDC_MLC=y
+
+#
+#  HIL device driver
+#
+CONFIG_HIL_KBD=y
+CONFIG_HIL_PTR=y
+
+#
+# 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=y
+CONFIG_JBD=y
+# 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=y
-# CONFIG_JOLIET is not set
+CONFIG_JOLIET=y
+# 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
@@ -299,13 +598,12 @@
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_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
@@ -315,13 +613,15 @@
 # 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_NFS_V3=y
 CONFIG_ROOT_NFS=y
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
+CONFIG_NFSD=y
+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
@@ -330,22 +630,60 @@
 # CONFIG_NCPFS_NFS_NS is not set
 # CONFIG_NCPFS_OS2_NS is not set
 # CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS 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_NLS is not set
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
 
 #
-# Sound Drivers
+# Native Language Support
 #
-# CONFIG_SOUND is not set
+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
 
 #
 # Console drivers
@@ -354,8 +692,171 @@
 #
 # Frame-buffer support
 #
-# CONFIG_FB is not set
-# CONFIG_STI_CONSOLE is not set
+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_STI=y
+# CONFIG_FB_MATROX 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_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB32=y
+CONFIG_FBCON_STI=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_STI_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FBCON=y
+CONFIG_FBCON_FONT=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_6x11=y
+CONFIG_FONT_SUN12x22=y
+
+#
+# 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_HARMONY=y
+# 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_OSS is not set
+# CONFIG_SOUND_TVMIXER 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
+#
+
+#
+#   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 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_IPAQ 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_KLSI 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
diff -urN linux-2.4.20-pre1/arch/parisc/hpux/Makefile linux-2.4.20-pre2/arch/parisc/hpux/Makefile
--- linux-2.4.20-pre1/arch/parisc/hpux/Makefile	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/hpux/Makefile	Mon Aug 12 16:34:14 2002
@@ -7,10 +7,7 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-all: hpux.o
 O_TARGET = hpux.o
-O_OBJS = entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o
-
-.o.S:	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
+obj-y := entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/arch/parisc/hpux/entry_hpux.S linux-2.4.20-pre2/arch/parisc/hpux/entry_hpux.S
--- linux-2.4.20-pre1/arch/parisc/hpux/entry_hpux.S	Fri Oct  5 12:22:07 2001
+++ linux-2.4.20-pre2/arch/parisc/hpux/entry_hpux.S	Mon Aug 12 16:34:14 2002
@@ -1,6 +1,6 @@
-/* -----------------------------------------------------------------------------
+/*
  *
- * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+ * Linux/PARISC Project (http://www.parisc-linux.org/)
  *
  * modified by Matthew Wilcox <willy@bofh.ai> 1999-07-26
  */
@@ -10,13 +10,13 @@
 #include <linux/linkage.h>
 #include <asm/unistd.h>
 
-
 	.text
 
 #define ENTRY_NAME(_name_) .word _name_
 
 	.align 4
 	.export hpux_call_table
+	.import hpux_unimplemented_wrapper
 hpux_call_table:
 	ENTRY_NAME(sys_ni_syscall)	/* 0 */
 	ENTRY_NAME(sys_exit)
@@ -36,7 +36,7 @@
 	ENTRY_NAME(sys_chmod)	/* 15 */
 	ENTRY_NAME(sys_chown)
 	ENTRY_NAME(hpux_brk)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_lseek)
 	ENTRY_NAME(sys_getpid)	/* 20 */
 	ENTRY_NAME(hpux_mount)
@@ -46,34 +46,34 @@
 	ENTRY_NAME(sys_stime)	/* 25 */
 	ENTRY_NAME(hpux_ptrace)
 	ENTRY_NAME(sys_alarm)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_pause)
 	ENTRY_NAME(sys_utime)	/* 30 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_access)
 	ENTRY_NAME(hpux_nice)
-	ENTRY_NAME(sys_ni_syscall)	/* 35 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 35 */
 	ENTRY_NAME(sys_sync)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_newstat)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_setpgrp3)
 	ENTRY_NAME(sys_newlstat)	/* 40 */
 	ENTRY_NAME(sys_dup)
 	ENTRY_NAME(hpux_pipe_wrapper)
 	ENTRY_NAME(sys_times)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 45 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 45 */
 	ENTRY_NAME(sys_setgid)
 	ENTRY_NAME(sys_getgid)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 50 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 50 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_ioctl)
-	ENTRY_NAME(sys_ni_syscall)	/* 55 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 55 */
 	ENTRY_NAME(sys_symlink)
 	ENTRY_NAME(hpux_utssys)
 	ENTRY_NAME(sys_readlink)
@@ -81,218 +81,218 @@
 	ENTRY_NAME(sys_umask)	/* 60 */
 	ENTRY_NAME(sys_chroot)
 	ENTRY_NAME(sys_fcntl)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 65 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 65 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_sbrk)
-	ENTRY_NAME(sys_ni_syscall)	/* 70 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 70 */
 	ENTRY_NAME(sys_mmap)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 75 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 80 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 75 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 80 */
 	ENTRY_NAME(sys_getpgid)
 	ENTRY_NAME(sys_setpgid)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 85 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(sys_setitimer)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 85 */
+	ENTRY_NAME(sys_getitimer)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_dup2)		/* 90 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_newfstat)
 	ENTRY_NAME(sys_select)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 95 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 100 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 105 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 110 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 115 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 95 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 100 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 105 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 110 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 115 */
 	ENTRY_NAME(sys_gettimeofday)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 120 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 120 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_fchown)
 	ENTRY_NAME(sys_fchmod)
-	ENTRY_NAME(sys_ni_syscall)	/* 125 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 125 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_rename)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 130 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 130 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_sysconf)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 135 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 135 */
 	ENTRY_NAME(sys_mkdir)
 	ENTRY_NAME(sys_rmdir)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 140 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 145 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 150 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 155 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 160 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 165 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 170 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 175 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 180 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 185 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 190 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 140 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(sys_getrlimit)
+	ENTRY_NAME(sys_setrlimit)      /* 145 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 150 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_lockf)      /* 155 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 160 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 165 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 170 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 175 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 180 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(sys_sigprocmask)      /* 185 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 190 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_getdomainname)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 195 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 195 */
+	ENTRY_NAME(hpux_statfs)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_waitpid)	/* 200 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 205 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 210 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 215 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 220 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 225 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 230 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 235 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 240 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 245 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 250 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 255 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 260 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 265 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 270 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 205 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 210 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 215 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 220 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 225 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 230 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 235 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 240 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 245 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 250 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 255 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 260 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 265 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 270 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_fchdir)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_accept)		/* 275 */
 	ENTRY_NAME(sys_bind)
 	ENTRY_NAME(sys_connect)
@@ -309,227 +309,227 @@
 	ENTRY_NAME(sys_setsockopt)
 	ENTRY_NAME(sys_shutdown)
 	ENTRY_NAME(sys_socket)		/* 290 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 295 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 300 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 305 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 310 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 315 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 320 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 325 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 330 */
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 295 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 300 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 305 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 310 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 315 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 320 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 325 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 330 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_lchown)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 335 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 340 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 345 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 350 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_sysfs)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 335 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 340 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 345 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 350 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(sys_nanosleep)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 355 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 355 */
 	ENTRY_NAME(hpux_getdents)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 360 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 360 */
 	ENTRY_NAME(hpux_fstat64)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 365 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 365 */
 	ENTRY_NAME(hpux_lstat64)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 	ENTRY_NAME(hpux_stat64)
-	ENTRY_NAME(sys_ni_syscall)	/* 370 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 375 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 380 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 385 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 390 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 395 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 400 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 405 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 410 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 415 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 420 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 425 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 430 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 435 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 440 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 445 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 450 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 455 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 460 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 465 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 470 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 475 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 480 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 485 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 490 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 495 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 500 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 505 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)	/* 510 */
-	ENTRY_NAME(sys_ni_syscall)
-	ENTRY_NAME(sys_ni_syscall)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 370 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 375 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 380 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_setpgrp)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 385 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 390 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 395 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 400 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 405 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 410 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 415 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 420 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 425 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 430 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 435 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 440 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 445 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 450 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 455 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 460 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 465 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 470 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 475 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 480 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 485 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 490 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 495 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 500 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 505 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)      /* 510 */
+	ENTRY_NAME(hpux_unimplemented_wrapper)
+	ENTRY_NAME(hpux_unimplemented_wrapper)
 .end
 
diff -urN linux-2.4.20-pre1/arch/parisc/hpux/fs.c linux-2.4.20-pre2/arch/parisc/hpux/fs.c
--- linux-2.4.20-pre1/arch/parisc/hpux/fs.c	Sun Aug 12 15:07:55 2001
+++ linux-2.4.20-pre2/arch/parisc/hpux/fs.c	Mon Aug 12 16:34:14 2002
@@ -52,7 +52,8 @@
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
 
-static int filldir(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino)
+static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
+		ino_t ino, unsigned int d_type)
 {
 	struct hpux_dirent * dirent;
 	struct getdents_callback * buf = (struct getdents_callback *) __buf;
@@ -83,42 +84,21 @@
 int hpux_getdents(unsigned int fd, struct hpux_dirent *dirent, unsigned int count)
 {
 	struct file * file;
-	struct dentry * dentry;
-	struct inode * inode;
 	struct hpux_dirent * lastdirent;
 	struct getdents_callback buf;
 	int error;
 
-	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
 		goto out;
 
-	dentry = file->f_dentry;
-	if (!dentry)
-		goto out_putf;
-
-	inode = dentry->d_inode;
-	if (!inode)
-		goto out_putf;
-
 	buf.current_dir = dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out_putf;
-
-	/*
-	 * Get the inode's semaphore to prevent changes
-	 * to the directory while we read it.
-	 */
-	down(&inode->i_sem);
-	error = file->f_op->readdir(file, &buf, filldir);
-	up(&inode->i_sem);
+	error = vfs_readdir(file, filldir, &buf);
 	if (error < 0)
 		goto out_putf;
 	error = buf.error;
@@ -131,7 +111,6 @@
 out_putf:
 	fput(file);
 out:
-	unlock_kernel();
 	return error;
 }
 
diff -urN linux-2.4.20-pre1/arch/parisc/hpux/gate.S linux-2.4.20-pre2/arch/parisc/hpux/gate.S
--- linux-2.4.20-pre1/arch/parisc/hpux/gate.S	Wed Dec  6 11:46:39 2000
+++ linux-2.4.20-pre2/arch/parisc/hpux/gate.S	Mon Aug 12 16:34:14 2002
@@ -1,6 +1,6 @@
-/* ------------------------------------------------------------------------------
+/*
  *
- * Linux/PARISC Project (http://www.thepuffingroup.com/parisc)
+ * Linux/PARISC Project (http://www.parisc-linux.org/)
  *
  * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>
  * Licensed under the GNU GPL.
@@ -8,14 +8,23 @@
  * sorry about the wall, puffin..
  */
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/offset.h>
 #include <asm/unistd.h>
 #include <asm/errno.h>
 
+#ifdef __LP64__
+	.level          2.0w
+#else
+	.level		1.1
+#endif
 	.text
 
+#ifdef __LP64__
+#define FRAME_SIZE	128
+#else
+#define FRAME_SIZE	64
+#endif
 	.import hpux_call_table
 	.import hpux_syscall_exit,code
 	.export hpux_gateway_page
@@ -23,35 +32,70 @@
 	.align 4096
 hpux_gateway_page:
 	nop
-	mfsp	%sr7,%r1			;! we must set sr3 to the space
-	mtsp	%r1,%sr3			;! of the user before the gate
 #ifdef __LP64__
 #warning NEEDS WORK for 64-bit
 #endif
-	ldw	-64(%r30), %r28			;! 8th argument
+	ldw     -64(%r30), %r29                 ;! 8th argument
 	ldw	-60(%r30), %r19			;! 7th argument
 	ldw	-56(%r30), %r20			;! 6th argument
 	ldw	-52(%r30), %r21			;! 5th argument
-	gate	.+8, %r0			;! become privileged
-	mtsp	%r0,%sr4			;! get kernel space into sr4
-	mtsp	%r0,%sr5			;! get kernel space into sr5
-	mtsp	%r0,%sr6			;! get kernel space into sr6
-	mtsp	%r0,%sr7			;! get kernel space into sr7
-	mfctl	%cr30,%r1			;! get the kernel task ptr
-	mtctl	%r0,%cr30			;! zero it (flag)
-	STREG	%r30,TASK_PT_GR30(%r1)		;! preserve userspace sp
-	STREG	%r2,TASK_PT_GR2(%r1)		;! preserve rp
-	STREG	%r27,TASK_PT_GR27(%r1)		;! user dp
-	STREG	%r31,TASK_PT_GR31(%r1)		;! preserve syscall return ptr
+	gate	.+8, %r0			/* become privileged */
+	mtsp	%r0,%sr4			/* get kernel space into sr4 */
+	mtsp	%r0,%sr5			/* get kernel space into sr5 */
+	mtsp	%r0,%sr6			/* get kernel space into sr6 */
+	mfsp    %sr7,%r1                        /* save user sr7 */
+	mtsp    %r1,%sr3                        /* and store it in sr3 */
+
+	mtctl   %r30,%cr28
+	mfctl   %cr30,%r1
+	xor     %r1,%r30,%r30                   /* ye olde xor trick */
+	xor     %r1,%r30,%r1
+	xor     %r1,%r30,%r30
+	ldo     TASK_SZ_ALGN+FRAME_SIZE(%r30),%r30  /* set up kernel stack */
+
+	/* N.B.: It is critical that we don't set sr7 to 0 until r30
+	 *       contains a valid kernel stack pointer. It is also
+	 *       critical that we don't start using the kernel stack
+	 *       until after sr7 has been set to 0.
+	 */
+
+	mtsp	%r0,%sr7			/* get kernel space into sr7 */
+	STREG   %r1,TASK_PT_GR30-TASK_SZ_ALGN-FRAME_SIZE(%r30) /* save usp */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1   /* get task ptr in %r1 */
+
+	/* Save some registers for sigcontext and potential task
+	   switch (see entry.S for the details of which ones are
+	   saved/restored).  TASK_PT_PSW is zeroed so we can see whether
+	   a process is on a syscall or not.  For an interrupt the real
+	   PSW value is stored.  This is needed for gdb and sys_ptrace. */
+	STREG	%r0,  TASK_PT_PSW(%r1)
+	STREG	%r2,  TASK_PT_GR2(%r1)		/* preserve rp */
+	STREG   %r19, TASK_PT_GR19(%r1)         /* 7th argument */
+	STREG   %r20, TASK_PT_GR20(%r1)         /* 6th argument */
+	STREG   %r21, TASK_PT_GR21(%r1)         /* 5th argument */
+	STREG   %r22, TASK_PT_GR22(%r1)         /* syscall # */
+	STREG	%r23, TASK_PT_GR23(%r1)		/* 4th argument */
+	STREG	%r24, TASK_PT_GR24(%r1)		/* 3rd argument */
+	STREG	%r25, TASK_PT_GR25(%r1)		/* 2nd argument */
+	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */
+	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */
+	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
+	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
+	STREG   %r29, TASK_PT_GR29(%r1)         /* 8th argument */
+	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */
+	
+	ldo	TASK_PT_FR0(%r1), %r27		/* save fpregs from the kernel */
+	save_fp	%r27				/* or potential task switch  */
 
-	loadgp					;! setup kernel dp
+	mfctl	%cr11, %r27			/* i.e. SAR */
+	STREG	%r27, TASK_PT_SAR(%r1)
 
-	ldo	TASK_SZ_ALGN+64(%r1),%r30	;! set up kernel stack
+	loadgp
 
 	stw	%r21, -52(%r30)			;! 5th argument
 	stw	%r20, -56(%r30)			;! 6th argument
 	stw	%r19, -60(%r30)			;! 7th argument
-	stw	%r28, -64(%r30)			;! 8th argument
+	stw     %r29, -64(%r30)                 ;! 8th argument
 
 	ldil	L%hpux_call_table, %r21
 	ldo	R%hpux_call_table(%r21), %r21
diff -urN linux-2.4.20-pre1/arch/parisc/hpux/ioctl.c linux-2.4.20-pre2/arch/parisc/hpux/ioctl.c
--- linux-2.4.20-pre1/arch/parisc/hpux/ioctl.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/hpux/ioctl.c	Mon Aug 12 16:34:14 2002
@@ -19,6 +19,7 @@
  *   TIOCSPGRP
  */
 
+#include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <asm/errno.h>
 #include <asm/ioctl.h>
@@ -54,10 +55,6 @@
 	case 't':
 		result = hpux_ioctl_t(fd, cmd, arg);
 		break;
-	default:
-		/* If my mother ever sees this, I hope she disowns me.
-		 * Take this out after NYLWE. */
-		result = sys_ioctl(fd, cmd, arg);
 	}
 	return result;
 }
diff -urN linux-2.4.20-pre1/arch/parisc/hpux/sys_hpux.c linux-2.4.20-pre2/arch/parisc/hpux/sys_hpux.c
--- linux-2.4.20-pre1/arch/parisc/hpux/sys_hpux.c	Thu Aug  9 16:41:36 2001
+++ linux-2.4.20-pre2/arch/parisc/hpux/sys_hpux.c	Mon Aug 12 16:34:14 2002
@@ -9,6 +9,9 @@
 #include <linux/utsname.h>
 #include <asm/errno.h>
 #include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#include <asm/pgalloc.h>
+#include <linux/slab.h>
 
 unsigned long sys_brk(unsigned long addr);
  
@@ -41,6 +44,17 @@
 	return sys_waitpid(-1, stat_loc, 0);
 }
 
+int hpux_setpgrp(void)
+{
+	extern int sys_setpgid(int, int);
+	return sys_setpgid(0,0);
+}
+
+int hpux_setpgrp3(void)
+{
+	return hpux_setpgrp();
+}
+
 #define _SC_CPU_VERSION	10001
 #define _SC_OPEN_MAX	4
 #define CPU_PA_RISC1_1	0x210
@@ -129,6 +143,66 @@
 	return err;
 }
 
+/*
+ * Wrapper for hpux statfs call. At the moment, just calls the linux native one
+ * and ignores the extra fields at the end of the hpux statfs struct.
+ *
+ */
+
+typedef int32_t hpux_fsid_t[2];              /* file system ID type */
+typedef uint16_t hpux_site_t;
+
+struct hpux_statfs {
+     int32_t f_type;                    /* type of info, zero for now */
+     int32_t f_bsize;                   /* fundamental file system block size */
+     int32_t f_blocks;                  /* total blocks in file system */
+     int32_t f_bfree;                   /* free block in fs */
+     int32_t f_bavail;                  /* free blocks avail to non-superuser */
+     int32_t f_files;                   /* total file nodes in file system */
+     int32_t f_ffree;                   /* free file nodes in fs */
+     hpux_fsid_t  f_fsid;                    /* file system ID */
+     int32_t f_magic;                   /* file system magic number */
+     int32_t f_featurebits;             /* file system features */
+     int32_t f_spare[4];                /* spare for later */
+     hpux_site_t  f_cnode;                   /* cluster node where mounted */
+     int16_t f_pad;
+};
+
+/* hpux statfs */
+int hpux_statfs(const char *path, struct hpux_statfs *buf)
+{
+	int error;
+	int len;
+	char *kpath;
+
+	len = strlen_user((char *)path); 
+
+	kpath = (char *) kmalloc(len+1, GFP_KERNEL);
+	if ( !kpath ) {
+	printk(KERN_DEBUG "failed to kmalloc kpath\n");
+	return 0;
+	}
+
+	if ( copy_from_user(kpath, (char *)path, len+1) ) {
+	printk(KERN_DEBUG "failed to copy_from_user kpath\n");
+	kfree(kpath);
+	return 0;
+	}
+
+	printk(KERN_DEBUG "hpux_statfs(\"%s\",-)\n", kpath);
+
+	kfree(kpath);
+
+	/* just fake it, beginning of structures match */
+	extern int sys_statfs(const char *, struct statfs *);
+	error = sys_statfs(path, (struct statfs *) buf);
+
+	/* ignoring rest of statfs struct, but it should be zeros. Need to do 
+		something with f_fsid[1], which is the fstype for sysfs */
+
+	return error;
+}
+
 
 /*  This function is called from hpux_utssys(); HP-UX implements
  *  uname() as an option to utssys().
@@ -333,3 +407,541 @@
 	unlock_kernel();
 	return error;
 }
+
+/* lies - says it works, but it really didn't lock anything */
+int hpux_lockf(int fildes, int function, off_t size)
+{
+	return 0;
+}
+
+int hpux_sysfs(int opcode, unsigned long arg1, unsigned long arg2)
+{
+	char *fsname = NULL;
+	int len = 0;
+	int fstype;
+
+/*Unimplemented HP-UX syscall emulation. Syscall #334 (sysfs)
+  Args: 1 80057bf4 0 400179f0 0 0 0 */
+	printk(KERN_DEBUG "in hpux_sysfs\n");
+	printk(KERN_DEBUG "hpux_sysfs called with opcode = %d\n", opcode);
+	printk(KERN_DEBUG "hpux_sysfs called with arg1='%lx'\n", arg1);
+
+	if ( opcode == 1 ) { /* GETFSIND */	
+		len = strlen_user((char *)arg1);
+		printk(KERN_DEBUG "len of arg1 = %d\n", len);
+
+		fsname = (char *) kmalloc(len+1, GFP_KERNEL);
+		if ( !fsname ) {
+			printk(KERN_DEBUG "failed to kmalloc fsname\n");
+			return 0;
+		}
+
+		if ( copy_from_user(fsname, (char *)arg1, len+1) ) {
+			printk(KERN_DEBUG "failed to copy_from_user fsname\n");
+			kfree(fsname);
+			return 0;
+		}
+
+		printk(KERN_DEBUG "that is '%s' as (char *)\n", fsname);
+		if ( !strcmp(fsname, "hfs") ) {
+			fstype = 0;
+		} else {
+			fstype = 0;
+		};
+
+		kfree(fsname);
+
+		printk(KERN_DEBUG "returning fstype=%d\n", fstype);
+		return fstype; /* something other than default */
+	}
+
+
+	return 0;
+}
+
+
+/* Table of syscall names and handle for unimplemented routines */
+static const char *syscall_names[] = {
+	"nosys",                  /* 0 */
+	"exit",                  
+	"fork",                  
+	"read",                  
+	"write",                 
+	"open",                   /* 5 */
+	"close",                 
+	"wait",                  
+	"creat",                 
+	"link",                  
+	"unlink",                 /* 10 */
+	"execv",                 
+	"chdir",                 
+	"time",                  
+	"mknod",                 
+	"chmod",                  /* 15 */
+	"chown",                 
+	"brk",                   
+	"lchmod",                
+	"lseek",                 
+	"getpid",                 /* 20 */
+	"mount",                 
+	"umount",                
+	"setuid",                
+	"getuid",                
+	"stime",                  /* 25 */
+	"ptrace",                
+	"alarm",                 
+	NULL,                    
+	"pause",                 
+	"utime",                  /* 30 */
+	"stty",                  
+	"gtty",                  
+	"access",                
+	"nice",                  
+	"ftime",                  /* 35 */
+	"sync",                  
+	"kill",                  
+	"stat",                  
+	"setpgrp3",              
+	"lstat",                  /* 40 */
+	"dup",                   
+	"pipe",                  
+	"times",                 
+	"profil",                
+	"ki_call",                /* 45 */
+	"setgid",                
+	"getgid",                
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 50 */
+	"acct",                  
+	"set_userthreadid",      
+	NULL,                    
+	"ioctl",                 
+	"reboot",                 /* 55 */
+	"symlink",               
+	"utssys",                
+	"readlink",              
+	"execve",                
+	"umask",                  /* 60 */
+	"chroot",                
+	"fcntl",                 
+	"ulimit",                
+	NULL,                    
+	NULL,                     /* 65 */
+	"vfork",                 
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 70 */
+	"mmap",                  
+	NULL,                    
+	"munmap",                
+	"mprotect",              
+	"madvise",                /* 75 */
+	"vhangup",               
+	"swapoff",               
+	NULL,                    
+	"getgroups",             
+	"setgroups",              /* 80 */
+	"getpgrp2",              
+	"setpgid/setpgrp2",      
+	"setitimer",             
+	"wait3",                 
+	"swapon",                 /* 85 */
+	"getitimer",             
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	"dup2",                   /* 90 */
+	NULL,                    
+	"fstat",                 
+	"select",                
+	NULL,                    
+	"fsync",                  /* 95 */
+	"setpriority",           
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	"getpriority",            /* 100 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 105 */
+	NULL,                    
+	NULL,                    
+	"sigvector",             
+	"sigblock",              
+	"sigsetmask",             /* 110 */
+	"sigpause",              
+	"sigstack",              
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 115 */
+	"gettimeofday",          
+	"getrusage",             
+	NULL,                    
+	NULL,                    
+	"readv",                  /* 120 */
+	"writev",                
+	"settimeofday",          
+	"fchown",                
+	"fchmod",                
+	NULL,                     /* 125 */
+	"setresuid",             
+	"setresgid",             
+	"rename",                
+	"truncate",              
+	"ftruncate",              /* 130 */
+	NULL,                    
+	"sysconf",               
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 135 */
+	"mkdir",                 
+	"rmdir",                 
+	NULL,                    
+	"sigcleanup",            
+	"setcore",                /* 140 */
+	NULL,                    
+	"gethostid",             
+	"sethostid",             
+	"getrlimit",             
+	"setrlimit",              /* 145 */
+	NULL,                    
+	NULL,                    
+	"quotactl",              
+	"get_sysinfo",           
+	NULL,                     /* 150 */
+	"privgrp",               
+	"rtprio",                
+	"plock",                 
+	NULL,                    
+	"lockf",                  /* 155 */
+	"semget",                
+	NULL,                    
+	"semop",                 
+	"msgget",                
+	NULL,                     /* 160 */
+	"msgsnd",                
+	"msgrcv",                
+	"shmget",                
+	NULL,                    
+	"shmat",                  /* 165 */
+	"shmdt",                 
+	NULL,                    
+	"csp/nsp_init",          
+	"cluster",               
+	"mkrnod",                 /* 170 */
+	"test",                  
+	"unsp_open",             
+	NULL,                    
+	"getcontext",            
+	"osetcontext",            /* 175 */
+	"bigio",                 
+	"pipenode",              
+	"lsync",                 
+	"getmachineid",          
+	"cnodeid/mysite",         /* 180 */
+	"cnodes/sitels",         
+	"swapclients",           
+	"rmtprocess",            
+	"dskless_stats",         
+	"sigprocmask",            /* 185 */
+	"sigpending",            
+	"sigsuspend",            
+	"sigaction",             
+	NULL,                    
+	"nfssvc",                 /* 190 */
+	"getfh",                 
+	"getdomainname",         
+	"setdomainname",         
+	"async_daemon",          
+	"getdirentries",          /* 195 */
+	"statfs",                
+	"fstatfs",               
+	"vfsmount",              
+	NULL,                    
+	"waitpid",                /* 200 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 205 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 210 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 215 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 220 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	"sigsetreturn",          
+	"sigsetstatemask",        /* 225 */
+	"bfactl",                
+	"cs",                    
+	"cds",                   
+	NULL,                    
+	"pathconf",               /* 230 */
+	"fpathconf",             
+	NULL,                    
+	NULL,                    
+	"nfs_fcntl",             
+	"ogetacl",                /* 235 */
+	"ofgetacl",              
+	"osetacl",               
+	"ofsetacl",              
+	"pstat",                 
+	"getaudid",               /* 240 */
+	"setaudid",              
+	"getaudproc",            
+	"setaudproc",            
+	"getevent",              
+	"setevent",               /* 245 */
+	"audwrite",              
+	"audswitch",             
+	"audctl",                
+	"ogetaccess",            
+	"fsctl",                  /* 250 */
+	"ulconnect",             
+	"ulcontrol",             
+	"ulcreate",              
+	"uldest",                
+	"ulrecv",                 /* 255 */
+	"ulrecvcn",              
+	"ulsend",                
+	"ulshutdown",            
+	"swapfs",                
+	"fss",                    /* 260 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 265 */
+	NULL,                    
+	"tsync",                 
+	"getnumfds",             
+	"poll",                  
+	"getmsg",                 /* 270 */
+	"putmsg",                
+	"fchdir",                
+	"getmount_cnt",          
+	"getmount_entry",        
+	"accept",                 /* 275 */
+	"bind",                  
+	"connect",               
+	"getpeername",           
+	"getsockname",           
+	"getsockopt",             /* 280 */
+	"listen",                
+	"recv",                  
+	"recvfrom",              
+	"recvmsg",               
+	"send",                   /* 285 */
+	"sendmsg",               
+	"sendto",                
+	"setsockopt",            
+	"shutdown",              
+	"socket",                 /* 290 */
+	"socketpair",            
+	"proc_open",             
+	"proc_close",            
+	"proc_send",             
+	"proc_recv",              /* 295 */
+	"proc_sendrecv",         
+	"proc_syscall",          
+	"ipccreate",             
+	"ipcname",               
+	"ipcnamerase",            /* 300 */
+	"ipclookup",             
+	"ipcselect",             
+	"ipcconnect",            
+	"ipcrecvcn",             
+	"ipcsend",                /* 305 */
+	"ipcrecv",               
+	"ipcgetnodename",        
+	"ipcsetnodename",        
+	"ipccontrol",            
+	"ipcshutdown",            /* 310 */
+	"ipcdest",               
+	"semctl",                
+	"msgctl",                
+	"shmctl",                
+	"mpctl",                  /* 315 */
+	"exportfs",              
+	"getpmsg",               
+	"putpmsg",               
+	"strioctl",              
+	"msync",                  /* 320 */
+	"msleep",                
+	"mwakeup",               
+	"msem_init",             
+	"msem_remove",           
+	"adjtime",                /* 325 */
+	"kload",                 
+	"fattach",               
+	"fdetach",               
+	"serialize",             
+	"statvfs",                /* 330 */
+	"fstatvfs",              
+	"lchown",                
+	"getsid",                
+	"sysfs",                 
+	NULL,                     /* 335 */
+	NULL,                    
+	"sched_setparam",        
+	"sched_getparam",        
+	"sched_setscheduler",    
+	"sched_getscheduler",     /* 340 */
+	"sched_yield",           
+	"sched_get_priority_max",
+	"sched_get_priority_min",
+	"sched_rr_get_interval", 
+	"clock_settime",          /* 345 */
+	"clock_gettime",         
+	"clock_getres",          
+	"timer_create",          
+	"timer_delete",          
+	"timer_settime",          /* 350 */
+	"timer_gettime",         
+	"timer_getoverrun",      
+	"nanosleep",             
+	"toolbox",               
+	NULL,                     /* 355 */
+	"getdents",              
+	"getcontext",            
+	"sysinfo",               
+	"fcntl64",               
+	"ftruncate64",            /* 360 */
+	"fstat64",               
+	"getdirentries64",       
+	"getrlimit64",           
+	"lockf64",               
+	"lseek64",                /* 365 */
+	"lstat64",               
+	"mmap64",                
+	"setrlimit64",           
+	"stat64",                
+	"truncate64",             /* 370 */
+	"ulimit64",              
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                     /* 375 */
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	NULL,                    
+	"setcontext",             /* 380 */
+	"sigaltstack",           
+	"waitid",                
+	"setpgrp",               
+	"recvmsg2",              
+	"sendmsg2",               /* 385 */
+	"socket2",               
+	"socketpair2",           
+	"setregid",              
+	"lwp_create",            
+	"lwp_terminate",          /* 390 */
+	"lwp_wait",              
+	"lwp_suspend",           
+	"lwp_resume",            
+	"lwp_self",              
+	"lwp_abort_syscall",      /* 395 */
+	"lwp_info",              
+	"lwp_kill",              
+	"ksleep",                
+	"kwakeup",               
+	"ksleep_abort",           /* 400 */
+	"lwp_proc_info",         
+	"lwp_exit",              
+	"lwp_continue",          
+	"getacl",                
+	"fgetacl",                /* 405 */
+	"setacl",                
+	"fsetacl",               
+	"getaccess",             
+	"lwp_mutex_init",        
+	"lwp_mutex_lock_sys",     /* 410 */
+	"lwp_mutex_unlock",      
+	"lwp_cond_init",         
+	"lwp_cond_signal",       
+	"lwp_cond_broadcast",    
+	"lwp_cond_wait_sys",      /* 415 */
+	"lwp_getscheduler",      
+	"lwp_setscheduler",      
+	"lwp_getprivate",        
+	"lwp_setprivate",        
+	"lwp_detach",             /* 420 */
+	"mlock",                 
+	"munlock",               
+	"mlockall",              
+	"munlockall",            
+	"shm_open",               /* 425 */
+	"shm_unlink",            
+	"sigqueue",              
+	"sigwaitinfo",           
+	"sigtimedwait",          
+	"sigwait",                /* 430 */
+	"aio_read",              
+	"aio_write",             
+	"lio_listio",            
+	"aio_error",             
+	"aio_return",             /* 435 */
+	"aio_cancel",            
+	"aio_suspend",           
+	"aio_fsync",             
+	"mq_open",               
+	"mq_unlink",              /* 440 */
+	"mq_send",               
+	"mq_receive",            
+	"mq_notify",             
+	"mq_setattr",            
+	"mq_getattr",             /* 445 */
+	"ksem_open",             
+	"ksem_unlink",           
+	"ksem_close",            
+	"ksem_destroy",          
+	"lw_sem_incr",            /* 450 */
+	"lw_sem_decr",           
+	"lw_sem_read",           
+	"mq_close",              
+};
+static const int syscall_names_max = 453;
+
+int
+hpux_unimplemented(unsigned long arg1,unsigned long arg2,unsigned long arg3,
+		   unsigned long arg4,unsigned long arg5,unsigned long arg6,
+		   unsigned long arg7,unsigned long sc_num)
+{
+	/* NOTE: sc_num trashes arg8 for the few syscalls that actually
+	 * have a valid 8th argument.
+	 */
+	const char *name = NULL;
+	if ( sc_num <= syscall_names_max && sc_num >= 0 ) {
+		name = syscall_names[sc_num];
+	}
+
+	if ( name ) {
+		printk(KERN_DEBUG "Unimplemented HP-UX syscall emulation. Syscall #%lu (%s)\n",
+		sc_num, name);
+	} else {
+		printk(KERN_DEBUG "Unimplemented unknown HP-UX syscall emulation. Syscall #%lu\n",
+		sc_num);
+	}
+	
+	printk(KERN_DEBUG "  Args: %lx %lx %lx %lx %lx %lx %lx\n",
+		arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+
+	return -ENOSYS;
+}
diff -urN linux-2.4.20-pre1/arch/parisc/hpux/wrappers.S linux-2.4.20-pre2/arch/parisc/hpux/wrappers.S
--- linux-2.4.20-pre1/arch/parisc/hpux/wrappers.S	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/hpux/wrappers.S	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
-/*------------------------------------------------------------------------------
- * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+/*
+ * Linux/PARISC Project (http://www.parisc-linux.org/)
  *
  * HP-UX System Call Wrapper routines and System Call Return Path
  *
@@ -29,7 +29,6 @@
 	.level		1.1
 	.text
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/signal.h>
 
@@ -81,6 +80,7 @@
 
 
 	.export hpux_fork_wrapper
+	.export hpux_child_return
 	.import sys_fork
 
 hpux_fork_wrapper:
@@ -91,12 +91,10 @@
 	stw	%r2,-20(%r30)
 	ldo	64(%r30),%r30
 	stw	%r2,PT_GR19(%r1)	;! save for child
-	stw	%r30,PT_GR20(%r1)	;! save for child
-	ldil	L%child_return,%r3
-	ldo	R%child_return(%r3),%r3
-	stw	%r3,PT_GR21(%r1)	;! save for child
+	stw	%r30,PT_GR21(%r1)	;! save for child
 
-	ldw	TASK_PT_GR30(%r1),%r25
+	ldw     PT_GR30(%r1),%r25
+	mtctl   %r25,%cr29
 	copy	%r1,%r24
 	bl	sys_clone,%r2
 	ldi	SIGCHLD,%r26
@@ -130,7 +128,10 @@
 
 	/* Set the return value for the child */
 
-child_return:
+hpux_child_return:
+	bl	schedule_tail, %r2
+	nop
+
 	ldw TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
 	b fork_return
 	copy %r0,%r28
@@ -242,3 +243,10 @@
 no_error:
 	b syscall_exit
 	nop
+
+	.export hpux_unimplemented_wrapper
+	.import hpux_unimplemented
+
+hpux_unimplemented_wrapper:
+	b hpux_unimplemented
+	stw %r22,-64(%r30)  /* overwrite arg8 with syscall number */
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/Makefile linux-2.4.20-pre2/arch/parisc/kernel/Makefile
--- linux-2.4.20-pre1/arch/parisc/kernel/Makefile	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/Makefile	Mon Aug 12 16:34:14 2002
@@ -7,26 +7,30 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-all: kernel.o init_task.o pdc_cons.o process.o head.o
-O_TARGET = kernel.o
-O_OBJS = 
+ifdef CONFIG_PARISC64
+all: kernel.o init_task.o pdc_cons.o process.o head64.o unaligned.o perf.o perf_asm.o
+else
+all: kernel.o init_task.o pdc_cons.o process.o head.o unaligned.o
+endif
 
-# Object file lists.
+O_TARGET = kernel.o
 
 obj-y		:=
 obj-m		:=
 obj-n		:=
 obj-		:=
 
-obj-y		+= cache.o setup.o traps.o time.o irq.o \
-		syscall.o entry.o sys_parisc.o pdc.o ptrace.o hardware.o \
-		inventory.o drivers.o semaphore.o pa7300lc.o pci-dma.o \
-		signal.o hpmc.o \
-		real1.o real2.o led.o parisc_ksyms.o
+obj-y           += cache.o pacache.o setup.o traps.o time.o irq.o \
+		pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \
+		ptrace.o hardware.o inventory.o drivers.o semaphore.o \
+		signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \
+		processor.o power.o
 
-export-objs	:= parisc_ksyms.o
+export-objs	:= parisc_ksyms.o superio.o keyboard.o
 
 
+obj-$(CONFIG_SMP) += smp.o irq_smp.o
+obj-$(CONFIG_PA11) += pci-dma.o
 obj-$(CONFIG_PCI) += pci.o
 obj-$(CONFIG_VT) += keyboard.o
 obj-$(CONFIG_PCI_LBA) += lba_pci.o
@@ -37,16 +41,11 @@
 # Only use one of them: ccio-rm-dma is for PCX-W systems *only*
 # obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o
 obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
-
-.o.S:	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
-
-# Translate to Rules.make lists.
-
-O_OBJS          := $(filter-out $(export-objs), $(obj-y))
-OX_OBJS         := $(filter     $(export-objs), $(obj-y))
-M_OBJS          := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS         := $(sort $(filter     $(export-objs), $(obj-m)))
-MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
-MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+obj-$(CONFIG_CHASSIS_LCD_LED) += led.o 
+obj-$(CONFIG_SUPERIO) += superio.o
+obj-$(CONFIG_PARISC64) += binfmt_elf32.o sys_parisc32.o \
+		ioctl32.o signal32.o
+# only supported for PCX-W/U in 64-bit mode at the moment
+obj-$(CONFIG_PARISC64) += perf.o perf_asm.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/binfmt_elf32.c linux-2.4.20-pre2/arch/parisc/kernel/binfmt_elf32.c
--- linux-2.4.20-pre1/arch/parisc/kernel/binfmt_elf32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/binfmt_elf32.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,93 @@
+/*
+ * Support for 32-bit Linux/Parisc ELF binaries on 64 bit kernels
+ *
+ * Copyright (C) 2000 John Marvin
+ * Copyright (C) 2000 Hewlett Packard Co.
+ *
+ * Heavily inspired from various other efforts to do the same thing
+ * (ia64,sparc64/mips64)
+ */
+
+/* Make sure include/asm-parisc/elf.h does the right thing */
+
+#define ELF_CLASS	ELFCLASS32
+
+typedef unsigned int elf_greg_t;
+
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/elfcore.h>
+#include "sys32.h"		/* struct timeval32 */
+
+#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;	/* GP 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 */
+	u16	pr_uid;
+	u16	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 */
+};
+
+#define elf_addr_t	unsigned int
+typedef unsigned int elf_caddr_t;
+#define init_elf_binfmt init_elf32_binfmt
+
+#define ELF_PLATFORM  ("PARISC32\0")
+
+#define ELF_CORE_COPY_REGS(dst, pt)	\
+	memset(dst, 0, sizeof(dst));	/* don't leak any "random" bits */ \
+	{	int i; \
+		for (i = 0; i < 32; i++) dst[i] = (elf_greg_t) pt->gr[i]; \
+		for (i = 0; i < 8; i++) dst[32 + i] = (elf_greg_t) pt->sr[i]; \
+	} \
+	dst[40] = (elf_greg_t) pt->iaoq[0]; dst[41] = (elf_greg_t) pt->iaoq[1]; \
+	dst[42] = (elf_greg_t) pt->iasq[0]; dst[43] = (elf_greg_t) pt->iasq[1]; \
+	dst[44] = (elf_greg_t) pt->sar;   dst[45] = (elf_greg_t) pt->iir; \
+	dst[46] = (elf_greg_t) pt->isr;   dst[47] = (elf_greg_t) pt->ior; \
+	dst[48] = (elf_greg_t) mfctl(22); dst[49] = (elf_greg_t) mfctl(0); \
+	dst[50] = (elf_greg_t) mfctl(24); dst[51] = (elf_greg_t) mfctl(25); \
+	dst[52] = (elf_greg_t) mfctl(26); dst[53] = (elf_greg_t) mfctl(27); \
+	dst[54] = (elf_greg_t) mfctl(28); dst[55] = (elf_greg_t) mfctl(29); \
+	dst[56] = (elf_greg_t) mfctl(30); dst[57] = (elf_greg_t) mfctl(31); \
+	dst[58] = (elf_greg_t) mfctl( 8); dst[59] = (elf_greg_t) mfctl( 9); \
+	dst[60] = (elf_greg_t) mfctl(12); dst[61] = (elf_greg_t) mfctl(13); \
+	dst[62] = (elf_greg_t) mfctl(10); dst[63] = (elf_greg_t) mfctl(15);
+
+/*
+ * We should probably use this macro to set a flag somewhere to indicate
+ * this is a 32 on 64 process. We could use PER_LINUX_32BIT, or we
+ * could set a processor dependent flag in the thread_struct.
+ */
+
+#define SET_PERSONALITY(ex, ibcs2) \
+	current->personality = PER_LINUX_32BIT
+
+#include "../../../fs/binfmt_elf.c"
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/cache.c linux-2.4.20-pre2/arch/parisc/kernel/cache.c
--- linux-2.4.20-pre1/arch/parisc/kernel/cache.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/cache.c	Mon Aug 12 16:34:14 2002
@@ -15,202 +15,85 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 
 #include <asm/pdc.h>
 #include <asm/cache.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
+#include <asm/processor.h>
+
+int split_tlb;
+int dcache_stride;
+int icache_stride;
 
 struct pdc_cache_info cache_info;
-#ifndef __LP64__
+#ifndef CONFIG_PA20
 static struct pdc_btlb_info btlb_info;
 #endif
 
-
-void __flush_page_to_ram(unsigned long address)
-{
-	__flush_dcache_range(address, PAGE_SIZE);
-	__flush_icache_range(address, PAGE_SIZE);
-}
-
-
-
-void flush_data_cache(void)
+#ifdef CONFIG_SMP
+void
+flush_data_cache(void)
 {
-	register unsigned long base   = cache_info.dc_base;
-	register unsigned long count  = cache_info.dc_count;
-	register unsigned long loop   = cache_info.dc_loop;
-	register unsigned long stride = cache_info.dc_stride;
-	register unsigned long addr;
-	register long i, j;
-
-	for(i=0,addr=base; i<count; i++,addr+=stride)
-		for(j=0; j<loop; j++)
-			fdce(addr);
-}
-		
-static inline void flush_data_tlb_space(void)
-{
-	unsigned long base   = cache_info.dt_off_base;
-	unsigned long count  = cache_info.dt_off_count;
-	unsigned long stride = cache_info.dt_off_stride;
-	unsigned long loop   = cache_info.dt_loop;
-
-	unsigned long addr;
-	long i,j;
-	
-	for(i=0,addr=base; i<count; i++,addr+=stride)
-		for(j=0; j<loop; j++)
-			pdtlbe(addr);
-}
-
-
-
-void flush_data_tlb(void)
-{
-	unsigned long base   = cache_info.dt_sp_base;
-	unsigned long count  = cache_info.dt_sp_count;
-	unsigned long stride = cache_info.dt_sp_stride;
-	unsigned long space;
-	unsigned long old_sr1;
-	long i;
-	
-	old_sr1 = mfsp(1);
-	
-	for(i=0,space=base; i<count; i++, space+=stride) {
-		mtsp(space,1);
-		flush_data_tlb_space();
-	}
-
-	mtsp(old_sr1, 1);
+	smp_call_function((void (*)(void *))flush_data_cache_local, NULL, 1, 1);
+	flush_data_cache_local();
 }
+#endif
 
-static inline void flush_instruction_tlb_space(void)
+void
+flush_cache_all_local(void)
 {
-	unsigned long base   = cache_info.it_off_base;
-	unsigned long count  = cache_info.it_off_count;
-	unsigned long stride = cache_info.it_off_stride;
-	unsigned long loop   = cache_info.it_loop;
-
-	unsigned long addr;
-	long i,j;
-	
-	for(i=0,addr=base; i<count; i++,addr+=stride)
-		for(j=0; j<loop; j++)
-			pitlbe(addr);
-}
-
-void flush_instruction_tlb(void)
-{
-	unsigned long base   = cache_info.it_sp_base;
-	unsigned long count  = cache_info.it_sp_count;
-	unsigned long stride = cache_info.it_sp_stride;
-	unsigned long space;
-	unsigned long old_sr1;
-	unsigned int i;
-	
-	old_sr1 = mfsp(1);
-	
-	for(i=0,space=base; i<count; i++, space+=stride) {
-		mtsp(space,1);
-		flush_instruction_tlb_space();
-	}
-
-	mtsp(old_sr1, 1);
+	flush_instruction_cache_local();
+	flush_data_cache_local();
 }
 
+/* flushes EVERYTHING (tlb & cache) */
 
-void __flush_tlb_space(unsigned long space)
+void
+flush_all_caches(void)
 {
-	unsigned long old_sr1;
-
-	old_sr1 = mfsp(1);
-	mtsp(space, 1);
-	
-	flush_data_tlb_space();
-	flush_instruction_tlb_space();
-
-	mtsp(old_sr1, 1);
+	flush_cache_all();
+	flush_tlb_all();
 }
 
-
-void flush_instruction_cache(void)
+void
+update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
-	register unsigned long base   = cache_info.ic_base;
-	register unsigned long count  = cache_info.ic_count;
-	register unsigned long loop   = cache_info.ic_loop;
-	register unsigned long stride = cache_info.ic_stride;
-	register unsigned long addr;
-	register long i, j;
-	unsigned long old_sr1;
-	
-	old_sr1 = mfsp(1);
-	mtsp(0,1);
+	struct page *page = pte_page(pte);
 
-	/*
-	 * Note: fice instruction has 3 bit space field, so one must
-	 *       be specified (otherwise you are justing using whatever
-	 *       happens to be in sr0).
-	 */
+	if (VALID_PAGE(page) && page->mapping &&
+	    test_bit(PG_dcache_dirty, &page->flags)) {
 
-	for(i=0,addr=base; i<count; i++,addr+=stride)
-		for(j=0; j<loop; j++)
-			fice(addr);
-
-	mtsp(old_sr1, 1);
-}
-
-/* not yet ... fdc() needs to be implemented in cache.h !
-void flush_datacache_range( unsigned int base, unsigned int end )
-{
-    register long offset,offset_add;
-    offset_add = ( (1<<(cache_info.dc_conf.cc_block-1)) * 
-		    cache_info.dc_conf.cc_line ) << 4;
-    for (offset=base; offset<=end; offset+=offset_add)
-	fdc(space,offset);
-    fdc(space,end);
-}
-*/
-
-/* flushes code and data-cache */
-void flush_all_caches(void)
-{
-	flush_instruction_cache();
-	flush_data_cache();
-
-	flush_instruction_tlb();
-	flush_data_tlb();
-
-	asm volatile("sync");
-	asm volatile("syncdma");
-	asm volatile("sync");
+		flush_kernel_dcache_page(page_address(page));
+		clear_bit(PG_dcache_dirty, &page->flags);
+	}
 }
 
-int get_cache_info(char *buffer)
+void
+show_cache_info(struct seq_file *m)
 {
-	char *p = buffer;
-
-	p += sprintf(p, "I-cache\t\t: %ld KB\n", 
+	seq_printf(m, "I-cache\t\t: %ld KB\n", 
 		cache_info.ic_size/1024 );
-	p += sprintf(p, "D-cache\t\t: %ld KB (%s)%s\n", 
+	seq_printf(m, "D-cache\t\t: %ld KB (%s)%s\n", 
 		cache_info.dc_size/1024,
 		(cache_info.dc_conf.cc_wt ? "WT":"WB"),
 		(cache_info.dc_conf.cc_sh ? " - shared I/D":"")
 	);
 
-	p += sprintf(p, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
+	seq_printf(m, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
 		cache_info.it_size,
 		cache_info.dt_size,
 		cache_info.dt_conf.tc_sh ? " - shared with ITLB":""
 	);
 		
-#ifndef __LP64__
+#ifndef CONFIG_PA20
 	/* BTLB - Block TLB */
 	if (btlb_info.max_size==0) {
-		p += sprintf(p, "BTLB\t\t: not supported\n" );
+		seq_printf(m, "BTLB\t\t: not supported\n" );
 	} else {
-		p += sprintf(p, 
+		seq_printf(m, 
 		"BTLB fixed\t: max. %d pages, pagesize=%d (%dMB)\n"
 		"BTLB fix-entr.\t: %d instruction, %d data (%d combined)\n"
 		"BTLB var-entr.\t: %d instruction, %d data (%d combined)\n",
@@ -225,11 +108,8 @@
 		);
 	}
 #endif
-
-	return p - buffer;
 }
 
-
 void __init 
 cache_init(void)
 {
@@ -237,17 +117,108 @@
 		panic("cache_init: pdc_cache_info failed");
 
 #if 0
-	printk("ic_size %lx dc_size %lx it_size %lx pdc_cache_info %d*long pdc_cache_cf %d\n",
+	printk(KERN_DEBUG "ic_size %lx dc_size %lx it_size %lx pdc_cache_info %d*long pdc_cache_cf %d\n",
 	    cache_info.ic_size,
 	    cache_info.dc_size,
 	    cache_info.it_size,
 	    sizeof (struct pdc_cache_info) / sizeof (long),
 	    sizeof (struct pdc_cache_cf)
 	);
+
+	printk(KERN_DEBUG "dc base %x dc stride %x dc count %x dc loop %d\n",
+	    cache_info.dc_base,
+	    cache_info.dc_stride,
+	    cache_info.dc_count,
+	    cache_info.dc_loop);
+
+	printk(KERN_DEBUG "dc conf: alias %d block %d line %d wt %d sh %d cst %d assoc %d\n",
+	    cache_info.dc_conf.cc_alias,
+	    cache_info.dc_conf.cc_block,
+	    cache_info.dc_conf.cc_line,
+	    cache_info.dc_conf.cc_wt,
+	    cache_info.dc_conf.cc_sh,
+	    cache_info.dc_conf.cc_cst,
+	    cache_info.dc_conf.cc_assoc);
+
+	printk(KERN_DEBUG "ic conf: alias %d block %d line %d wt %d sh %d cst %d assoc %d\n",
+	    cache_info.ic_conf.cc_alias,
+	    cache_info.ic_conf.cc_block,
+	    cache_info.ic_conf.cc_line,
+	    cache_info.ic_conf.cc_wt,
+	    cache_info.ic_conf.cc_sh,
+	    cache_info.ic_conf.cc_cst,
+	    cache_info.ic_conf.cc_assoc);
+
+	printk(KERN_DEBUG "dt conf: sh %d page %d cst %d aid %d pad1 %d \n",
+	    cache_info.dt_conf.tc_sh,
+	    cache_info.dt_conf.tc_page,
+	    cache_info.dt_conf.tc_cst,
+	    cache_info.dt_conf.tc_aid,
+	    cache_info.dt_conf.tc_pad1);
+
+	printk(KERN_DEBUG "it conf: sh %d page %d cst %d aid %d pad1 %d \n",
+	    cache_info.it_conf.tc_sh,
+	    cache_info.it_conf.tc_page,
+	    cache_info.it_conf.tc_cst,
+	    cache_info.it_conf.tc_aid,
+	    cache_info.it_conf.tc_pad1);
 #endif
-#ifndef __LP64__
+
+	split_tlb = 0;
+	if (cache_info.dt_conf.tc_sh == 0 || cache_info.dt_conf.tc_sh == 2) {
+
+	    if (cache_info.dt_conf.tc_sh == 2)
+		printk(KERN_WARNING "Unexpected TLB configuration. "
+			"Will flush I/D separately (could be optimized).\n");
+
+	    split_tlb = 1;
+	}
+
+	dcache_stride = ( (1<<(cache_info.dc_conf.cc_block+3)) *
+			 cache_info.dc_conf.cc_line );
+	icache_stride = ( (1<<(cache_info.ic_conf.cc_block+3)) *
+			 cache_info.ic_conf.cc_line );
+#ifndef CONFIG_PA20
 	if(pdc_btlb_info(&btlb_info)<0) {
 		memset(&btlb_info, 0, sizeof btlb_info);
 	}
 #endif
+
+	if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) == PDC_MODEL_NVA_UNSUPPORTED) {
+		printk(KERN_WARNING "Only equivalent aliasing supported\n");
+#ifndef CONFIG_SMP
+		panic("SMP kernel required to avoid non-equivalent aliasing");
+#endif
+	}
+}
+
+void disable_sr_hashing(void)
+{
+    int srhash_type;
+
+    if (boot_cpu_data.cpu_type == pcxl2)
+	return; /* pcxl2 doesn't support space register hashing */
+
+    switch (boot_cpu_data.cpu_type) {
+
+    case pcx:
+	BUG(); /* We shouldn't get here. code in setup.c should prevent it */
+	return;
+
+    case pcxs:
+    case pcxt:
+    case pcxt_:
+	srhash_type = SRHASH_PCXST;
+	break;
+
+    case pcxl:
+	srhash_type = SRHASH_PCXL;
+	break;
+
+    default: /* Currently all PA2.0 machines use the same ins. sequence */
+	srhash_type = SRHASH_PA20;
+	break;
+    }
+
+    disable_sr_hashing_asm(srhash_type);
 }
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/ccio-dma.c linux-2.4.20-pre2/arch/parisc/kernel/ccio-dma.c
--- linux-2.4.20-pre1/arch/parisc/kernel/ccio-dma.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/ccio-dma.c	Mon Aug 12 16:34:14 2002
@@ -38,16 +38,19 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#define PCI_DEBUG
 #include <linux/pci.h>
+#undef PCI_DEBUG
 
 #include <asm/byteorder.h>
 #include <asm/cache.h>		/* for L1_CACHE_BYTES */
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/page.h>
-
+#include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/gsc.h>		/* for gsc_writeN()... */
+#include <asm/hardware.h>       /* for register_module() */
 
 /* 
 ** Choose "ccio" since that's what HP-UX calls it.
@@ -55,12 +58,10 @@
 */
 #define MODULE_NAME "ccio"
 
-/*
-#define DEBUG_CCIO_RES
-#define DEBUG_CCIO_RUN
-#define DEBUG_CCIO_INIT
-#define DUMP_RESMAP
-*/
+#undef DEBUG_CCIO_RES
+#undef DEBUG_CCIO_RUN
+#undef DEBUG_CCIO_INIT
+#undef DEBUG_CCIO_RUN_SG
 
 #include <linux/proc_fs.h>
 #include <asm/runway.h>		/* for proc_runway_root */
@@ -83,68 +84,20 @@
 #define DBG_RES(x...)
 #endif
 
+#ifdef DEBUG_CCIO_RUN_SG
+#define DBG_RUN_SG(x...) printk(x)
+#else
+#define DBG_RUN_SG(x...)
+#endif
+
 #define CCIO_INLINE	/* inline */
-#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
+#define WRITE_U32(value, addr) gsc_writel(value, (u32 *)(addr))
+#define READ_U32(addr) gsc_readl((u32 *)(addr))
 
 #define U2_IOA_RUNWAY 0x580
 #define U2_BC_GSC     0x501
 #define UTURN_IOA_RUNWAY 0x581
 #define UTURN_BC_GSC     0x502
-/* We *can't* support JAVA (T600). Venture there at your own risk. */
-
-static void dump_resmap(void);
-
-static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-static struct pa_iodc_driver ccio_drivers_for[] = {
-
-   {HPHW_IOA, U2_IOA_RUNWAY, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback},
-
-   {HPHW_IOA, UTURN_IOA_RUNWAY, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback},
-
-/*
-** FIXME: The following claims the GSC bus port, not the IOA.
-**        And there are two busses below a single I/O TLB.
-**
-** These should go away once we have a real PA bus walk.
-** Firmware wants to tell the PA bus walk code about the GSC ports
-** since they are not "architected" PA I/O devices. Ie a PA bus walk
-** wouldn't discover them. But the PA bus walk code could check
-** the "fixed module table" to add such devices to an I/O Tree
-** and proceed with the recursive, depth first bus walk.
-*/
-   {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xc, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "U2 GSC+ BC", (void *) ccio_driver_callback},
-
-   {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xc, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "Uturn GSC+ BC", (void *) ccio_driver_callback},
-
-   {0,0,0,0,0,0,
-   0,
-   (char *) NULL, (char *) NULL, (void *) NULL }
-};
-
-
-#define IS_U2(id) ( \
-    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \
-    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC))  \
-)
-
-#define IS_UTURN(id) ( \
-    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \
-    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC))  \
-)
-
 
 #define IOA_NORMAL_MODE      0x00020080 /* IO_CONTROL to turn on CCIO        */
 #define CMD_TLB_DIRECT_WRITE 35         /* IO_COMMAND for I/O TLB Writes     */
@@ -176,41 +129,46 @@
         volatile uint32_t   io_io_high;             /* Offset 15 */
 };
 
+struct ioc {
+	struct ioa_registers *ioc_hpa;  /* I/O MMU base address */
+	u8  *res_map;	                /* resource map, bit == pdir entry */
+	u64 *pdir_base;	                /* physical base address */
+	u32 res_hint;	                /* next available IOVP - 
+					   circular search */
+	u32 res_size;		    	/* size of resource map in bytes */
+	spinlock_t res_lock;
+
+#ifdef CONFIG_PROC_FS
+#define CCIO_SEARCH_SAMPLE 0x100
+	unsigned long avg_search[CCIO_SEARCH_SAMPLE];
+	unsigned long avg_idx;		  /* current index into avg_search */
+	unsigned long used_pages;
+	unsigned long msingle_calls;
+	unsigned long msingle_pages;
+	unsigned long msg_calls;
+	unsigned long msg_pages;
+	unsigned long usingle_calls;
+	unsigned long usingle_pages;
+	unsigned long usg_calls;
+	unsigned long usg_pages;
 
-struct ccio_device {
-	struct ccio_device    *next;  /* list of LBA's in system */
-	struct hp_device      *iodc;  /* data about dev from firmware */
-	spinlock_t            ccio_lock;
-
-	struct ioa_registers   *ccio_hpa; /* base address */
-	u64   *pdir_base;   /* physical base address */
-	char  *res_map;     /* resource map, bit == pdir entry */
-
-	int   res_hint;	/* next available IOVP - circular search */
-	int   res_size;	/* size of resource map in bytes */
-	int   chainid_shift; /* specify bit location of chain_id */
-	int   flags;         /* state/functionality enabled */
-#ifdef DELAYED_RESOURCE_CNT
-	dma_addr_t res_delay[DELAYED_RESOURCE_CNT];
+	unsigned short cujo20_bug;
 #endif
 
 	/* STUFF We don't need in performance path */
-	int  pdir_size;     /* in bytes, determined by IOV Space size */
-	int  hw_rev;        /* HW revision of chip */
+	u32 pdir_size; 			/* in bytes, determined by IOV Space size */
+	u32 chainid_shift; 		/* specify bit location of chain_id */
+	struct ioc *next;		/* Linked list of discovered iocs */
+	const char *name;		/* device name from firmware */
+	unsigned int hw_path;           /* the hardware path this ioc is associatd with */
+	struct pci_dev *fake_pci_dev;   /* the fake pci_dev for non-pci devs */
+	struct resource mmio_region[2]; /* The "routed" MMIO regions */
 };
 
-
 /* Ratio of Host MEM to IOV Space size */
 static unsigned long ccio_mem_ratio = 4;
-static struct ccio_device *ccio_list = NULL;
-
-static int ccio_proc_info(char *buffer, char **start, off_t offset, int length);
-static unsigned long ccio_used_bytes = 0;
-static unsigned long ccio_used_pages = 0;
-static int ccio_cujo_bug = 0;
-
-static unsigned long ccio_alloc_size = 0;
-static unsigned long ccio_free_size = 0;
+static struct ioc *ioc_list;
+static int ioc_count;
 
 /**************************************************************
 *
@@ -227,55 +185,41 @@
 *   match the I/O TLB replacement policy.
 *
 ***************************************************************/
-#define PAGES_PER_RANGE 1	/* could increase this to 4 or 8 if needed */
 #define IOVP_SIZE PAGE_SIZE
 #define IOVP_SHIFT PAGE_SHIFT
 #define IOVP_MASK PAGE_MASK
 
 /* Convert from IOVP to IOVA and vice versa. */
 #define CCIO_IOVA(iovp,offset) ((iovp) | (offset))
-#define CCIO_IOVP(iova) ((iova) & ~(IOVP_SIZE-1) )
+#define CCIO_IOVP(iova) ((iova) & IOVP_MASK)
 
 #define PDIR_INDEX(iovp)    ((iovp)>>IOVP_SHIFT)
 #define MKIOVP(pdir_idx)    ((long)(pdir_idx) << IOVP_SHIFT)
 #define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset)
-
-/* CUJO20 KLUDGE start */
-#define CUJO_20_BITMASK    0x0ffff000	/* upper nibble is a don't care   */
-#define CUJO_20_STEP       0x10000000	/* inc upper nibble */
-#define CUJO_20_BADPAGE1   0x01003000	/* pages that hpmc on raven U+    */
-#define CUJO_20_BADPAGE2   0x01607000	/* pages that hpmc on firehawk U+ */
-#define CUJO_20_BADHVERS   0x6821	/* low nibble 1 is cujo rev 2.0 */
-#define CUJO_RAVEN_LOC     0xf1000000UL	/* cujo location on raven U+ */
-#define CUJO_FIREHAWK_LOC  0xf1604000UL	/* cujo location on firehawk U+ */
-/* CUJO20 KLUDGE end */
+#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
 
 /*
 ** Don't worry about the 150% average search length on a miss.
 ** If the search wraps around, and passes the res_hint, it will
 ** cause the kernel to panic anyhow.
 */
-
-/* ioa->res_hint = idx + (size >> 3); \ */
-
-#define CCIO_SEARCH_LOOP(ioa, idx, mask, size)  \
-       for(; res_ptr < res_end; ++res_ptr) \
-       { \
-               if(0 == ((*res_ptr) & mask)) { \
-                       *res_ptr |= mask; \
-                       idx = (int)((unsigned long)res_ptr - (unsigned long)ioa->res_map); \
-                       ioa->res_hint = 0;\
+#define CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size)  \
+       for(; res_ptr < res_end; ++res_ptr) { \
+               if(0 == (*res_ptr & *mask_ptr)) { \
+                       *res_ptr |= *mask_ptr; \
+                       res_idx = (int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \
+                       ioc->res_hint = res_idx + (size >> 3); \
                        goto resource_found; \
                } \
        }
 
-#define CCIO_FIND_FREE_MAPPING(ioa, idx, mask, size)  { \
-       u##size *res_ptr = (u##size *)&((ioa)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \
-       u##size *res_end = (u##size *)&(ioa)->res_map[ioa->res_size]; \
-       CCIO_SEARCH_LOOP(ioa, idx, mask, size); \
-       res_ptr = (u##size *)&(ioa)->res_map[0]; \
-       CCIO_SEARCH_LOOP(ioa, idx, mask, size); \
-}
+#define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \
+       u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \
+       u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \
+       u##size *mask_ptr = (u##size *)&mask; \
+       CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size); \
+       res_ptr = (u##size *)&(ioc)->res_map[0]; \
+       CCIO_SEARCH_LOOP(ioa, res_idx, mask_ptr, size);
 
 /*
 ** Find available bit in this ioa's resource map.
@@ -290,123 +234,132 @@
 ** o use different search for "large" (eg > 4 pages) or "very large"
 **   (eg > 16 pages) mappings.
 */
+
+/**
+ * ccio_alloc_range - Allocate pages in the ioc's resource map.
+ * @ioc: The I/O Controller.
+ * @pages_needed: The requested number of pages to be mapped into the
+ * I/O Pdir...
+ *
+ * This function searches the resource map of the ioc to locate a range
+ * of available pages for the requested size.
+ */
 static int
-ccio_alloc_range(struct ccio_device *ioa, size_t size)
+ccio_alloc_range(struct ioc *ioc, unsigned long pages_needed)
 {
 	int res_idx;
-	unsigned long mask, flags;
-	unsigned int pages_needed = size >> PAGE_SHIFT;
-
+	unsigned long mask;
+#ifdef CONFIG_PROC_FS
+	unsigned long cr_start = mfctl(16);
+#endif
+	
 	ASSERT(pages_needed);
-	ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT));
+	ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(pages_needed <= BITS_PER_LONG);
 
-	mask = (unsigned long) -1L;
- 	mask >>= BITS_PER_LONG - pages_needed;
-
-	DBG_RES(__FUNCTION__ " size: %d pages_needed %d pages_mask 0x%08lx\n", 
-		size, pages_needed, mask);
-
-	spin_lock_irqsave(&ioa->ccio_lock, flags);
+	mask = ~(~0UL >> pages_needed);
+     
+	DBG_RES("%s() size: %d pages_needed %d mask 0x%08lx\n", 
+		__FUNCTION__, size, pages_needed, mask);
 
 	/*
 	** "seek and ye shall find"...praying never hurts either...
-	** ggg sacrafices another 710 to the computer gods.
+	** ggg sacrifices another 710 to the computer gods.
 	*/
 
 	if(pages_needed <= 8) {
-		CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 8);
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8);
 	} else if(pages_needed <= 16) {
-		CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 16);
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 16);
 	} else if(pages_needed <= 32) {
-		CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 32);
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 32);
 #ifdef __LP64__
 	} else if(pages_needed <= 64) {
-		CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 64)
+		CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64);
 #endif
 	} else {
-		panic(__FILE__ ":" __FUNCTION__ "() Too many pages to map.\n");
+		panic(__FILE__ ": %s() Too many pages to map. pages_needed: %ld\n", 
+		      __FUNCTION__, pages_needed);
 	}
 
-#ifdef DUMP_RESMAP
-	dump_resmap();
-#endif
-	panic(__FILE__ ":" __FUNCTION__ "() I/O MMU is out of mapping resources\n");
+	panic(__FILE__ ": %s() I/O MMU is out of mapping resources.\n", 
+	      __FUNCTION__);
 	
 resource_found:
 	
-	DBG_RES(__FUNCTION__ " res_idx %d mask 0x%08lx res_hint: %d\n",
-		res_idx, mask, ioa->res_hint);
+	DBG_RES("%s() res_idx %d mask 0x%08lx res_hint: %d\n",
+		__FUNCTION__, res_idx, mask, ioc->res_hint);
 
-	ccio_used_pages += pages_needed;
-	ccio_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1);
-
-	spin_unlock_irqrestore(&ioa->ccio_lock, flags);
+#ifdef CONFIG_PROC_FS
+	{
+		unsigned long cr_end = mfctl(16);
+		unsigned long tmp = cr_end - cr_start;
+		/* check for roll over */
+		cr_start = (cr_end < cr_start) ?  -(tmp) : (tmp);
+	}
+	ioc->avg_search[ioc->avg_idx++] = cr_start;
+	ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1;
 
-#ifdef DUMP_RESMAP
-	dump_resmap();
+	ioc->used_pages += pages_needed;
 #endif
 
 	/* 
-	** return the bit address (convert from byte to bit).
+	** return the bit address.
 	*/
-	return (res_idx << 3);
+	return res_idx << 3;
 }
 
-
-#define CCIO_FREE_MAPPINGS(ioa, idx, mask, size) \
-        u##size *res_ptr = (u##size *)&((ioa)->res_map[idx + (((size >> 3) - 1) & ~((size >> 3) - 1))]); \
-        ASSERT((*res_ptr & mask) == mask); \
-        *res_ptr &= ~mask;
-
-/*
-** clear bits in the ioa's resource map
-*/
+#define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \
+        u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \
+	u##size *mask_ptr = (u##size *)&mask; \
+        ASSERT((*res_ptr & *mask_ptr) == *mask_ptr); \
+        *res_ptr &= ~(*mask_ptr);
+
+/**
+ * ccio_free_range - Free pages from the ioc's resource map.
+ * @ioc: The I/O Controller.
+ * @iova: The I/O Virtual Address.
+ * @pages_mapped: The requested number of pages to be freed from the
+ * I/O Pdir.
+ *
+ * This function frees the resouces allocated for the iova.
+ */
 static void
-ccio_free_range(struct ccio_device *ioa, dma_addr_t iova, size_t size)
+ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
 {
-	unsigned long mask, flags;
+	unsigned long mask;
 	unsigned long iovp = CCIO_IOVP(iova);
-	unsigned int res_idx = PDIR_INDEX(iovp)>>3;
-	unsigned int pages_mapped = (size >> IOVP_SHIFT) + !!(size & ~IOVP_MASK);
+	unsigned int res_idx = PDIR_INDEX(iovp) >> 3;
 
-	ASSERT(pages_needed);
-	ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT));
+	ASSERT(pages_mapped);
+	ASSERT((pages_mapped * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(pages_mapped <= BITS_PER_LONG);
 
-	mask = (unsigned long) -1L;
- 	mask >>= BITS_PER_LONG - pages_mapped;
+	mask = ~(~0UL >> pages_mapped);
 
-	DBG_RES(__FUNCTION__ " res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", 
-		res_idx, size, pages_mapped, mask);
+	DBG_RES("%s():  res_idx: %d pages_mapped %d mask 0x%08lx\n", 
+		__FUNCTION__, res_idx, pages_mapped, mask);
 
-	spin_lock_irqsave(&ioa->ccio_lock, flags);
+#ifdef CONFIG_PROC_FS
+	ioc->used_pages -= pages_mapped;
+#endif
 
 	if(pages_mapped <= 8) {
-		CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 8);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8);
 	} else if(pages_mapped <= 16) {
-		CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 16);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 16);
 	} else if(pages_mapped <= 32) {
-		CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 32);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 32);
 #ifdef __LP64__
 	} else if(pages_mapped <= 64) {
-		CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 64);
+		CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64);
 #endif
 	} else {
-		panic(__FILE__ ":" __FUNCTION__ "() Too many pages to unmap.\n");
+		panic(__FILE__ ":%s() Too many pages to unmap.\n", 
+		      __FUNCTION__);
 	}
-	
-	ccio_used_pages -= (pages_mapped ? pages_mapped : 1);
-	ccio_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1);
-
-	spin_unlock_irqrestore(&ioa->ccio_lock, flags);
-
-#ifdef DUMP_RESMAP
-	dump_resmap();
-#endif
 }
 
-
 /****************************************************************
 **
 **          CCIO dma_ops support routines
@@ -416,7 +369,6 @@
 typedef unsigned long space_t;
 #define KERNEL_SPACE 0
 
-
 /*
 ** DMA "Page Type" and Hints 
 ** o if SAFE_DMA isn't set, mapping is for FAST_DMA. SAFE_DMA should be
@@ -466,32 +418,35 @@
 	[PCI_DMA_NONE]           0,            /* not valid */
 };
 
-/*
-** Initialize an I/O Pdir entry
-**
-** Given a virtual address (vba, arg2) and space id, (sid, arg1),
-** load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir
-** entry consists of 8 bytes as shown below (MSB == bit 0):
-**
-**
-** WORD 0:
-** +------+----------------+-----------------------------------------------+
-** | Phys | Virtual Index  |               Phys                            |
-** | 0:3  |     0:11       |               4:19                            |
-** |4 bits|   12 bits      |              16 bits                          |
-** +------+----------------+-----------------------------------------------+
-** WORD 1:
-** +-----------------------+-----------------------------------------------+
-** |      Phys    |  Rsvd  | Prefetch |Update |Rsvd  |Lock  |Safe  |Valid  |
-** |     20:39    |        | Enable   |Enable |      |Enable|DMA   |       |
-** |    20 bits   | 5 bits | 1 bit    |1 bit  |2 bits|1 bit |1 bit |1 bit  |
-** +-----------------------+-----------------------------------------------+
-**
-** The virtual index field is filled with the results of the LCI
-** (Load Coherence Index) instruction.  The 8 bits used for the virtual
-** index are bits 12:19 of the value returned by LCI.
-*/
-
+/**
+ * ccio_io_pdir_entry - Initialize an I/O Pdir.
+ * @pdir_ptr: A pointer into I/O Pdir.
+ * @sid: The Space Identifier.
+ * @vba: The virtual address.
+ * @hints: The DMA Hint.
+ *
+ * Given a virtual address (vba, arg2) and space id, (sid, arg1),
+ * load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir
+ * entry consists of 8 bytes as shown below (MSB == bit 0):
+ *
+ *
+ * WORD 0:
+ * +------+----------------+-----------------------------------------------+
+ * | Phys | Virtual Index  |               Phys                            |
+ * | 0:3  |     0:11       |               4:19                            |
+ * |4 bits|   12 bits      |              16 bits                          |
+ * +------+----------------+-----------------------------------------------+
+ * WORD 1:
+ * +-----------------------+-----------------------------------------------+
+ * |      Phys    |  Rsvd  | Prefetch |Update |Rsvd  |Lock  |Safe  |Valid  |
+ * |     20:39    |        | Enable   |Enable |      |Enable|DMA   |       |
+ * |    20 bits   | 5 bits | 1 bit    |1 bit  |2 bits|1 bit |1 bit |1 bit  |
+ * +-----------------------+-----------------------------------------------+
+ *
+ * The virtual index field is filled with the results of the LCI
+ * (Load Coherence Index) instruction.  The 8 bits used for the virtual
+ * index are bits 12:19 of the value returned by LCI.
+ */ 
 void CCIO_INLINE
 ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, void * vba, unsigned long hints)
 {
@@ -499,8 +454,7 @@
 	register unsigned long ci; /* coherent index */
 
 	/* We currently only support kernel addresses */
-	ASSERT(sid == 0);
-	ASSERT(((unsigned long) vba & 0xf0000000UL) == 0xc0000000UL);
+	ASSERT(sid == KERNEL_SPACE);
 
 	mtsp(sid,1);
 
@@ -524,7 +478,7 @@
 	** and deposit them
 	*/
 	asm volatile ("extrd,u %1,15,4,%0" : "=r" (ci) : "r" (pa));
-	asm volatile ("extrd,u %1,31,16,%0" : "+r" (ci) : "r" (ci));
+	asm volatile ("extrd,u %1,31,16,%0" : "+r" (pa) : "r" (pa));
 	asm volatile ("depd  %1,35,4,%0" : "+r" (pa) : "r" (ci));
 #else
 	pa = 0;
@@ -556,31 +510,39 @@
 	asm volatile("sync");
 }
 
-
-/*
-** Remove stale entries from the I/O TLB.
-** Need to do this whenever an entry in the PDIR is marked invalid.
-*/
+/**
+ * ccio_clear_io_tlb - Remove stale entries from the I/O TLB.
+ * @ioc: The I/O Controller.
+ * @iovp: The I/O Virtual Page.
+ * @byte_cnt: The requested number of bytes to be freed from the I/O Pdir.
+ *
+ * Purge invalid I/O PDIR entries from the I/O TLB.
+ *
+ * FIXME: Can we change the byte_cnt to pages_mapped?
+ */
 static CCIO_INLINE void
-ccio_clear_io_tlb( struct ccio_device *d, dma_addr_t iovp, size_t byte_cnt)
+ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt)
 {
-	u32 chain_size = 1 << d->chainid_shift;
+	u32 chain_size = 1 << ioc->chainid_shift;
 
-	iovp &= ~(IOVP_SIZE-1);	/* clear offset bits, just want pagenum */
+	iovp &= IOVP_MASK;	/* clear offset bits, just want pagenum */
 	byte_cnt += chain_size;
 
-        while (byte_cnt > chain_size) {
-		WRITE_U32(CMD_TLB_PURGE | iovp, &d->ccio_hpa->io_command);
-                iovp += chain_size;
+	while(byte_cnt > chain_size) {
+		WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_hpa->io_command);
+		iovp += chain_size;
 		byte_cnt -= chain_size;
-        }
+      }
 }
 
-
-/***********************************************************
+/**
+ * ccio_mark_invalid - Mark the I/O Pdir entries invalid.
+ * @ioc: The I/O Controller.
+ * @iova: The I/O Virtual Address.
+ * @byte_cnt: The requested number of bytes to be freed from the I/O Pdir.
  *
- * Mark the I/O Pdir entries invalid and blow away the
- * corresponding I/O TLB entries.
+ * Mark the I/O Pdir entries invalid and blow away the corresponding I/O
+ * TLB entries.
  *
  * FIXME: at some threshhold it might be "cheaper" to just blow
  *        away the entire I/O TLB instead of individual entries.
@@ -588,25 +550,25 @@
  * FIXME: Uturn has 256 TLB entries. We don't need to purge every
  *        PDIR entry - just once for each possible TLB entry.
  *        (We do need to maker I/O PDIR entries invalid regardless).
- ***********************************************************/
+ *
+ * FIXME: Can we change byte_cnt to pages_mapped?
+ */ 
 static CCIO_INLINE void
-ccio_mark_invalid(struct ccio_device *d, dma_addr_t iova, size_t byte_cnt)
+ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
 {
-	u32 iovp = (u32) CCIO_IOVP(iova);
+	u32 iovp = (u32)CCIO_IOVP(iova);
 	size_t saved_byte_cnt;
 
 	/* round up to nearest page size */
-	saved_byte_cnt = byte_cnt = (byte_cnt + IOVP_SIZE - 1) & IOVP_MASK;
+	saved_byte_cnt = byte_cnt = ROUNDUP(byte_cnt, IOVP_SIZE);
 
-	while (byte_cnt > 0) {
+	while(byte_cnt > 0) {
 		/* invalidate one page at a time */
 		unsigned int idx = PDIR_INDEX(iovp);
-		char *pdir_ptr = (char *) &(d->pdir_base[idx]);
-
-		ASSERT( idx < (d->pdir_size/sizeof(u64)));
-
-		pdir_ptr[7] = 0;	/* clear only VALID bit */
+		char *pdir_ptr = (char *) &(ioc->pdir_base[idx]);
 
+		ASSERT(idx < (ioc->pdir_size / sizeof(u64)));
+		pdir_ptr[7] = 0;	/* clear only VALID bit */ 
 		/*
 		** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
 		**   PCX-U/U+ do. (eg C200/C240)
@@ -622,232 +584,485 @@
 	}
 
 	asm volatile("sync");
-	ccio_clear_io_tlb(d, CCIO_IOVP(iova), saved_byte_cnt);
+	ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt);
 }
 
-
 /****************************************************************
 **
 **          CCIO dma_ops
 **
 *****************************************************************/
 
-void __init ccio_init(void)
-{
-	register_driver(ccio_drivers_for);
-}
-
-
-static int ccio_dma_supported( struct pci_dev *dev, u64 mask)
+/**
+ * ccio_dma_supported - Verify the IOMMU supports the DMA address range.
+ * @dev: The PCI device.
+ * @mask: A bit mask describing the DMA address range of the device.
+ *
+ * This function implements the pci_dma_supported function.
+ */
+static int 
+ccio_dma_supported(struct pci_dev *dev, u64 mask)
 {
-	if (dev == NULL) {
-		printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
+	if(dev == NULL) {
+		printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
 		BUG();
-		return(0);
+		return 0;
 	}
 
 	dev->dma_mask = mask;   /* save it */
 
 	/* only support 32-bit devices (ie PCI/GSC) */
-	return((int) (mask >= 0xffffffffUL));
+	return (int)(mask == 0xffffffffUL);
 }
 
-/*
-** Dump a hex representation of the resource map.
-*/
-
-#ifdef DUMP_RESMAP
-static 
-void dump_resmap()
-{
-	struct ccio_device *ioa = ccio_list;
-	unsigned long *res_ptr = (unsigned long *)ioa->res_map;
-	unsigned long i = 0;
-
-	printk("res_map: ");
-	for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr)
-		printk("%08lx ", *res_ptr);
-
-	printk("\n");
-}
-#endif
-
-/*
-** map_single returns a fully formed IOVA
-*/
-static dma_addr_t ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
+/**
+ * ccio_map_single - Map an address range into the IOMMU.
+ * @dev: The PCI device.
+ * @addr: The start address of the DMA region.
+ * @size: The length of the DMA region.
+ * @direction: The direction of the DMA transaction (to/from device).
+ *
+ * This function implements the pci_map_single function.
+ */
+static dma_addr_t 
+ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
 {
-	struct ccio_device *ioa = ccio_list;  /* FIXME : see Multi-IOC below */
+	int idx;
+	struct ioc *ioc;
+	unsigned long flags;
 	dma_addr_t iovp;
 	dma_addr_t offset;
 	u64 *pdir_start;
 	unsigned long hint = hint_lookup[direction];
-	int idx;
+
+	ASSERT(dev);
+	ASSERT(dev->sysdata);
+	ASSERT(HBA_DATA(dev->sysdata)->iommu);
+	ioc = GET_IOC(dev);
 
 	ASSERT(size > 0);
 
 	/* save offset bits */
-	offset = ((dma_addr_t) addr) & ~IOVP_MASK;
+	offset = ((unsigned long) addr) & ~IOVP_MASK;
 
 	/* round up to nearest IOVP_SIZE */
-	size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK;
+	size = ROUNDUP(size + offset, IOVP_SIZE);
+	spin_lock_irqsave(&ioc->res_lock, flags);
+
+#ifdef CONFIG_PROC_FS
+	ioc->msingle_calls++;
+	ioc->msingle_pages += size >> IOVP_SHIFT;
+#endif
 
-	idx = ccio_alloc_range(ioa, size);
-	iovp = (dma_addr_t) MKIOVP(idx);
+	idx = ccio_alloc_range(ioc, (size >> IOVP_SHIFT));
+	iovp = (dma_addr_t)MKIOVP(idx);
 
-	DBG_RUN(__FUNCTION__ " 0x%p -> 0x%lx", addr, (long) iovp | offset);
+	pdir_start = &(ioc->pdir_base[idx]);
 
-	pdir_start = &(ioa->pdir_base[idx]);
+	DBG_RUN("%s() 0x%p -> 0x%lx size: %0x%x\n",
+		__FUNCTION__, addr, (long)iovp | offset, size);
 
 	/* If not cacheline aligned, force SAFE_DMA on the whole mess */
-	if ((size % L1_CACHE_BYTES) || ((unsigned long) addr % L1_CACHE_BYTES))
+	if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
 		hint |= HINT_SAFE_DMA;
 
-	/* round up to nearest IOVP_SIZE */
-	size = (size + IOVP_SIZE - 1) & IOVP_MASK;
-
-	while (size > 0) {
-
+	while(size > 0) {
 		ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint);
 
 		DBG_RUN(" pdir %p %08x%08x\n",
 			pdir_start,
 			(u32) (((u32 *) pdir_start)[0]),
-			(u32) (((u32 *) pdir_start)[1])
-			);
+			(u32) (((u32 *) pdir_start)[1]));
+		++pdir_start;
 		addr += IOVP_SIZE;
 		size -= IOVP_SIZE;
-		pdir_start++;
 	}
+
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
+
 	/* form complete address */
 	return CCIO_IOVA(iovp, offset);
 }
 
-
-static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction)
-{
-#ifdef FIXME
-/* Multi-IOC (ie N-class) :  need to lookup IOC from dev
-** o If we can't know about lba PCI data structs, that eliminates ->sysdata.
-** o walking up pcidev->parent dead ends at elroy too
-** o leaves hashing dev->bus->number into some lookup.
-**   (may only work for N-class)
-*/
-	struct ccio_device *ioa = dev->sysdata
-#else
-	struct ccio_device *ioa = ccio_list;
-#endif
-	dma_addr_t offset;
+/**
+ * ccio_unmap_single - Unmap an address range from the IOMMU.
+ * @dev: The PCI device.
+ * @addr: The start address of the DMA region.
+ * @size: The length of the DMA region.
+ * @direction: The direction of the DMA transaction (to/from device).
+ *
+ * This function implements the pci_unmap_single function.
+ */
+static void 
+ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, 
+		  int direction)
+{
+	struct ioc *ioc;
+	unsigned long flags; 
+	dma_addr_t offset = iova & ~IOVP_MASK;
 	
-	offset = iova & ~IOVP_MASK;
-
-	/* round up to nearest IOVP_SIZE */
-	size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK;
+	ASSERT(dev);
+	ASSERT(dev->sysdata);
+	ASSERT(HBA_DATA(dev->sysdata)->iommu);
+	ioc = GET_IOC(dev);
+
+	DBG_RUN("%s() iovp 0x%lx/%x\n",
+		__FUNCTION__, (long)iova, size);
+
+	iova ^= offset;        /* clear offset bits */
+	size += offset;
+	size = ROUNDUP(size, IOVP_SIZE);
 
-	/* Mask off offset */
-	iova &= IOVP_MASK;
+	spin_lock_irqsave(&ioc->res_lock, flags);
 
-	DBG_RUN(__FUNCTION__ " iovp 0x%lx\n", (long) iova);
-
-#ifdef DELAYED_RESOURCE_CNT
-	if (ioa->saved_cnt < DELAYED_RESOURCE_CNT) {
-		ioa->saved_iova[ioa->saved_cnt] = iova;
-		ioa->saved_size[ioa->saved_cnt] = size;
-		ccio_saved_cnt++;
-	} else {
-		do {
+#ifdef CONFIG_PROC_FS
+	ioc->usingle_calls++;
+	ioc->usingle_pages += size >> IOVP_SHIFT;
 #endif
-			ccio_mark_invalid(ioa, iova, size);
-			ccio_free_range(ioa, iova, size);
 
-#ifdef DELAYED_RESOURCE_CNT
-			d->saved_cnt--;
-			iova = ioa->saved_iova[ioa->saved_cnt];
-			size = ioa->saved_size[ioa->saved_cnt];
-		} while (ioa->saved_cnt)
-	}
-#endif
+	ccio_mark_invalid(ioc, iova, size);
+	ccio_free_range(ioc, iova, (size >> IOVP_SHIFT));
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
 }
 
-
-static void * ccio_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+/**
+ * ccio_alloc_consistent - Allocate a consistent DMA mapping.
+ * @dev: The PCI device.
+ * @size: The length of the DMA region.
+ * @dma_handle: The DMA address handed back to the device (not the cpu).
+ *
+ * This function implements the pci_alloc_consistent function.
+ */
+static void * 
+ccio_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_handle)
 {
-	void *ret;
-	unsigned long flags;
-	struct ccio_device *ioa = ccio_list;
-
-	DBG_RUN(__FUNCTION__ " size 0x%x\n",  size);
-
+      void *ret;
 #if 0
 /* GRANT Need to establish hierarchy for non-PCI devs as well
 ** and then provide matching gsc_map_xxx() functions for them as well.
 */
-	if (!hwdev) {
+	if(!hwdev) {
 		/* only support PCI */
 		*dma_handle = 0;
 		return 0;
 	}
 #endif
-	spin_lock_irqsave(&ioa->ccio_lock, flags);
-	ccio_alloc_size += get_order(size);
-	spin_unlock_irqrestore(&ioa->ccio_lock, flags);
-
         ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size));
 
 	if (ret) {
 		memset(ret, 0, size);
-		*dma_handle = ccio_map_single(hwdev, ret, size, PCI_DMA_BIDIRECTIONAL);
+		*dma_handle = ccio_map_single(dev, ret, size, PCI_DMA_BIDIRECTIONAL);
 	}
-	DBG_RUN(__FUNCTION__ " ret %p\n",  ret);
 
 	return ret;
 }
 
-
-static void ccio_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
+/**
+ * ccio_free_consistent - Free a consistent DMA mapping.
+ * @dev: The PCI device.
+ * @size: The length of the DMA region.
+ * @cpu_addr: The cpu address returned from the ccio_alloc_consistent.
+ * @dma_handle: The device address returned from the ccio_alloc_consistent.
+ *
+ * This function implements the pci_free_consistent function.
+ */
+static void 
+ccio_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr, 
+		     dma_addr_t dma_handle)
 {
-	unsigned long flags;
-	struct ccio_device *ioa = ccio_list;
+	ccio_unmap_single(dev, dma_handle, size, 0);
+	free_pages((unsigned long)cpu_addr, get_order(size));
+}
 
-	spin_lock_irqsave(&ioa->ccio_lock, flags);
-	ccio_free_size += get_order(size);
-	spin_unlock_irqrestore(&ioa->ccio_lock, flags);
+/*
+** Since 0 is a valid pdir_base index value, can't use that
+** to determine if a value is valid or not. Use a flag to indicate
+** the SG list entry contains a valid pdir index.
+*/
+#define PIDE_FLAG 0x80000000UL
 
-	ccio_unmap_single(hwdev, dma_handle, size, 0);
-	free_pages((unsigned long) vaddr, get_order(size));
+/**
+ * ccio_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir.
+ * @ioc: The I/O Controller.
+ * @startsg: The scatter/gather list of coalesced chunks.
+ * @nents: The number of entries in the scatter/gather list.
+ * @hint: The DMA Hint.
+ *
+ * This function inserts the coalesced scatter/gather list chunks into the
+ * I/O Controller's I/O Pdir.
+ */ 
+static CCIO_INLINE int
+ccio_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, 
+	       unsigned long hint)
+{
+	struct scatterlist *dma_sg = startsg;	/* pointer to current DMA */
+	int n_mappings = 0;
+	u64 *pdirp = 0;
+	unsigned long dma_offset = 0;
+
+	dma_sg--;
+	while (nents-- > 0) {
+		int cnt = sg_dma_len(startsg);
+		sg_dma_len(startsg) = 0;
+
+		DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", nents,
+			   (unsigned long)sg_dma_address(startsg), cnt,
+			   startsg->address, startsg->length
+		);
+
+		/*
+		** Look for the start of a new DMA stream
+		*/
+		if(sg_dma_address(startsg) & PIDE_FLAG) {
+			u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG;
+			dma_offset = (unsigned long) pide & ~IOVP_MASK;
+			sg_dma_address(startsg) = 0;
+			dma_sg++;
+			sg_dma_address(dma_sg) = pide;
+			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
+			n_mappings++;
+		}
+
+		/*
+		** Look for a VCONTIG chunk
+		*/
+		if (cnt) {
+			unsigned long vaddr = (unsigned long)startsg->address;
+			ASSERT(pdirp);
+
+			/* Since multiple Vcontig blocks could make up
+			** one DMA stream, *add* cnt to dma_len.
+			*/
+			sg_dma_len(dma_sg) += cnt;
+			cnt += dma_offset;
+			dma_offset=0;	/* only want offset on first chunk */
+			cnt = ROUNDUP(cnt, IOVP_SIZE);
+#ifdef CONFIG_PROC_FS
+			ioc->msg_pages += cnt >> IOVP_SHIFT;
+#endif
+			do {
+				ccio_io_pdir_entry(pdirp, KERNEL_SPACE, 
+						   (void *)vaddr, hint);
+				vaddr += IOVP_SIZE;
+				cnt -= IOVP_SIZE;
+				pdirp++;
+			} while (cnt > 0);
+		}
+		startsg++;
+	}
+	return(n_mappings);
 }
 
+/*
+** First pass is to walk the SG list and determine where the breaks are
+** in the DMA stream. Allocates PDIR entries but does not fill them.
+** Returns the number of DMA chunks.
+**
+** Doing the fill seperate from the coalescing/allocation keeps the
+** code simpler. Future enhancement could make one pass through
+** the sglist do both.
+*/
 
-static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+static CCIO_INLINE int
+ccio_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents)
 {
-	int tmp = nents;
+	struct scatterlist *vcontig_sg;    /* VCONTIG chunk head */
+	unsigned long vcontig_len;         /* len of VCONTIG chunk */
+	unsigned long vcontig_end;
+	struct scatterlist *dma_sg;        /* next DMA stream head */
+	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
+	int n_mappings = 0;
+
+	while (nents > 0) {
+
+		/*
+		** Prepare for first/next DMA stream
+		*/
+		dma_sg = vcontig_sg = startsg;
+		dma_len = vcontig_len = vcontig_end = startsg->length;
+		vcontig_end += (unsigned long) startsg->address;
+		dma_offset = (unsigned long) startsg->address & ~IOVP_MASK;
+
+		/* PARANOID: clear entries */
+		sg_dma_address(startsg) = 0;
+		sg_dma_len(startsg) = 0;
+
+		/*
+		** This loop terminates one iteration "early" since
+		** it's always looking one "ahead".
+		*/
+		while(--nents > 0) {
+			unsigned long startsg_end;
 
-	DBG_RUN(KERN_WARNING __FUNCTION__ " START\n");
+			startsg++;
+			startsg_end = (unsigned long)startsg->address + 
+				startsg->length;
+
+			/* PARANOID: clear entries */
+			sg_dma_address(startsg) = 0;
+			sg_dma_len(startsg) = 0;
+
+			/*
+			** First make sure current dma stream won't
+			** exceed DMA_CHUNK_SIZE if we coalesce the
+			** next entry.
+			*/   
+			if(ROUNDUP(dma_len + dma_offset + startsg->length,
+				   IOVP_SIZE) > DMA_CHUNK_SIZE)
+				break;
+
+			/*
+			** Append the next transaction?
+			*/
+			if(vcontig_end == (unsigned long) startsg->address) {
+				vcontig_len += startsg->length;
+				vcontig_end += startsg->length;
+				dma_len     += startsg->length;
+				continue;
+			}
+
+			/*
+			** Not virtually contigous.
+			** Terminate prev chunk.
+			** Start a new chunk.
+			**
+			** Once we start a new VCONTIG chunk, dma_offset
+			** can't change. And we need the offset from the first
+			** chunk - not the last one. Ergo Successive chunks
+			** must start on page boundaries and dove tail
+			** with it's predecessor.
+			*/
+			sg_dma_len(vcontig_sg) = vcontig_len;
+
+			vcontig_sg = startsg;
+			vcontig_len = startsg->length;
+			break;
+		}
 
-        /* KISS: map each buffer seperately. */
-	while (nents) {
-		sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction);
-		sg_dma_len(sglist) = sglist->length;
-		nents--;
-		sglist++;
+		/*
+		** End of DMA Stream
+		** Terminate last VCONTIG block.
+		** Allocate space for DMA stream.
+		*/
+		sg_dma_len(vcontig_sg) = vcontig_len;
+		dma_len = ROUNDUP(dma_len + dma_offset, IOVP_SIZE);
+		sg_dma_address(dma_sg) =
+			PIDE_FLAG 
+			| (ccio_alloc_range(ioc, (dma_len >> IOVP_SHIFT)) << IOVP_SHIFT)
+			| dma_offset;
+		n_mappings++;
 	}
 
-	DBG_RUN(KERN_WARNING __FUNCTION__ " DONE\n");
-	return tmp;
+	return n_mappings;
 }
 
-
-static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
+/**
+ * ccio_map_sg - Map the scatter/gather list into the IOMMU.
+ * @dev: The PCI device.
+ * @sglist: The scatter/gather list to be mapped in the IOMMU.
+ * @nents: The number of entries in the scatter/gather list.
+ * @direction: The direction of the DMA transaction (to/from device).
+ *
+ * This function implements the pci_map_sg function.
+ */
+static int
+ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, 
+	    int direction)
 {
-	DBG_RUN(KERN_WARNING __FUNCTION__ " : unmapping %d entries\n", nents);
-	while (nents) {
-		ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
-		nents--;
-		sglist++;
+	struct ioc *ioc;
+	int coalesced, filled = 0;
+	unsigned long flags;
+	unsigned long hint = hint_lookup[direction];
+	
+	ASSERT(dev);
+	ASSERT(dev->sysdata);
+	ASSERT(HBA_DATA(dev->sysdata)->iommu);
+	ioc = GET_IOC(dev);
+	
+	DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+
+	/* Fast path single entry scatterlists. */
+	if(nents == 1) {
+		sg_dma_address(sglist)= ccio_map_single(dev, sglist->address,
+							sglist->length, 
+							direction);
+		sg_dma_len(sglist)= sglist->length;
+		return 1;
 	}
-	return;
+	
+	spin_lock_irqsave(&ioc->res_lock, flags);
+
+#ifdef CONFIG_PROC_FS
+	ioc->msg_calls++;
+#endif
+
+	/*
+	** First coalesce the chunks and allocate I/O pdir space
+	**
+	** If this is one DMA stream, we can properly map using the
+	** correct virtual address associated with each DMA page.
+	** w/o this association, we wouldn't have coherent DMA!
+	** Access to the virtual address is what forces a two pass algorithm.
+	*/
+	coalesced = ccio_coalesce_chunks(ioc, sglist, nents);
+
+	/*
+	** Program the I/O Pdir
+	**
+	** map the virtual addresses to the I/O Pdir
+	** o dma_address will contain the pdir index
+	** o dma_len will contain the number of bytes to map 
+	** o address contains the virtual address.
+	*/
+	filled = ccio_fill_pdir(ioc, sglist, nents, hint);
+
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+	ASSERT(coalesced == filled);
+	DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
+
+	return filled;
 }
 
+/**
+ * ccio_unmap_sg - Unmap the scatter/gather list from the IOMMU.
+ * @dev: The PCI device.
+ * @sglist: The scatter/gather list to be unmapped from the IOMMU.
+ * @nents: The number of entries in the scatter/gather list.
+ * @direction: The direction of the DMA transaction (to/from device).
+ *
+ * This function implements the pci_unmap_sg function.
+ */
+static void 
+ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, 
+	      int direction)
+{
+	struct ioc *ioc;
+
+	ASSERT(dev);
+	ASSERT(dev->sysdata);
+	ASSERT(HBA_DATA(dev->sysdata)->iommu);
+	ioc = GET_IOC(dev);
+
+	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
+		__FUNCTION__, nents, sglist->address, sglist->length);
+
+#ifdef CONFIG_PROC_FS
+	ioc->usg_calls++;
+#endif
+
+	while(sg_dma_len(sglist) && nents--) {
+
+#ifdef CONFIG_PROC_FS
+		ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
+#endif
+		ccio_unmap_single(dev, sg_dma_address(sglist),
+				  sg_dma_len(sglist), direction);
+		++sglist;
+	}
+
+	DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents);
+}
 
 static struct pci_dma_ops ccio_ops = {
 	ccio_dma_supported,
@@ -861,6 +1076,201 @@
 	NULL,                   /* dma_sync_sg     : ditto */
 };
 
+#ifdef CONFIG_PROC_FS
+static int proc_append(char *src, int len, char **dst, off_t *offset, int *max)
+{
+	if (len < *offset) {
+		*offset -= len;
+		return 0;
+	}
+	if (*offset > 0) {
+		src += *offset;
+		len -= *offset;
+		*offset = 0;
+	}
+	if (len > *max) {
+		len = *max;
+	}
+	memcpy(*dst, src, len);
+	*dst += len;
+	*max -= len;
+	return (*max == 0);
+}
+
+static int ccio_proc_info(char *buf, char **start, off_t offset, int count,
+			  int *eof, void *data)
+{
+	int max = count;
+	char tmp[80]; /* width of an ANSI-standard terminal */
+	struct ioc *ioc = ioc_list;
+
+	while (ioc != NULL) {
+		unsigned int total_pages = ioc->res_size << 3;
+		unsigned long avg = 0, min, max;
+		int j, len;
+
+		len = sprintf(tmp, "%s\n", ioc->name);
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		len = sprintf(tmp, "Cujo 2.0 bug    : %s\n",
+			      (ioc->cujo20_bug ? "yes" : "no"));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		len = sprintf(tmp, "IO PDIR size    : %d bytes (%d entries)\n",
+			      total_pages * 8, total_pages);
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		len = sprintf(tmp, "IO PDIR entries : %ld free  %ld used (%d%%)\n",
+			      total_pages - ioc->used_pages, ioc->used_pages,
+			      (int)(ioc->used_pages * 100 / total_pages));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		len = sprintf(tmp, "Resource bitmap : %d bytes (%d pages)\n", 
+			ioc->res_size, total_pages);
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+		min = max = ioc->avg_search[0];
+		for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) {
+			avg += ioc->avg_search[j];
+			if(ioc->avg_search[j] > max) 
+				max = ioc->avg_search[j];
+			if(ioc->avg_search[j] < min) 
+				min = ioc->avg_search[j];
+		}
+		avg /= CCIO_SEARCH_SAMPLE;
+		len = sprintf(tmp, "  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+			      min, avg, max);
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+
+		len = sprintf(tmp, "pci_map_single(): %8ld calls  %8ld pages (avg %d/1000)\n",
+			      ioc->msingle_calls, ioc->msingle_pages,
+			      (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		
+
+		/* KLUGE - unmap_sg calls unmap_single for each mapped page */
+		min = ioc->usingle_calls - ioc->usg_calls;
+		max = ioc->usingle_pages - ioc->usg_pages;
+		len = sprintf(tmp, "pci_unmap_single: %8ld calls  %8ld pages (avg %d/1000)\n",
+			      min, max, (int)((max * 1000)/min));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+ 
+		len = sprintf(tmp, "pci_map_sg()    : %8ld calls  %8ld pages (avg %d/1000)\n",
+			      ioc->msg_calls, ioc->msg_pages,
+			      (int)((ioc->msg_pages * 1000)/ioc->msg_calls));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+		len = sprintf(tmp, "pci_unmap_sg()  : %8ld calls  %8ld pages (avg %d/1000)\n\n\n",
+			      ioc->usg_calls, ioc->usg_pages,
+			      (int)((ioc->usg_pages * 1000)/ioc->usg_calls));
+		if (proc_append(tmp, len, &buf, &offset, &count))
+			break;
+
+		ioc = ioc->next;
+	}
+
+	if (count == 0) {
+		*eof = 1;
+	}
+	return (max - count);
+}
+
+static int ccio_resource_map(char *buf, char **start, off_t offset, int len,
+			     int *eof, void *data)
+{
+	struct ioc *ioc = ioc_list;
+
+	buf[0] = '\0';
+	while (ioc != NULL) {
+		u32 *res_ptr = (u32 *)ioc->res_map;
+		int j;
+
+		for (j = 0; j < (ioc->res_size / sizeof(u32)); j++) {
+			if ((j & 7) == 0)
+				strcat(buf,"\n   ");
+			sprintf(buf, "%s %08x", buf, *res_ptr);
+			res_ptr++;
+		}
+		strcat(buf, "\n\n");
+		ioc = ioc->next;
+		break; /* XXX - remove me */
+	}
+
+	return strlen(buf);
+}
+#endif
+
+/**
+ * ccio_find_ioc - Find the ioc in the ioc_list
+ * @hw_path: The hardware path of the ioc.
+ *
+ * This function searches the ioc_list for an ioc that matches
+ * the provide hardware path.
+ */
+static struct ioc * ccio_find_ioc(int hw_path)
+{
+	int i;
+	struct ioc *ioc;
+
+	ioc = ioc_list;
+	for (i = 0; i < ioc_count; i++) {
+		if (ioc->hw_path == hw_path)
+			return ioc;
+
+		ioc = ioc->next;
+	}
+
+	return NULL;
+}
+
+/**
+ * ccio_get_iommu - Find the iommu which controls this device
+ * @dev: The parisc device.
+ *
+ * This function searches through the registerd IOMMU's and returns the
+ * appropriate IOMMU for the device based upon the devices hardware path.
+ */
+void * ccio_get_iommu(const struct parisc_device *dev)
+{
+	dev = find_pa_parent_type(dev, HPHW_IOA);
+	if (!dev)
+		return NULL;
+
+	return ccio_find_ioc(dev->hw_path);
+}
+
+#define CUJO_20_STEP       0x10000000	/* inc upper nibble */
+
+/* Cujo 2.0 has a bug which will silently corrupt data being transferred
+ * to/from certain pages.  To avoid this happening, we mark these pages
+ * as `used', and ensure that nothing will try to allocate from them.
+ */
+void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp)
+{
+	unsigned int idx;
+	struct ioc *ioc = ccio_get_iommu(dev);
+	u8 *res_ptr;
+
+#ifdef CONFIG_PROC_FS
+	ioc->cujo20_bug = 1;
+#endif
+	res_ptr = ioc->res_map;
+	idx = PDIR_INDEX(iovp) >> 3;
+
+	while (idx < ioc->res_size) {
+ 		res_ptr[idx] |= 0xff;
+		idx += PDIR_INDEX(CUJO_20_STEP) >> 3;
+	}
+}
+
 #if 0
 /* GRANT -  is this needed for U2 or not? */
 
@@ -875,38 +1285,37 @@
 ** I think only Java (K/D/R-class too?) systems don't do this.
 */
 static int
-ccio_get_iotlb_size(struct hp_device *d)
+ccio_get_iotlb_size(struct parisc_device *dev)
 {
-	if(d->spa_shift == 0) {
-		panic(__FUNCTION__ ": Can't determine I/O TLB size.\n");
+	if (dev->spa_shift == 0) {
+		panic("%s() : Can't determine I/O TLB size.\n", __FUNCTION__);
 	}
-	return(1 << d->spa_shift);
+	return (1 << dev->spa_shift);
 }
 #else
 
 /* Uturn supports 256 TLB entries */
 #define CCIO_CHAINID_SHIFT	8
 #define CCIO_CHAINID_MASK	0xff
-
 #endif /* 0 */
 
-
-/*
-** Figure out how big the I/O PDIR should be and alloc it.
-** Also sets variables which depend on pdir size.
-*/
+/**
+ * ccio_ioc_init - Initalize the I/O Controller
+ * @ioc: The I/O Controller.
+ *
+ * Initalize the I/O Controller which includes setting up the
+ * I/O Page Directory, the resource map, and initalizing the
+ * U2/Uturn chip into virtual mode.
+ */
 static void
-ccio_alloc_pdir(struct ccio_device *ioa)
+ccio_ioc_init(struct ioc *ioc)
 {
-	extern unsigned long mem_max;          /* arch.../setup.c */
-
-	u32 iova_space_size = 0;
-	void * pdir_base;
-	int pdir_size, iov_order;
+	int i, iov_order;
+	u32 iova_space_size;
+	unsigned long physmem;
 
 	/*
 	** Determine IOVA Space size from memory size.
-	** Using "mem_max" is a kluge.
 	**
 	** Ideally, PCI drivers would register the maximum number
 	** of DMA they can have outstanding for each device they
@@ -915,15 +1324,18 @@
 	** methods still require some "extra" to support PCI
 	** Hot-Plug/Removal of PCI cards. (aka PCI OLARD).
 	*/
+
 	/* limit IOVA space size to 1MB-1GB */
-	if (mem_max < (ccio_mem_ratio*1024*1024)) {
-		iova_space_size = 1024*1024;
+
+	physmem = num_physpages << PAGE_SHIFT;
+	if(physmem < (ccio_mem_ratio * 1024 * 1024)) {
+		iova_space_size = 1024 * 1024;
 #ifdef __LP64__
-	} else if (mem_max > (ccio_mem_ratio*512*1024*1024)) {
-		iova_space_size = 512*1024*1024;
+	} else if(physmem > (ccio_mem_ratio * 512 * 1024 * 1024)) {
+		iova_space_size = 512 * 1024 * 1024;
 #endif
 	} else {
-		iova_space_size = (u32) (mem_max/ccio_mem_ratio);
+		iova_space_size = (u32)(physmem / ccio_mem_ratio);
 	}
 
 	/*
@@ -933,277 +1345,271 @@
 
 	/* We could use larger page sizes in order to *decrease* the number
 	** of mappings needed.  (ie 8k pages means 1/2 the mappings).
-        **
+	**
 	** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either
 	**   since the pages must also be physically contiguous - typically
 	**   this is the case under linux."
 	*/
 
-	iov_order = get_order(iova_space_size);
+	iov_order = get_order(iova_space_size) >> (IOVP_SHIFT - PAGE_SHIFT);
 	ASSERT(iov_order <= (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
 	ASSERT(iov_order >= (20 - IOVP_SHIFT));   /* iova_space_size >= 1MB */
 	iova_space_size = 1 << (iov_order + IOVP_SHIFT);
 
-	ioa->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
+	ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
 
-	ASSERT(pdir_size < 4*1024*1024);   /* max pdir size < 4MB */
+	ASSERT(ioc->pdir_size < 4 * 1024 * 1024);   /* max pdir size < 4MB */
 
 	/* Verify it's a power of two */
-	ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT));
+	ASSERT((1 << get_order(ioc->pdir_size)) == (ioc->pdir_size >> PAGE_SHIFT));
 
-	DBG_INIT(__FUNCTION__ " hpa 0x%p mem %dMB IOV %dMB (%d bits)\n    PDIR size 0x%0x",
-		ioa->ccio_hpa, (int) (mem_max>>20), iova_space_size>>20,
-		iov_order + PAGE_SHIFT, pdir_size);
-
-	ioa->pdir_base =
-	pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
-	if (NULL == pdir_base)
-	{
-		panic(__FILE__ ":" __FUNCTION__ "() could not allocate I/O Page Table\n");
+	DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits) PDIR size 0x%0x",
+		__FUNCTION__, ioc->ioc_hpa, physmem>>20, iova_space_size>>20,
+		 iov_order + PAGE_SHIFT, ioc->pdir_size);
+
+	ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, 
+						 get_order(ioc->pdir_size));
+	if(NULL == ioc->pdir_base) {
+		panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
 	}
-	memset(pdir_base, 0, pdir_size);
+	memset(ioc->pdir_base, 0, ioc->pdir_size);
 
-	ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
+	ASSERT((((unsigned long)ioc->pdir_base) & PAGE_MASK) == (unsigned long)ioc->pdir_base);
+	DBG_INIT(" base %p", ioc->pdir_base);
 
-	DBG_INIT(" base %p", pdir_base);
+	/* resource map size dictated by pdir_size */
+ 	ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3;
+	DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size);
+	
+	ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, 
+					      get_order(ioc->res_size));
+	if(NULL == ioc->res_map) {
+		panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__);
+	}
+	memset(ioc->res_map, 0, ioc->res_size);
+
+	/* Initialize the res_hint to 16 */
+	ioc->res_hint = 16;
+
+	/* Initialize the spinlock */
+	spin_lock_init(&ioc->res_lock);
 
 	/*
 	** Chainid is the upper most bits of an IOVP used to determine
 	** which TLB entry an IOVP will use.
 	*/
-	ioa->chainid_shift = get_order(iova_space_size)+PAGE_SHIFT-CCIO_CHAINID_SHIFT;
-
-	DBG_INIT(" chainid_shift 0x%x\n", ioa->chainid_shift);
-}
-
-
-static void
-ccio_hw_init(struct ccio_device *ioa)
-{
-	int i;
+	ioc->chainid_shift = get_order(iova_space_size) + PAGE_SHIFT - CCIO_CHAINID_SHIFT;
+	DBG_INIT(" chainid_shift 0x%x\n", ioc->chainid_shift);
 
 	/*
 	** Initialize IOA hardware
 	*/
-	WRITE_U32(CCIO_CHAINID_MASK << ioa->chainid_shift, &ioa->ccio_hpa->io_chain_id_mask);
-	WRITE_U32(virt_to_phys(ioa->pdir_base), &ioa->ccio_hpa->io_pdir_base);
+	WRITE_U32(CCIO_CHAINID_MASK << ioc->chainid_shift, 
+		  &ioc->ioc_hpa->io_chain_id_mask);
 
+	WRITE_U32(virt_to_phys(ioc->pdir_base), 
+		  &ioc->ioc_hpa->io_pdir_base);
 
 	/*
 	** Go to "Virtual Mode"
 	*/
-	WRITE_U32(IOA_NORMAL_MODE, &ioa->ccio_hpa->io_control);
+	WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_hpa->io_control);
 
 	/*
 	** Initialize all I/O TLB entries to 0 (Valid bit off).
 	*/
-	WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_m);
-	WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_l);
+	WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_m);
+	WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_l);
 
-	for (i = 1 << CCIO_CHAINID_SHIFT; i ; i--) {
-		WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioa->chainid_shift)),
-					&ioa->ccio_hpa->io_command);
+	for(i = 1 << CCIO_CHAINID_SHIFT; i ; i--) {
+		WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioc->chainid_shift)),
+			  &ioc->ioc_hpa->io_command);
 	}
-
 }
 
-
 static void
-ccio_resmap_init(struct ccio_device *ioa)
+ccio_init_resource(struct resource *res, char *name, unsigned long ioaddr)
 {
-	u32 res_size;
-
-	/*
-	** Ok...we do more than just init resource map
-	*/
-	ioa->ccio_lock = SPIN_LOCK_UNLOCKED;
+	int result;
 
-	ioa->res_hint = 16;    /* next available IOVP - circular search */
-
-	/* resource map size dictated by pdir_size */
-	res_size = ioa->pdir_size/sizeof(u64); /* entries */
-	res_size >>= 3;	/* convert bit count to byte count */
-	DBG_INIT(__FUNCTION__ "() res_size 0x%x\n", res_size);
-
-	ioa->res_size = res_size;
-	ioa->res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
-	if (NULL == ioa->res_map)
-	{
-		panic(__FILE__ ":" __FUNCTION__ "() could not allocate resource map\n");
+	res->flags = IORESOURCE_MEM;
+	res->start = (unsigned long)(signed) __raw_readl(ioaddr) << 16;
+	res->end = (unsigned long)(signed) (__raw_readl(ioaddr + 4) << 16) - 1;
+	if (res->end + 1 == res->start)
+		return;
+	res->name = name;
+	result = request_resource(&iomem_resource, res);
+	if (result < 0) {
+		printk(KERN_ERR 
+		       "%s: failed to claim CCIO bus address space (%p,%p)\n", 
+		       __FILE__, res->start, res->end);
 	}
-	memset(ioa->res_map, 0, res_size);
 }
 
-/* CUJO20 KLUDGE start */
-static struct {
-		u16 hversion;
-		u8  spa;
-		u8  type;
-		u32     foo[3];	/* 16 bytes total */
-} cujo_iodc __attribute__ ((aligned (64)));
-static unsigned long cujo_result[32] __attribute__ ((aligned (16))) = {0,0,0,0};
+static void __init ccio_init_resources(struct ioc *ioc)
+{
+	struct resource *res = ioc->mmio_region;
+	char *name = kmalloc(14, GFP_KERNEL);
 
-/*
-** CUJO 2.0 incorrectly decodes a memory access for specific
-** pages (every page at specific iotlb locations dependent
-** upon where the cujo is flexed - diff on raven/firehawk.
-** resulting in an hpmc and/or silent data corruption.
-** Workaround is to prevent use of those I/O TLB entries
-** by marking the suspect bitmap range entries as busy.
-*/
-static void
-ccio_cujo20_hack(struct ccio_device *ioa)
+	sprintf(name, "GSC Bus [%d/]", ioc->hw_path);
+
+	ccio_init_resource(res, name, (unsigned long)&ioc->ioc_hpa->io_io_low);
+	ccio_init_resource(res + 1, name,
+			(unsigned long)&ioc->ioc_hpa->io_io_low_hv);
+}
+
+static void expand_ioc_area(struct ioc *ioc, unsigned long size,
+		unsigned long min, unsigned long max, unsigned long align)
 {
-	unsigned long status;
-	unsigned int idx;
-	u8 *res_ptr = ioa->res_map;
-	u32 iovp=0x0;
-	unsigned long mask;
+#ifdef NASTY_HACK_FOR_K_CLASS
+	__raw_writel(0xfffff600, (unsigned long)&(ioc->ioc_hpa->io_io_high));
+	ioc->mmio_region[0].end = 0xf5ffffff;
+#endif
+}
 
-	status = pdc_iodc_read( &cujo_result, (void *) CUJO_RAVEN_LOC, 0, &cujo_iodc, 16);
-	if (status == 0) {
-		if (cujo_iodc.hversion==CUJO_20_BADHVERS)
-			iovp = CUJO_20_BADPAGE1;
+static struct resource *ccio_get_resource(struct ioc* ioc,
+		const struct parisc_device *dev)
+{
+	if (!ioc) {
+		return &iomem_resource;
+	} else if ((ioc->mmio_region->start <= dev->hpa) &&
+			(dev->hpa < ioc->mmio_region->end)) {
+		return ioc->mmio_region;
+	} else if (((ioc->mmio_region + 1)->start <= dev->hpa) &&
+			(dev->hpa < (ioc->mmio_region + 1)->end)) {
+		return ioc->mmio_region + 1;
 	} else {
-		status = pdc_iodc_read( &cujo_result, (void *) CUJO_FIREHAWK_LOC, 0, &cujo_iodc, 16);
-		if (status == 0) {
-			if (cujo_iodc.hversion==CUJO_20_BADHVERS)
-				iovp = CUJO_20_BADPAGE2;
-		} else {
-			/* not a defective system */
-			return;
-		}
+		return NULL;
 	}
+}
 
-	printk(MODULE_NAME ": Cujo 2.0 bug needs a work around\n");
-	ccio_cujo_bug = 1;
+int ccio_allocate_resource(const struct parisc_device *dev,
+		struct resource *res, unsigned long size,
+		unsigned long min, unsigned long max, unsigned long align,
+		void (*alignf)(void *, struct resource *, unsigned long),
+		void *alignf_data)
+{
+	struct ioc *ioc = ccio_get_iommu(dev);
+	struct resource *parent = ccio_get_resource(ioc, dev);
+	if (!parent)
+		return -EBUSY;
 
-	/*
-	** mark bit entries that match "bad page"
-	*/
-	idx = PDIR_INDEX(iovp)>>3;
-	mask = 0xff;
-	
-	while(idx * sizeof(u8) < ioa->res_size) {
-		res_ptr[idx] |= mask;
-		idx += (PDIR_INDEX(CUJO_20_STEP)>>3);
-		ccio_used_pages += 8;
-		ccio_used_bytes += 1;
-	}
+	if (!allocate_resource(parent, res, size, min, max, align, alignf,
+			alignf_data))
+		return 0;
+
+	expand_ioc_area(ioc, size, min, max, align);
+	return allocate_resource(parent, res, size, min, max, align, alignf,
+			alignf_data);
 }
-/* CUJO20 KLUDGE end */
 
-#ifdef CONFIG_PROC_FS
-static int ccio_proc_info(char *buf, char **start, off_t offset, int len)
+int ccio_request_resource(const struct parisc_device *dev,
+		struct resource *res)
 {
-	unsigned long i = 0;
-	struct ccio_device *ioa = ccio_list;
-	unsigned long *res_ptr = (unsigned long *)ioa->res_map;
-	unsigned long total_pages = ioa->res_size << 3;            /* 8 bits per byte */
-
-	sprintf(buf, "%s\nCujo 2.0 bug    : %s\n",
-		parisc_getHWdescription(ioa->iodc->hw_type, ioa->iodc->hversion,
-					ioa->iodc->sversion),
-		(ccio_cujo_bug ? "yes" : "no"));
-
-	sprintf(buf, "%sIO pdir size    : %d bytes (%d entries)\n",
-		buf, ((ioa->res_size << 3) * sizeof(u64)), /* 8 bits per byte */
-		ioa->res_size << 3);                       /* 8 bits per byte */
+	struct ioc *ioc = ccio_get_iommu(dev);
+	struct resource *parent = ccio_get_resource(ioc, dev);
+
+	return request_resource(parent, res);
+}
+/**
+ * ccio_probe - Determine if ccio should claim this device.
+ * @dev: The device which has been found
+ *
+ * Determine if ccio should claim this chip (return 0) or not (return 1).
+ * If so, initialize the chip and tell other partners in crime they
+ * have work to do.
+ */
+static int ccio_probe(struct parisc_device *dev)
+{
+	int i;
+	struct ioc *ioc, **ioc_p = &ioc_list;
 	
-	sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", 
-		buf, ioa->res_size, ioa->res_size << 3);   /* 8 bits per byte */
+	ioc = kmalloc(sizeof(struct ioc), GFP_KERNEL);
+	if (ioc == NULL) {
+		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
+		return 1;
+	}
+	memset(ioc, 0, sizeof(struct ioc));
 
-	strcat(buf,  "     	  total:    free:    used:   % used:\n");
-	sprintf(buf, "%sblocks  %8d %8ld %8ld %8ld%%\n", buf, ioa->res_size,
-		ioa->res_size - ccio_used_bytes, ccio_used_bytes,
-		(ccio_used_bytes * 100) / ioa->res_size);
-
-	sprintf(buf, "%spages   %8ld %8ld %8ld %8ld%%\n", buf, total_pages,
-		total_pages - ccio_used_pages, ccio_used_pages,
-		(ccio_used_pages * 100 / total_pages));
+	ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn";
 
-	sprintf(buf, "%sconsistent       %8ld %8ld\n", buf,
-		ccio_alloc_size, ccio_free_size);
- 
-	strcat(buf, "\nResource bitmap:\n");
+	printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa);
 
-	for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr)
-		len += sprintf(buf, "%s%08lx ", buf, *res_ptr);
+	for (i = 0; i < ioc_count; i++) {
+		ioc_p = &(*ioc_p)->next;
+	}
+	*ioc_p = ioc;
 
-	strcat(buf, "\n");
-	return strlen(buf);
+	ioc->hw_path = dev->hw_path;
+	ioc->ioc_hpa = (struct ioa_registers *)dev->hpa;
+	ccio_ioc_init(ioc);
+	ccio_init_resources(ioc);
+	hppa_dma_ops = &ccio_ops;
+
+	if (ioc_count == 0) {
+		/* XXX: Create separate entries for each ioc */
+		create_proc_read_entry(MODULE_NAME, S_IRWXU, proc_runway_root,
+				       ccio_proc_info, NULL);
+		create_proc_read_entry(MODULE_NAME"-bitmap", S_IRWXU,
+				       proc_runway_root, ccio_resource_map, NULL);
+	}
+
+	ioc_count++;
+	return 0;
 }
-#endif
 
-/*
-** Determine if ccio should claim this chip (return 0) or not (return 1).
-** If so, initialize the chip and tell other partners in crime they
-** have work to do.
-*/
-static int
-ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+struct pci_dev * ccio_get_fake(const struct parisc_device *dev)
 {
-	struct ccio_device *ioa;
+	struct ioc *ioc;
 
-	printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa);
+	dev = find_pa_parent_type(dev, HPHW_IOA);
+	if(!dev)
+		return NULL;
 
-	if (ccio_list) {
-		printk(MODULE_NAME ": already initialized one device\n");
-		return(0);
-	}
+	ioc = ccio_find_ioc(dev->hw_path);
+	if(!ioc)
+		return NULL;
 
-	ioa = kmalloc(sizeof(struct ccio_device), GFP_KERNEL);
-	if (NULL == ioa)
-	{
-		printk(MODULE_NAME " - couldn't alloc ccio_device\n");
-		return(1);
-	}
-	memset(ioa, 0, sizeof(struct ccio_device));
+	if(ioc->fake_pci_dev)
+		return ioc->fake_pci_dev;
 
-	/*
-	** ccio list is used mainly as a kluge to support a single instance. 
-	** Eventually, with core dumps, it'll be useful for debugging.
-	*/
-	ccio_list = ioa;
-	ioa->iodc = d;
+	ioc->fake_pci_dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	if(ioc->fake_pci_dev == NULL) {
+		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
+		return NULL;
+	}
+	memset(ioc->fake_pci_dev, 0, sizeof(struct pci_dev));
 
-#if 1
-/* KLUGE: determine IOA hpa based on GSC port value.
-** Needed until we have a PA bus walk. Can only discover IOA via
-** walking the architected PA MMIO space as described by the I/O ACD.
-** "Legacy" PA Firmware only tells us about unarchitected devices
-** that can't be detected by PA/EISA/PCI bus walks.
-*/
-	switch((long) d->hpa) {
-	case 0xf3fbf000L:       /* C110 IOA0 LBC (aka GSC port) */
-		/* ccio_hpa same as C200 IOA0 */
-	case 0xf203f000L:       /* C180/C200/240/C360 IOA0 LBC (aka GSC port) */
-		ioa->ccio_hpa = (struct ioa_registers *) 0xfff88000L;
-		break;
-	case 0xf103f000L:       /* C180/C200/240/C360 IOA1 LBC (aka GSC port) */
-		ioa->ccio_hpa = (struct ioa_registers *) 0xfff8A000L;
-		break;
-	default:
-		panic("ccio-dma.c doesn't know this GSC port Address!\n");
-		break;
-	};
-#else
-	ioa->ccio_hpa = d->hpa;
-#endif
+	ioc->fake_pci_dev->sysdata = kmalloc(sizeof(struct pci_hba_data), GFP_KERNEL);
+	if(ioc->fake_pci_dev->sysdata == NULL) {
+		printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
+		return NULL;
+	}
 
-	ccio_alloc_pdir(ioa);
-	ccio_hw_init(ioa);
-	ccio_resmap_init(ioa);
+	HBA_DATA(ioc->fake_pci_dev->sysdata)->iommu = ioc;
+	return ioc->fake_pci_dev;
+}
 
-	/* CUJO20 KLUDGE start */
-	ccio_cujo20_hack(ioa);
-	/* CUJO20 KLUDGE end */
+/* We *can't* support JAVA (T600). Venture there at your own risk. */
+static struct parisc_device_id ccio_tbl[] = {
+	{ HPHW_IOA, HVERSION_REV_ANY_ID, U2_IOA_RUNWAY, 0xb }, /* U2 */
+	{ HPHW_IOA, HVERSION_REV_ANY_ID, UTURN_IOA_RUNWAY, 0xb }, /* UTurn */
+	{ 0, }
+};
 
-	hppa_dma_ops = &ccio_ops;
+static struct parisc_driver ccio_driver = {
+	name:		"U2/Uturn",
+	id_table:	ccio_tbl,
+	probe:		ccio_probe,
+};
 
-	create_proc_info_entry(MODULE_NAME, 0, proc_runway_root, ccio_proc_info);
-	return(0);
+/**
+ * ccio_init - ccio initalization procedure.
+ *
+ * Register this driver.
+ */
+void __init ccio_init(void)
+{
+	register_parisc_driver(&ccio_driver);
 }
 
-
-
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/ccio-rm-dma.c linux-2.4.20-pre2/arch/parisc/kernel/ccio-rm-dma.c
--- linux-2.4.20-pre1/arch/parisc/kernel/ccio-rm-dma.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/ccio-rm-dma.c	Mon Aug 12 16:34:14 2002
@@ -56,26 +56,6 @@
 #define UTURN_IOA_RUNWAY 0x581
 #define UTURN_BC_GSC     0x502
 
-static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-static struct pa_iodc_driver ccio_drivers_for[] = {
-
-   {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback},
-
-   {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback},
-
-   {0,0,0,0,0,0,
-   0,
-   (char *) NULL, (char *) NULL, (void *) NULL }
-};
-
-
 #define IS_U2(id) ( \
     (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \
     (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC))  \
@@ -86,17 +66,10 @@
     (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC))  \
 )
 
-
-void __init ccio_init(void)
-{
-	register_driver(ccio_drivers_for);
-}
-
-
 static int ccio_dma_supported( struct pci_dev *dev, u64 mask)
 {
 	if (dev == NULL) {
-		printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
+		printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
 		BUG();
 		return(0);
 	}
@@ -182,8 +155,6 @@
 	ccio_unmap_sg,
 	NULL,                   /* dma_sync_single : NOP for U2 */
 	NULL,                   /* dma_sync_sg     : ditto */
-
-
 };
 
 
@@ -193,9 +164,11 @@
 ** have work to do.
 */
 static int
-ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+ccio_probe(struct parisc_device *dev)
 {
-	printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa);
+	printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME,
+			dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn",
+			dev->hpa);
 
 /*
 ** FIXME - should check U2 registers to verify it's really running
@@ -210,3 +183,20 @@
 	hppa_dma_ops = &ccio_ops;
 	return 0;
 }
+
+static struct parisc_device_id ccio_tbl[] = {
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, U2_BC_GSC, 0xc },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, UTURN_BC_GSC, 0xc },
+	{ 0, }
+};
+
+static struct parisc_driver ccio_driver = {
+        name:           "U2/Uturn",
+        id_table:       ccio_tbl,
+        probe:          ccio_probe,
+};
+
+void __init ccio_init(void)
+{
+	register_parisc_driver(&ccio_driver);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/drivers.c linux-2.4.20-pre2/arch/parisc/kernel/drivers.c
--- linux-2.4.20-pre1/arch/parisc/kernel/drivers.c	Wed Dec  6 11:46:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/drivers.c	Mon Aug 12 16:34:14 2002
@@ -1,134 +1,591 @@
 /*
-
-drivers.c
-
-Copyright (c) 1999 The Puffin Group 
-
-This is a collection of routines intended to register all the devices
-in a system, and register device drivers.
-
-*/
+ * drivers.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.
+ *
+ * Copyright (c) 1999 The Puffin Group
+ * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
+ * Copyright (c) 2001 Helge Deller <deller@gmx.de>
+ * 
+ * The file handles registering devices and drivers, then matching them.
+ * It's the closest we get to a dating agency.
+ */
 
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/pdc.h>
+#include <asm/gsc.h>
 
+/* See comments in include/asm-parisc/pci.h */
+struct pci_dma_ops *hppa_dma_ops;
 
-extern struct hp_hardware *parisc_get_reference(
-	unsigned short hw_type, unsigned long hversion, 
-	unsigned long sversion );
+static struct parisc_driver *pa_drivers;
+static struct parisc_device root;
 
+/* This lock protects the pa_drivers list _only_ since all parisc_devices
+ * are registered before smp_init() is called.  If you wish to add devices
+ * after that, this muct be serialised somehow.  I recommend a semaphore
+ * rather than a spinlock since driver ->probe functions are allowed to
+ * sleep (for example when allocating memory).
+ */
+static spinlock_t pa_lock = SPIN_LOCK_UNLOCKED;
 
-/* I'm assuming there'll never be 64 devices.  We should probably make 
-   this more flexible.  */
+#define for_each_padev(dev) \
+	for (dev = root.child; dev != NULL; dev = next_dev(dev))
 
-#define MAX_DEVICES 64
+#define check_dev(dev) \
+	(dev->id.hw_type != HPHW_FAULTY) ? dev : next_dev(dev)
 
-unsigned int num_devices = 0;
+/**
+ * next_dev - enumerates registered devices
+ * @dev: the previous device returned from next_dev
+ *
+ * next_dev does a depth-first search of the tree, returning parents
+ * before children.  Returns NULL when there are no more devices.
+ */
+struct parisc_device *next_dev(struct parisc_device *dev)
+{
+	if (dev->child) {
+		return check_dev(dev->child);
+	} else if (dev->sibling) {
+		return dev->sibling;
+	}
 
-struct hp_device devices[MAX_DEVICES];
+	/* Exhausted tree at this level, time to go up. */
+	do {
+		dev = dev->parent;
+		if (dev && dev->sibling)
+			return dev->sibling;
+	} while (dev != &root);
 
-static unsigned long pdc_result[32] __attribute__ ((aligned (16))) = {0,0,0,0};
-static  u8 iodc_data[32] __attribute__ ((aligned (64)));
+	return NULL;
+}
 
-/*
- *	XXX should we be using a locked array ?
+/**
+ * match_device - Report whether this driver can handle this device
+ * @driver: the PA-RISC driver to try
+ * @dev: the PA-RISC device to try
  */
- 
-int register_driver(struct pa_iodc_driver *driver)
+static int match_device(struct parisc_driver *driver, struct parisc_device *dev)
 {
-	unsigned int i;
-	struct hp_device * device;
+	const struct parisc_device_id *ids;
 
-	for (;driver->check;driver++)  {
+	for (ids = driver->id_table; ids->sversion; ids++) {
+		if ((ids->sversion != SVERSION_ANY_ID) &&
+		    (ids->sversion != dev->id.sversion))
+			continue;
+
+		if ((ids->hw_type != HWTYPE_ANY_ID) &&
+		    (ids->hw_type != dev->id.hw_type))
+			continue;
+
+		if ((ids->hversion != HVERSION_ANY_ID) &&
+		    (ids->hversion != dev->id.hversion))
+			continue;
 
-		for (i=0;i<num_devices;i++) {
-			device = &devices[i];
+		return 1;
+	}
+	return 0;
+}
 
-			if (device->managed) continue;
+static void claim_device(struct parisc_driver *driver, struct parisc_device *dev)
+{
+	dev->driver = driver;
+	request_mem_region(dev->hpa, 0x1000, driver->name);
+}
 
-			if ((driver->check & DRIVER_CHECK_HWTYPE) &&
-			    (driver->hw_type != device->hw_type))
-				continue;
-			if ((driver->check & DRIVER_CHECK_HVERSION) &&
-			    (driver->hversion != device->hversion))
-				continue;
-			if ((driver->check & DRIVER_CHECK_HVERSION_REV) &&
-			    (driver->hversion_rev != device->hversion_rev))
-				continue;
-			if ((driver->check & DRIVER_CHECK_SVERSION) &&
-			    (driver->sversion != device->sversion))
-				continue;
-			if ((driver->check & DRIVER_CHECK_SVERSION_REV) &&
-			    (driver->sversion_rev != device->sversion_rev))
-				continue;
-			if ((driver->check & DRIVER_CHECK_OPT) &&
-			    (driver->opt != device->opt))
-				continue;
-			if ( (*driver->callback)(device,driver) ==0) {
-				device->managed=1;
-			} else {
-				printk("Warning : device (%d, 0x%x, 0x%x, 0x%x, 0x%x) NOT claimed by %s %s\n",
-					device->hw_type,
-					device->hversion, device->hversion_rev,
-					device->sversion, device->sversion_rev,
-					driver->name, driver->version);
-			}
+/**
+ * register_parisc_driver - Register this driver if it can handle a device
+ * @driver: the PA-RISC driver to try
+ */
+int register_parisc_driver(struct parisc_driver *driver)
+{
+	struct parisc_device *device;
+
+	if (driver->next) {
+		printk(KERN_WARNING 
+		       "BUG: Skipping previously registered driver: %s\n",
+		       driver->name);
+		return 1;
+	}
+
+	for_each_padev(device) {
+		if (device->driver)
+			continue;
+		if (!match_device(driver, device))
+			continue;
+
+		if (driver->probe(device) < 0)
+			continue;
+		claim_device(driver, device);
+	}
+
+	/* Note that the list is in reverse order of registration.  This
+	 * may be significant if we ever actually support hotplug and have
+	 * multiple drivers capable of claiming the same chip.
+	 */
+
+	spin_lock(&pa_lock);
+	driver->next = pa_drivers;
+	pa_drivers = driver;
+	spin_unlock(&pa_lock);
+
+	return 0;
+}
+
+/**
+ * count_parisc_driver - count # of devices this driver would match
+ * @driver: the PA-RISC driver to try
+ *
+ * Use by IOMMU support to "guess" the right size IOPdir.
+ * Formula is something like memsize/(num_iommu * entry_size).
+ */
+int count_parisc_driver(struct parisc_driver *driver)
+{
+	struct parisc_device *device;
+	int cnt = 0;
+
+	for_each_padev(device) {
+		if (match_device(driver, device))
+			cnt++;
+	}
+
+	return cnt;
+}
+
+
+
+/**
+ * unregister_parisc_driver - Unregister this driver from the list of drivers
+ * @driver: the PA-RISC driver to unregister
+ */
+int unregister_parisc_driver(struct parisc_driver *driver)
+{
+	struct parisc_device *dev;
+
+	spin_lock(&pa_lock);
+
+	if (pa_drivers == driver) {
+		/* was head of list - update head */
+		pa_drivers = driver->next;
+	} else {
+		struct parisc_driver *prev = pa_drivers;
+
+		while (prev && driver != prev->next) {
+			prev = prev->next;
+		}
+
+		if (!prev) {
+			printk(KERN_WARNING "unregister_parisc_driver: %s wasn't registered\n", driver->name);
+		} else {
+			/* Drop driver from list */
+			prev->next = driver->next;
+			driver->next = NULL;
 		}
+
 	}
+
+	spin_unlock(&pa_lock);
+
+	for_each_padev(dev) {
+		if (dev->driver != driver)
+			continue;
+		dev->driver = NULL;
+		release_mem_region(dev->hpa, 0x1000);
+	}
+
 	return 0;
 }
 
+static struct parisc_device *find_device_by_addr(unsigned long hpa)
+{
+	struct parisc_device *dev;
+	for_each_padev(dev) {
+		if (dev->hpa == hpa)
+			return dev;
+	}
+	return NULL;
+}
 
-struct hp_device * register_module(void *hpa)
+/**
+ * find_pa_parent_type - Find a parent of a specific type
+ * @dev: The device to start searching from
+ * @type: The device type to search for.
+ *
+ * Walks up the device tree looking for a device of the specified type.
+ * If it finds it, it returns it.  If not, it returns NULL.
+ */
+const struct parisc_device *find_pa_parent_type(const struct parisc_device *dev, int type)
 {
+	while (dev != &root) {
+		if (dev->id.hw_type == type)
+			return dev;
+		dev = dev->parent;
+	}
 
-	struct hp_device * d;
+	return NULL;
+}
+
+static void
+get_node_path(struct parisc_device *dev, struct hardware_path *path)
+{
+	int i = 5;
+	memset(&path->bc, -1, 6);
+	while (dev != &root) {
+		path->bc[i--] = dev->hw_path;
+		dev = dev->parent;
+	}
+}
+
+static char *print_hwpath(struct hardware_path *path, char *output)
+{
+	int i;
+	for (i = 0; i < 6; i++) {
+		if (path->bc[i] == -1)
+			continue;
+		output += sprintf(output, "%u/", (unsigned char) path->bc[i]);
+	}
+	output += sprintf(output, "%u", (unsigned char) path->mod);
+	return output;
+}
+
+/**
+ * print_pa_hwpath - Returns hardware path for PA devices
+ * dev: The device to return the path for
+ * output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the output array with a human-readable path
+ * to a PA device.  This string is compatible with that used by PDC, and
+ * may be printed on the outside of the box.
+ */
+char *print_pa_hwpath(struct parisc_device *dev, char *output)
+{
+	struct hardware_path path;
+
+	get_node_path(dev->parent, &path);
+	path.mod = dev->hw_path;
+	return print_hwpath(&path, output);
+}
+
+
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+/**
+ * get_pci_node_path - Returns hardware path for PCI devices
+ * dev: The device to return the path for
+ * output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the hardware_path structure with the route to
+ * the specified PCI device.  This structure is suitable for passing to
+ * PDC calls.
+ */
+void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path)
+{
+	struct pci_bus *bus;
+	const struct parisc_device *padev;
+	int i = 5;
+
+	memset(&path->bc, -1, 6);
+	path->mod = PCI_FUNC(dev->devfn);
+	path->bc[i--] = PCI_SLOT(dev->devfn);
+	for (bus = dev->bus; bus->parent; bus = bus->parent) {
+		unsigned int devfn = bus->self->devfn;
+		path->bc[i--] = PCI_SLOT(devfn) | (PCI_FUNC(devfn) << 5);
+	}
+
+	padev = HBA_DATA(bus->sysdata)->dev;
+	while (padev != &root) {
+		path->bc[i--] = padev->hw_path;
+		padev = padev->parent;
+	}
+}
+
+/**
+ * print_pci_hwpath - Returns hardware path for PCI devices
+ * dev: The device to return the path for
+ * output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the output array with a human-readable path
+ * to a PCI device.  This string is compatible with that used by PDC, and
+ * may be printed on the outside of the box.
+ */
+char *print_pci_hwpath(struct pci_dev *dev, char *output)
+{
+	struct hardware_path path;
+
+	get_pci_node_path(dev, &path);
+	return print_hwpath(&path, output);
+}
+#endif /* defined(CONFIG_PCI) || defined(CONFIG_ISA) */
+
+
+struct parisc_device * create_tree_node(char id, struct parisc_device *parent,
+		struct parisc_device **insert)
+{
+	struct parisc_device *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+	memset(dev, 0, sizeof(*dev));
+	dev->hw_path = id;
+	dev->id.hw_type = HPHW_FAULTY;
+	dev->parent = parent;
+	dev->sibling = *insert;
+	*insert = dev;
+	return dev;
+}
+
+/**
+ * alloc_tree_node - returns a device entry in the iotree
+ * @parent: the parent node in the tree
+ * @id: the element of the module path for this entry
+ *
+ * Checks all the children of @parent for a matching @id.  If none
+ * found, it allocates a new device and returns it.
+ */
+struct parisc_device *
+alloc_tree_node(struct parisc_device *parent, char id)
+{
+	struct parisc_device *prev;
+	if ((!parent->child) || (parent->child->hw_path > id)) {
+		return create_tree_node(id, parent, &parent->child);
+	}
+
+	prev = parent->child;
+	if (prev->hw_path == id)
+		return prev;
+
+	while (prev->sibling && prev->sibling->hw_path < id) {
+		prev = prev->sibling;
+	}
+
+	if ((prev->sibling) && (prev->sibling->hw_path == id))
+		return prev->sibling;
+
+	return create_tree_node(id, parent, &prev->sibling);
+}
+
+static struct parisc_device *find_parisc_device(struct hardware_path *modpath)
+{
+	int i;
+	struct parisc_device *parent = &root;
+	for (i = 0; i < 6; i++) {
+		if (modpath->bc[i] == -1)
+			continue;
+		parent = alloc_tree_node(parent, modpath->bc[i]);
+	}
+	return alloc_tree_node(parent, modpath->mod);
+}
+
+struct parisc_device *
+alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path)
+{
 	int status;
+	unsigned long bytecnt;
+	u8 iodc_data[32];
+	struct parisc_device *dev;
+	const char *name;
+
+	/* Check to make sure this device has not already been added - Ryan */
+	if (find_device_by_addr(hpa) != NULL)
+		return NULL;
+
+	status = pdc_iodc_read(&bytecnt, hpa, 0, &iodc_data, 32);
+	if (status != PDC_OK)
+		return NULL;
+
+	dev = find_parisc_device(mod_path);
+	if (dev->id.hw_type != HPHW_FAULTY) {
+		char p[64];
+		print_pa_hwpath(dev, p);
+		printk("Two devices have hardware path %s.  Please file a bug with HP.\n"
+			"In the meantime, you could try rearranging your cards.\n", p);
+		return NULL;
+	}
+
+	dev->id.hw_type = iodc_data[3] & 0x1f;
+	dev->id.hversion = (iodc_data[0] << 4) | ((iodc_data[1] & 0xf0) >> 4);
+	dev->id.hversion_rev = iodc_data[1] & 0x0f;
+	dev->id.sversion = ((iodc_data[4] & 0x0f) << 16) |
+			(iodc_data[5] << 8) | iodc_data[6];
+	dev->hpa = hpa;
+	name = parisc_hardware_description(&dev->id);
+	if (name) {
+		strncpy(dev->name, name, sizeof(dev->name)-1);
+	}
+
+	return dev;
+}
 
-	d = &devices[num_devices];
-	status = pdc_iodc_read(&pdc_result,hpa,0,&iodc_data,32 );
-	if (status !=PDC_RET_OK) {
-		/* There is no device here, so we'll skip it */
+/**
+ * register_parisc_device - Locate a driver to manage this device.
+ * @dev: The parisc device.
+ *
+ * Search the driver list for a driver that is willing to manage
+ * this device.
+ */
+int register_parisc_device(struct parisc_device *dev)
+{
+	struct parisc_driver *driver;
+
+	if (!dev)
 		return 0;
+
+	if (dev->driver)
+		return 1;
+	
+	spin_lock(&pa_lock);
+
+	/* Locate a driver which agrees to manage this device.  */
+	for (driver = pa_drivers; driver; driver = driver->next) {
+		if (!match_device(driver,dev))
+			continue;
+		if (driver->probe(dev) == 0)
+			break;
 	}
 
-	d->hw_type = iodc_data[3]&0x1f;
-	d->hversion = (iodc_data[0]<<4)|((iodc_data[1]&0xf0)>>4);
-	d->sversion = 
-		((iodc_data[4]&0x0f)<<16)|(iodc_data[5]<<8)|(iodc_data[6]);
-	d->hversion_rev = iodc_data[1]&0x0f;
-	d->sversion_rev = iodc_data[4]>>4;
-	d->opt = iodc_data[7];
-	d->hpa = hpa;
-	d->managed=0;
-	d->reference = parisc_get_reference(d->hw_type, d->hversion, 
-								d->sversion);
-		
-	num_devices++;	
+	if (driver != NULL) {
+		claim_device(driver, dev);
+	}
+	spin_unlock(&pa_lock);
+	return driver != NULL;
+}
+
+#define BC_PORT_MASK 0x8
+#define BC_LOWER_PORT 0x8
+
+#define BUS_CONVERTER(dev) \
+        ((dev->id.hw_type == HPHW_IOA) || (dev->id.hw_type == HPHW_BCPORT))
+
+#define IS_LOWER_PORT(dev) \
+        ((gsc_readl(&((struct bc_module *)dev->hpa)->io_status) \
+                & BC_PORT_MASK) == BC_LOWER_PORT)
+
+#define READ_IO_IO_LOW(dev) \
+	(dev->id.hw_type == HPHW_IOA ? \
+	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low) << 16 : \
+	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low))
 
-	return d;
-}	
+static void walk_native_bus(unsigned long addr, struct parisc_device *parent);
+void walk_lower_bus(struct parisc_device *dev)
+{
+
+	if(!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev))
+		return;
 
-void print_devices(char * buf) {
+	walk_native_bus((unsigned long)(signed int)READ_IO_IO_LOW(dev), dev);
+}
 
+#define MAX_NATIVE_DEVICES 64
+#define NATIVE_DEVICE_OFFSET 0x1000
+
+/**
+ * walk_native_bus -- Probe a bus for devices
+ * @addr: Base address of this bus.
+ * 
+ * A native bus (eg Runway or GSC) may have up to 64 devices on it,
+ * spaced at intervals of 0x1000 bytes.  PDC may not inform us of these
+ * devices, so we have to probe for them.  Unfortunately, we may find
+ * devices which are not physically connected (such as extra serial &
+ * keyboard ports).  This problem is not yet solved.
+ */
+static void walk_native_bus(unsigned long addr, struct parisc_device *parent)
+{
 	int i;
-	struct hp_device *d;
-	printk("Found devices:\n");
-	for (i=0;i<num_devices;i++) {	
-		d = &devices[i];
-		printk(KERN_INFO 
-		"%d. %s (%d) at 0x%p, versions 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 
-		i+1,
-		(d->reference) ? d->reference->name : "Unknown device",
-		d->hw_type,d->hpa, d->hversion, d->hversion_rev,
-		d->sversion, d->sversion_rev, d->opt);
+	struct hardware_path path;
+
+	get_node_path(parent, &path);
+	for (i = 0; i < MAX_NATIVE_DEVICES; i++) {
+		unsigned long hpa = (addr + i * NATIVE_DEVICE_OFFSET);
+		struct parisc_device *dev;
+
+		/* Was the device already added by Firmware? */
+		dev = find_device_by_addr(hpa);
+		if (!dev) {
+			path.mod = i;
+			dev = alloc_pa_dev(hpa, &path);
+			if (!dev)
+				continue;
+
+			register_parisc_device(dev);
+		}
+		walk_lower_bus(dev);
+	}
+}
+
+#define CENTRAL_BUS_ADDR (unsigned long) 0xfffffffffff80000
+
+/**
+ * walk_central_bus - Find devices attached to the central bus
+ *
+ * PDC doesn't tell us about all devices in the system.  This routine
+ * finds devices connected to the central bus.
+ */
+void walk_central_bus(void)
+{
+	walk_native_bus(CENTRAL_BUS_ADDR, &root);
+}
+
+void fixup_child_irqs(struct parisc_device *parent, int base,
+			int (*choose_irq)(struct parisc_device *))
+{
+	struct parisc_device *dev;
 
+	if (!parent->child)
+		return;
+
+	for (dev = check_dev(parent->child); dev; dev = dev->sibling) {
+		int irq = choose_irq(dev);
+		if (irq > 0) {
+#ifdef __LP64__
+			irq += 32;
+#endif
+			dev->irq = base + irq;
+		}
 	}
-	printk("That's a total of %d devices.\n",num_devices);
 }
 
+static void print_parisc_device(struct parisc_device *dev)
+{
+	char hw_path[64];
+	static int count;
 
+	print_pa_hwpath(dev, hw_path);
+	printk(KERN_INFO "%d. %s (%d) at 0x%lx [%s], versions 0x%x, 0x%x, 0x%x",
+		++count, dev->name, dev->id.hw_type, dev->hpa, hw_path,
+		dev->id.hversion, dev->id.hversion_rev, dev->id.sversion);
+
+	if (dev->num_addrs) {
+		int k;
+		printk(",  additional addresses: ");
+		for (k = 0; k < dev->num_addrs; k++)
+			printk("0x%lx ", dev->addr[k]);
+	}
+	printk("\n");
+}
+
+void print_subdevices(struct parisc_device *parent)
+{
+	struct parisc_device *dev;
+	for (dev = parent->child; dev != parent->sibling; dev = next_dev(dev)) {
+		print_parisc_device(dev);
+	}
+}
+
+/**
+ * print_parisc_devices - Print out a list of devices found in this system
+ */
+void print_parisc_devices(void)
+{
+	struct parisc_device *dev;
+	for_each_padev(dev) {
+		print_parisc_device(dev);
+	}
+}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/entry.S linux-2.4.20-pre2/arch/parisc/kernel/entry.S
--- linux-2.4.20-pre1/arch/parisc/kernel/entry.S	Wed Dec  6 11:46:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/entry.S	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
-/*------------------------------------------------------------------------------
- * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
  *
  * kernel entry points (interruptions, system call wrappers)
  *  Copyright (C) 1999,2000 Philipp Rumpf 
@@ -25,39 +25,51 @@
 #include <linux/config.h>
 #include <asm/offset.h>
 
-/* the following is the setup i think we should follow:
- * whenever the CPU is interruptible, the following has to be true:
- *  CR30 is the kernel sp or 0 if we currently use the kernel stack
- *  CR31 is the kernel gp */ 
-
 /* we have the following possibilities to act on an interruption:
  *  - handle in assembly and use shadowed registers only
  *  - save registers to kernel stack and handle in assembly or C */
 
-	.text
-
-#ifdef __LP64__
-	.level 2.0w
-#endif
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>	/* for LDREG/STREG defines */
 #include <asm/pgtable.h>
 #include <asm/psw.h>
 #include <asm/signal.h>
+#include <asm/unistd.h>
 
 #ifdef __LP64__
-#define FRAME_SIZE	64
+#define FRAME_SIZE	128
+#define CMPIB           cmpib,*
+#define CMPB            cmpb,*
+
+	.level 2.0w
 #else
 #define FRAME_SIZE	64
+#define CMPIB           cmpib,
+#define CMPB            cmpb,
+
+	.level 2.0
+#endif
+
+	.import         pa_dbit_lock,data
+
+	/* space_to_prot macro creates a prot id from a space id */
+
+#if (SPACEID_SHIFT) == 0
+	.macro  space_to_prot spc prot
+	depd,z  \spc,62,31,\prot
+	.endm
+#else
+	.macro  space_to_prot spc prot
+	extrd,u \spc,(64 - (SPACEID_SHIFT)),32,\prot
+	.endm
 #endif
 
 	/* Switch to virtual mapping, trashing only %r1 */
-	.macro	virt_map rfi_type
-	mtsm	%r0
-	tovirt	%r29
-	tovirt	%r30
+	.macro  virt_map
+	rsm     PSW_SM_Q,%r0
+	tovirt_r1 %r29
 	mfsp	%sr7, %r1
+	or,=    %r0,%r1,%r0 /* Only save sr7 in sr3 if sr7 != 0 */
 	mtsp	%r1, %sr3
 	mtsp	%r0, %sr4
 	mtsp	%r0, %sr5
@@ -65,95 +77,114 @@
 	mtsp	%r0, %sr7
 	ldil	L%KERNEL_PSW, %r1
 	ldo	R%KERNEL_PSW(%r1), %r1
-	LDIL_FIXUP(%r1)
 	mtctl	%r1, %cr22
 	mtctl	%r0, %cr17
 	mtctl	%r0, %cr17
-	ldil	L%.+28, %r1
-	ldo	R%.+24(%r1), %r1
-	LDIL_FIXUP(%r1)
+	ldil	L%4f, %r1
+	ldo	R%4f(%r1), %r1
 	mtctl	%r1, %cr18
 	ldo	4(%r1), %r1
 	mtctl	%r1, %cr18
-	\rfi_type
+	rfir
 	nop
+4:
 	.endm
 
-	.macro	get_stack
-	mfctl	%cr30, %r1 
-	comib,=,n 0, %r1, 0f   /* forward so predicted not taken */
+	/*
+	 * The "get_stack" macros are responsible for determining the
+	 * kernel stack value.
+	 *
+	 * For Faults:
+	 *      If sr7 == 0
+	 *          Already using a kernel stack, so call the
+	 *          get_stack_use_r30 macro to push a pt_regs structure
+	 *          on the stack, and store registers there.
+	 *      else
+	 *          Need to set up a kernel stack, so call the
+	 *          get_stack_use_cr30 macro to set up a pointer
+	 *          to the pt_regs structure contained within the
+	 *          task pointer pointed to by cr30. Set the stack
+	 *          pointer to point to the end of the task structure.
+	 *
+	 * For Interrupts:
+	 *      If sr7 == 0
+	 *          Already using a kernel stack, check to see if r30
+	 *          is already pointing to the per processor interrupt
+	 *          stack. If it is, call the get_stack_use_r30 macro
+	 *          to push a pt_regs structure on the stack, and store
+	 *          registers there. Otherwise, call get_stack_use_cr31
+	 *          to get a pointer to the base of the interrupt stack
+	 *          and push a pt_regs structure on that stack.
+	 *      else
+	 *          Need to set up a kernel stack, so call the
+	 *          get_stack_use_cr30 macro to set up a pointer
+	 *          to the pt_regs structure contained within the
+	 *          task pointer pointed to by cr30. Set the stack
+	 *          pointer to point to the end of the task structure.
+	 *          N.B: We don't use the interrupt stack for the
+	 *          first interrupt from userland, because signals/
+	 *          resched's are processed when returning to userland,
+	 *          and we can sleep in those cases.
+	 *
+	 * Note that we use shadowed registers for temps until
+	 * we can save %r26 and %r29. %r26 is used to preserve
+	 * %r8 (a shadowed register) which temporarily contained
+	 * either the fault type ("code") or the eirr. We need
+	 * to use a non-shadowed register to carry the value over
+	 * the rfir in virt_map. We use %r26 since this value winds
+	 * up being passed as the argument to either do_cpu_irq_mask
+	 * or handle_interruption. %r29 is used to hold a pointer
+	 * the register save area, and once again, it needs to
+	 * be a non-shadowed register so that it survives the rfir.
+	 *
+	 * N.B. TASK_SZ_ALGN and PT_SZ_ALGN include space for a stack frame.
+	 */
+
+	.macro  get_stack_use_cr30
 
 	/* we save the registers in the task struct */
-	ldo	TASK_REGS(%r1), %r29
-	tophys	%r29
-	STREG	%r30, PT_GR30(%r29)
-	STREG	%r1,  PT_CR30(%r29)
+
+	mfctl   %cr30, %r1
+	tophys  %r1,%r9
+	ldo     TASK_REGS(%r9),%r9
+	STREG   %r30, PT_GR30(%r9)
 	ldo	TASK_SZ_ALGN(%r1), %r30
-	b	1f		    /* unconditional so predicted taken */	
-	mtctl	%r0,%cr30
-0:
-	/* we put a struct pt_regs on the stack and save the registers there */
-	copy	%r30,%r29
-	ldo	PT_SZ_ALGN(%r30),%r30
-	tophys	%r29
-	STREG	%r30,PT_GR30(%r29)
-	STREG	%r0,PT_CR30(%r29)
-1:
+	STREG   %r29,PT_GR29(%r9)
+	STREG   %r26,PT_GR26(%r9)
+	copy    %r9,%r29
 	.endm
 
-	.macro	rest_stack regs
-	LDREG	PT_CR30(\regs), %r1
-	comib,=,n 0, %r1, 2f/* forward so predicted not taken */
-
-	/* we restore the registers out of the task struct */
-	mtctl	%r1, %cr30
-	LDREG	PT_GR1(\regs), %r1
-	LDREG	PT_GR30(\regs),%r30
-	b	3f
-	LDREG	PT_GR29(\regs),%r29
-2:
-	/* we take a struct pt_regs off the stack */
-	LDREG	PT_GR1(\regs),  %r1
-	LDREG	PT_GR29(\regs), %r29
-	ldo	-PT_SZ_ALGN(%r30), %r30
-3:
-	.endm
+	.macro  get_stack_use_r30
 
-#ifdef OLD
-	/* fixme interruption handler */
-	.macro	def code
-	/* WARNING!!! THIS IS DEBUG CODE ONLY!!! */
-	b	unimplemented_64bitirq
-	ldi	\code, %r1
-	.align	32
+	/* we put a struct pt_regs on the stack and save the registers there */
+
+	tophys  %r30,%r9
+	STREG   %r30,PT_GR30(%r9)
+	ldo	PT_SZ_ALGN(%r30),%r30
+	STREG   %r29,PT_GR29(%r9)
+	STREG   %r26,PT_GR26(%r9)
+	copy    %r9,%r29
 	.endm
 
-	/* Use def to enable break - KWDB wants em
-	 * (calls traps.c:handle_interruption) */
-	.macro	pass_break code
+	.macro  rest_stack
+	LDREG   PT_GR1(%r29), %r1
+	LDREG   PT_GR30(%r29),%r30
+	LDREG   PT_GR29(%r29),%r29
+	.endm
 
-#else
 	/* default interruption handler
 	 * (calls traps.c:handle_interruption) */
 	.macro	def code
-#endif
-	mtctl	%r29, %cr31
-	mtctl	%r1,  %cr28
-	ldi	\code, %r1
 	b	intr_save
-	mtctl   %r1, %cr29
+	ldi     \code, %r8
 	.align	32
 	.endm
 
 	/* Interrupt interruption handler
-	 * (calls irq.c:do_irq_mask) */
+	 * (calls irq.c:do_cpu_irq_mask) */
 	.macro	extint code
-	mtctl	%r29, %cr31
-	mtctl	%r1,  %cr28
-	mfctl	%cr23, %r1
-	mtctl	%r1, %cr23
 	b	intr_extint
-	mtctl	%r1, %cr29
+	mfsp    %sr7,%r16
 	.align	32
 	.endm	
 
@@ -203,7 +234,6 @@
 	 */
 
 	.macro	itlb_20 code
-
 	mfctl	%pcsq, spc
 #ifdef __LP64__
 	b       itlb_miss_20w
@@ -298,37 +328,27 @@
 	.endm
 	
 #ifndef __LP64__
-	/* nadtlb miss interruption handler (parisc 1.1 - 32 bit)
-	 *
-	 * Note: nadtlb misses will be treated
-	 * as an ordinary dtlb miss for now.
-	 *
-	 */
+	/* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */
 
 	.macro	nadtlb_11 code
 
 	mfctl	%isr,spc
-	b	dtlb_miss_11
+	b       nadtlb_miss_11
 	mfctl	%ior,va
 
 	.align		32
 	.endm
 #endif
 	
-	/* nadtlb miss interruption handler (parisc 2.0)
-	 *
-	 * Note: nadtlb misses will be treated
-	 * as an ordinary dtlb miss for now.
-	 *
-	 */
+	/* nadtlb miss interruption handler (parisc 2.0) */
 
 	.macro	nadtlb_20 code
 
 	mfctl	%isr,spc
 #ifdef __LP64__
-	b       dtlb_miss_20w
+	b       nadtlb_miss_20w
 #else
-	b	dtlb_miss_20
+	b       nadtlb_miss_20
 #endif
 	mfctl	%ior,va
 
@@ -372,13 +392,14 @@
 	 * fault_vector_11 and fault_vector_20 are on the
 	 * same page. This is only necessary as long as we
 	 * write protect the kernel text, which we may stop
-	 * doing once we use large parge translations to cover
+	 * doing once we use large page translations to cover
 	 * the static part of the kernel address space.
 	 */
 
-
 	.export fault_vector_20
 
+	.text
+
 	.align 4096
 
 fault_vector_20:
@@ -402,7 +423,11 @@
 	def		13
 	def		14
 	dtlb_20		15
+#if 0
 	naitlb_20	16
+#else
+	def             16
+#endif
 	nadtlb_20	17
 	def		18
 	def		19
@@ -446,7 +471,11 @@
 	def		13
 	def		14
 	dtlb_11		15
+#if 0
 	naitlb_11	16
+#else
+	def             16
+#endif
 	nadtlb_11	17
 	def		18
 	def		19
@@ -467,7 +496,7 @@
 
 	.import		handle_interruption,code
 	.import		handle_real_interruption,code
-	.import		do_irq_mask,code
+	.import		do_cpu_irq_mask,code
 	.import		parisc_stopkernel,code
 	.import		cpu_irq_region,data
 
@@ -492,7 +521,8 @@
 	ldo	PT_SZ_ALGN(%r30),%r30
 #ifdef __LP64__
 	/* Yo, function pointers in wide mode are little structs... -PB */
-	/* XXX FIXME do we need to honor the fptr's %dp value too? */
+	ldd	24(%r26), %r2
+	STREG	%r2, PT_GR27(%r1)	/* Store childs %dp */
 	ldd	16(%r26), %r26
 #endif
 	STREG	%r26, PT_GR26(%r1)  /* Store function & argument for child */
@@ -500,15 +530,17 @@
 	ldo	CLONE_VM(%r0), %r26   /* Force CLONE_VM since only init_mm */
 	or	%r26, %r24, %r26      /* will have kernel mappings.	 */
 	copy	%r0, %r25
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 	bl	do_fork, %r2
 	copy	%r1, %r24
 
 	/* Parent Returns here */
 
-	ldo	-PT_SZ_ALGN(%r30), %r30
-	LDREG	-RP_OFFSET(%r30), %r2
+	LDREG	-PT_SZ_ALGN-RP_OFFSET(%r30), %r2
 	bv	%r0(%r2)
-	nop
+	ldo	-PT_SZ_ALGN(%r30), %r30
 
 	/*
 	 * Child Returns here
@@ -520,11 +552,22 @@
 	.export	ret_from_kernel_thread
 ret_from_kernel_thread:
 
+	/* Call schedule_tail first though */
+	bl	schedule_tail, %r2
+	nop
+
 	LDREG	TASK_PT_GR26-TASK_SZ_ALGN(%r30), %r1
 	LDREG	TASK_PT_GR25-TASK_SZ_ALGN(%r30), %r26
+#ifdef __LP64__
+	LDREG	TASK_PT_GR27-TASK_SZ_ALGN(%r30), %r27
+#endif
 	ble	0(%sr7, %r1)
 	copy	%r31, %r2
 
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+	loadgp				/* Thread could have been in a module */
+#endif
 	b	sys_exit
 	ldi	0, %r26
 
@@ -532,23 +575,22 @@
 	.export	__execve, code
 __execve:
 	copy	%r2, %r15
-	copy	%r23, %r17
 	copy	%r30, %r16
 	ldo	PT_SZ_ALGN(%r30), %r30
 	STREG	%r26, PT_GR26(%r16)
 	STREG	%r25, PT_GR25(%r16)
 	STREG	%r24, PT_GR24(%r16)
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 	bl	sys_execve, %r2
 	copy	%r16, %r26
 
-	comib,<>,n 0,%r28,__execve_failed
-
-	b	intr_return
-	STREG	%r17, PT_CR30(%r16)
+	cmpib,=,n 0,%r28,intr_return    /* forward */
 
-__execve_failed:
 	/* yes, this will trap and die. */
 	copy	%r15, %r2
+	copy	%r16, %r30
 	bv	%r0(%r2)
 	nop
 
@@ -567,16 +609,14 @@
 
 	ldil	L%_switch_to_ret, %r2
 	ldo	R%_switch_to_ret(%r2), %r2
-	LDIL_FIXUP(%r2)
 
 	STREG	%r2, TASK_PT_KPC(%r26)
 	LDREG	TASK_PT_KPC(%r25), %r2
 
 	STREG	%r30, TASK_PT_KSP(%r26)
 	LDREG	TASK_PT_KSP(%r25), %r30
-
 	bv	%r0(%r2)
-	nop
+	mtctl   %r25,%cr30
 
 _switch_to_ret:
 	mtctl	%r0, %cr0		/* Needed for single stepping */
@@ -587,27 +627,30 @@
 	copy	%r26, %r28
 
 	/*
-	 * Common rfi return path for interruptions, kernel execve, and some
-	 * syscalls.  The sys_rt_sigreturn syscall will return via this path
-	 * if the signal was received when the process was running; if the
-	 * process was blocked on a syscall then the normal syscall_exit
-	 * path is used.  All syscalls for traced proceses exit via
-	 * intr_restore.
-	 * Note that the following code uses a "relied upon translation". See
-	 * the parisc ACD for details. The ssm is necessary due to a PCXT bug.
+	 * Common rfi return path for interruptions, kernel execve, and
+	 * sys_rt_sigreturn (sometimes).  The sys_rt_sigreturn syscall will
+	 * return via this path if the signal was received when the process
+	 * was running; if the process was blocked on a syscall then the
+	 * normal syscall_exit path is used.  All syscalls for traced
+	 * proceses exit via intr_restore.
+	 *
+	 * XXX If any syscalls that change a processes space id ever exit
+	 * this way, then we will need to copy %sr3 in to PT_SR[3..7], and
+	 * adjust IASQ[0..1].
+	 *
+	 * Note that the following code uses a "relied upon translation".
+	 * See the parisc ACD for details. The ssm is necessary due to a
+	 * PCXT bug.
 	 */
 
 	.align 4096
 
 	.export	syscall_exit_rfi
 syscall_exit_rfi:
-	copy    %r30,%r16
-	/* FIXME! depi below has hardcoded dependency on kernel stack size */
-	depi    0,31,14,%r16 /* get task pointer */
+	mfctl   %cr30,%r16
 	ldo	TASK_REGS(%r16),%r16
 	/* Force iaoq to userspace, as the user has had access to our current
-	 * context via sigcontext.
-	 * XXX do we need any other protection here?
+	 * context via sigcontext. Also Filter the PSW for the same reason.
 	 */
 	LDREG	PT_IAOQ0(%r16),%r19
 	depi	3,31,2,%r19
@@ -615,57 +658,84 @@
 	LDREG	PT_IAOQ1(%r16),%r19
 	depi	3,31,2,%r19
 	STREG	%r19,PT_IAOQ1(%r16)
-	
+	LDREG   PT_PSW(%r16),%r19
+	ldil    L%USER_PSW_MASK,%r1
+	ldo     R%USER_PSW_MASK(%r1),%r1
+#ifdef __LP64__
+	ldil    L%USER_PSW_HI_MASK,%r20
+	ldo     R%USER_PSW_HI_MASK(%r20),%r20
+	depd    %r20,31,32,%r1
+#endif
+	and     %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
+	ldil    L%USER_PSW,%r1
+	ldo     R%USER_PSW(%r1),%r1
+	or      %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
+	STREG   %r19,PT_PSW(%r16)
+
+	/*
+	 * If we aren't being traced, we never saved space registers
+	 * (we don't store them in the sigcontext), so set them
+	 * to "proper" values now (otherwise we'll wind up restoring
+	 * whatever was last stored in the task structure, which might
+	 * be inconsistant if an interrupt occured while on the gateway
+	 * page) Note that we may be "trashing" values the user put in
+	 * them, but we don't support the the user changing them.
+	 */
+
+	STREG   %r0,PT_SR2(%r16)
+	mfsp    %sr3,%r19
+	STREG   %r19,PT_SR0(%r16)
+	STREG   %r19,PT_SR1(%r16)
+	STREG   %r19,PT_SR3(%r16)
+	STREG   %r19,PT_SR4(%r16)
+	STREG   %r19,PT_SR5(%r16)
+	STREG   %r19,PT_SR6(%r16)
+	STREG   %r19,PT_SR7(%r16)
+
 intr_return:
+	ssm     PSW_SM_I, %r0
 
 	/* Check for software interrupts */
 
 	.import irq_stat,data
 
-	ldil    L%irq_stat,%r19
-	ldo     R%irq_stat(%r19),%r19
-	LDIL_FIXUP(%r19)
-
+	ldil	L%irq_stat,%r19
+	ldo	R%irq_stat(%r19),%r19
 #ifdef CONFIG_SMP
-	copy    %r30,%r1
-	/* FIXME! depi below has hardcoded dependency on kernel stack size */
-	depi    0,31,14,%r1 /* get task pointer */
-	ldw     TASK_PROCESSOR(%r1),%r20 /* get cpu # - int */
-#if (IRQSTAT_SZ == 32)
-	dep     %r20,26,27,%r20 /* shift left 5 bits */
-#else
-#error IRQSTAT_SZ changed, fix dep
-#endif /* IRQSTAT_SZ */
-	add     %r19,%r20,%r19
+	mfctl   %cr30,%r1
+	ldw	TASK_PROCESSOR(%r1),%r1 /* get cpu # - int */
+	/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
+	** irq_stat[] is defined using ____cacheline_aligned.
+	*/
+#ifdef __LP64__
+	shld	%r1, 6, %r20
+#else
+	shlw	%r1, 5, %r20
+#endif
+	add     %r19,%r20,%r19	/* now have &irq_stat[smp_processor_id()] */
 #endif /* CONFIG_SMP */
 
-	ldw     IRQSTAT_SI_ACTIVE(%r19),%r20	/* hardirq.h: unsigned int */
-	ldw     IRQSTAT_SI_MASK(%r19),%r19	/* hardirq.h: unsigned int */
-	and     %r19,%r20,%r20
-	comib,<>,n 0,%r20,intr_do_softirq /* forward */
+	LDREG   IRQSTAT_SIRQ_PEND(%r19),%r20    /* hardirq.h: unsigned long */
+	cmpib,<>,n 0,%r20,intr_do_softirq /* forward */
 
 intr_check_resched:
 
 	/* check for reschedule */
-	copy    %r30,%r1
-	/* FIXME! depi below has hardcoded dependency on kernel stack size */
-	depi    0,31,14,%r1 /* get task pointer */
+	mfctl   %cr30,%r1
 	LDREG     TASK_NEED_RESCHED(%r1),%r19	/* sched.h: long need_resched */
-	comib,<>,n 0,%r19,intr_do_resched /* forward */
+	CMPIB<>,n 0,%r19,intr_do_resched /* forward */
 
 intr_check_sig:
 	/* As above */
-	copy    %r30,%r1
-	depi    0,31,14,%r1 /* get task pointer */
+	mfctl   %cr30,%r1
 	ldw	TASK_SIGPENDING(%r1),%r19	/* sched.h: int sigpending */
-	comib,<>,n 0,%r19,intr_do_signal /* forward */
+	cmpib,<>,n 0,%r19,intr_do_signal /* forward */
 
 intr_restore:
-	copy	    	%r16, %r29
-	ldo		PT_FR31(%r29), %r29
-	rest_fp		%r29
-	copy    	%r16, %r29
-	rest_general 	%r29
+	copy            %r16,%r29
+	ldo             PT_FR31(%r29),%r1
+	rest_fp         %r1
+	rest_general    %r29
 	ssm		0,%r0
 	nop
 	nop
@@ -674,10 +744,10 @@
 	nop
 	nop
 	nop
-	tophys		%r29
-	mtsm		%r0
+	tophys_r1       %r29
+	rsm             (PSW_SM_Q|PSW_SM_P|PSW_SM_D|PSW_SM_I),%r0
 	rest_specials	%r29
-	rest_stack	%r29
+	rest_stack
 	rfi
 	nop
 	nop
@@ -691,88 +761,175 @@
 	.import do_softirq,code
 intr_do_softirq:
 	bl      do_softirq,%r2
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	nop
+#endif
 	b       intr_check_resched
 	nop
 
 	.import schedule,code
 intr_do_resched:
 	/* Only do reschedule if we are returning to user space */
-	LDREG     PT_SR7(%r16), %r20
-	comib,= 0,%r20,intr_restore /* backward */
+	LDREG   PT_IASQ0(%r16), %r20
+	CMPIB= 0,%r20,intr_restore /* backward */
+	nop
+	LDREG   PT_IASQ1(%r16), %r20
+	CMPIB= 0,%r20,intr_restore /* backward */
 	nop
 
-	bl      schedule,%r2
-	ssm     PSW_SM_I, %r0
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
+
+	ldil	L%intr_return, %r2
+	b	schedule
+	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
 
-	/* It's OK to leave I bit on */
-	b       intr_return /* start over if we got a resched */
-	nop
 
 	.import do_signal,code
 intr_do_signal:
 	/* Only do signals if we are returning to user space */
-	LDREG   PT_SR7(%r16), %r20
-	comib,= 0,%r20,intr_restore /* backward */
+	LDREG   PT_IASQ0(%r16), %r20
+	CMPIB= 0,%r20,intr_restore /* backward */
+	nop
+	LDREG   PT_IASQ1(%r16), %r20
+	CMPIB= 0,%r20,intr_restore /* backward */
 	nop
 
 	copy	%r0, %r24			/* unsigned long in_syscall */
 	copy	%r16, %r25			/* struct pt_regs *regs */
 	ssm     PSW_SM_I, %r0
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#endif
 	bl	do_signal,%r2
 	copy	%r0, %r26			/* sigset_t *oldset = NULL */
 
 	b	intr_restore
 	nop
 
-	/* CR28 - saved GR1
-	 * CR29 - argument for do_irq_mask */
+	/*
+	 * External interrupts.
+	 */
 
-	/* External interrupts */
 intr_extint:
-	get_stack
+	CMPIB=,n 0,%r16,1f
+	get_stack_use_cr30
+	b,n 3f
+
+1:
+#if 0  /* Interrupt Stack support not working yet! */
+	mfctl	%cr31,%r1
+	copy	%r30,%r17
+	/* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/
+#ifdef __LP64__
+	depdi	0,63,15,%r17
+#else
+	depi	0,31,15,%r17
+#endif
+	CMPB=,n	%r1,%r17,2f
+	get_stack_use_cr31
+	b,n 3f
+#endif
+2:
+	get_stack_use_r30
+
+3:
 	save_specials	%r29
-	virt_map	rfi
+	virt_map
 	save_general	%r29
 
-	ldo		PT_FR0(%r29), %r24
-	save_fp		%r24
+	ldo	PT_FR0(%r29), %r24
+	save_fp	%r24
 	
 	loadgp
 
-	copy		%r29, %r24	/* arg2 is pt_regs */
-	copy		%r29, %r16	/* save pt_regs */
+	copy	%r29, %r25	/* arg1 is pt_regs */
+	copy	%r29, %r16	/* save pt_regs */
 #ifdef CONFIG_KWDB
-	copy		%r29, %r3	/* KWDB - update frame pointer (gr3) */
+	copy	%r29, %r3	/* KWDB - update frame pointer (gr3) */
 #endif
 
-	/* sorry to put this cruft in the interrupt path */
-	ldil		L%cpu_irq_region, %r25
-	ldo		R%cpu_irq_region(%r25), %r25
-	bl		do_irq_mask,%r2
 #ifdef __LP64__
-	LDIL_FIXUP(%r25)
+	ldo	-16(%r30),%r29	/* Reference param save area */
 #else
 	nop
 #endif
-
-	b		intr_return
-	nop
+	
+	/*
+	 * We need to either load the CPU's ID or IRQ region.
+	 * Until we have "per CPU" IRQ regions, this is easy.
+	 */
+	ldil	L%cpu_irq_region, %r26
+	ldil	L%intr_return, %r2
+	ldo	R%cpu_irq_region(%r26), %r26
+	
+	b	do_cpu_irq_mask
+	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
 
 	/* Generic interruptions (illegal insn, unaligned, page fault, etc) */
 
 	.export         intr_save, code /* for os_hpmc */
 
 intr_save:
-	get_stack
+	mfsp    %sr7,%r16
+	CMPIB=,n 0,%r16,1f
+	get_stack_use_cr30
+	b	2f
+	copy    %r8,%r26
+
+1:
+	get_stack_use_r30
+	copy    %r8,%r26
+
+2:
 	save_specials	%r29
 
-	mfctl		%cr20, %r1
-	STREG		%r1, PT_ISR(%r29)
-	mfctl		%cr21, %r1
-	STREG		%r1, PT_IOR(%r29)
+	/* If this trap is a itlb miss, skip saving/adjusting isr/ior */
+
+	/*
+	 * FIXME: 1) Use a #define for the hardwired "6" below (and in
+	 *           traps.c.
+	 *        2) Once we start executing code above 4 Gb, we need
+	 *           to adjust iasq/iaoq here in the same way we
+	 *           adjust isr/ior below.
+	 */
+
+	CMPIB=,n        6,%r26,skip_save_ior
+
+	/* save_specials left ipsw value in r8 for us to test */
+
+	mfctl           %cr20, %r16 /* isr */
+	mfctl           %cr21, %r17 /* ior */
+
+#ifdef __LP64__
+	/*
+	 * If the interrupted code was running with W bit off (32 bit),
+	 * clear the b bits (bits 0 & 1) in the ior.
+	 */
+	extrd,u,*<>     %r8,PSW_W_BIT,1,%r0
+	depdi           0,1,2,%r17
+
+	/*
+	 * FIXME: This code has hardwired assumptions about the split
+	 *        between space bits and offset bits. This will change
+	 *        when we allow alternate page sizes.
+	 */
+
+	/* adjust isr/ior. */
+
+	extrd,u         %r16,63,7,%r1    /* get high bits from isr for ior */
+	depd            %r1,31,7,%r17    /* deposit them into ior */
+	depdi           0,63,7,%r16      /* clear them from isr */
+#endif
+	STREG           %r16, PT_ISR(%r29)
+	STREG           %r17, PT_IOR(%r29)
+
 
-	virt_map	rfi
+skip_save_ior:
+	virt_map
 	save_general	%r29
 
 	ldo		PT_FR0(%r29), %r25
@@ -785,11 +942,16 @@
 	copy		%r29, %r3	/* KWDB - update frame pointer (gr3) */
 #endif
 
-	bl		handle_interruption,%r2
-	copy		%r29, %r16	/* save pt_regs */
+#ifdef __LP64__
+	ldo		-16(%r30),%r29	/* Reference param save area */
+#endif
+
+	ldil		L%intr_return, %r2
+	copy		%r25, %r16	/* save pt_regs */
+
+	b		handle_interruption
+	ldo		R%intr_return(%r2), %r2	/* return to intr_return */
 
-	b		intr_return
-	nop
 
 	/*
 	 * Note for all tlb miss handlers:
@@ -821,10 +983,9 @@
 #ifdef __LP64__
 
 dtlb_miss_20w:
-
-	extrd,u         spc,31,7,t1     /* adjust va */
+	extrd,u         spc,63,7,t1     /* adjust va */
 	depd            t1,31,7,va      /* adjust va */
-	depdi           0,31,7,spc      /* adjust space */
+	depdi           0,63,7,spc      /* adjust space */
 	mfctl           %cr25,ptp	/* Assume user space miss */
 	or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
 	mfctl           %cr24,ptp	/* Load kernel pgd instead */
@@ -832,20 +993,20 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dtlb_fault /* forward */
+	cmpb,*<>,n       t0,spc,dtlb_fault /* forward */
 
 	/* First level page table lookup */
 
 	ldd,s           t1(ptp),ptp
 	extrd,u         va,42,9,t0     /* get second-level index */
-	bb,>=,n 	ptp,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
 	depdi           0,63,12,ptp     /* clear prot bits */
 
 	/* Second level page table lookup */
 
 	ldd,s           t0(ptp),ptp
 	extrd,u         va,51,9,t0     /* get third-level index */
-	bb,>=,n 	ptp,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
 	depdi           0,63,12,ptp     /* clear prot bits */
 
 	/* Third level page table lookup */
@@ -853,7 +1014,7 @@
 	shladd           t0,3,ptp,ptp
 	ldi		_PAGE_ACCESSED,t1
 	ldd              0(ptp),pte
-	bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
 
 	/* Check whether the "accessed" bit was set, otherwise do so */
 
@@ -861,11 +1022,9 @@
 	and,*<>         t1,pte,%r0      /* test and nullify if already set */
 	std             t0,0(ptp)       /* write back pte */
 
-	copy            spc,prot	/* init prot with faulting space */
-	
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -874,11 +1033,106 @@
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
 	depdi		0,63,12,pte
-	extrd,u         pte,56,32,pte
-	idtlbt		%r16,%r17
+	extrd,u         pte,56,52,pte
+	idtlbt          pte,prot
 
 	rfir
 	nop
+
+dtlb_check_alias_20w:
+
+	/* Check to see if fault is in the temporary alias region */
+
+	cmpib,*<>,n     0,spc,dtlb_fault /* forward */
+	ldil            L%(TMPALIAS_MAP_START),t0
+	copy            va,t1
+	depdi           0,63,23,t1
+	cmpb,*<>,n      t0,t1,dtlb_fault /* forward */
+	ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
+	depd,z          prot,8,7,prot
+
+	/*
+	 * OK, it is in the temp alias region, check whether "from" or "to".
+	 * Check "subtle" note in pacache.S re: r23/r26.
+	 */
+
+	extrd,u,*=      va,41,1,r0
+	or,*tr          %r23,%r0,pte    /* If "from" use "from" page */
+	or,*            %r26,%r0,pte    /* else "to", use "to" page  */
+
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
+nadtlb_miss_20w:
+	extrd,u         spc,63,7,t1     /* adjust va */
+	depd            t1,31,7,va      /* adjust va */
+	depdi           0,63,7,spc      /* adjust space */
+	mfctl           %cr25,ptp	/* Assume user space miss */
+	or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
+	mfctl           %cr24,ptp	/* Load kernel pgd instead */
+	extrd,u         va,33,9,t1      /* Get pgd index */
+
+	mfsp            %sr7,t0		/* Get current space */
+	or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
+	cmpb,*<>,n       t0,spc,nadtlb_fault /* forward */
+
+	/* First level page table lookup */
+
+	ldd,s           t1(ptp),ptp
+	extrd,u         va,42,9,t0     /* get second-level index */
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+	depdi           0,63,12,ptp     /* clear prot bits */
+
+	/* Second level page table lookup */
+
+	ldd,s           t0(ptp),ptp
+	extrd,u         va,51,9,t0     /* get third-level index */
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+	depdi           0,63,12,ptp     /* clear prot bits */
+
+	/* Third level page table lookup */
+
+	shladd           t0,3,ptp,ptp
+	ldi		_PAGE_ACCESSED,t1
+	ldd              0(ptp),pte
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20w
+
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
+	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
+	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
+	depdi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
+
+	/* Get rid of prot bits and convert to page addr for idtlbt */
+
+	depdi		0,63,12,pte
+	extrd,u         pte,56,52,pte
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
+nadtlb_check_flush_20w:
+	bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
+
+	/* Insert a "flush only" translation */
+
+	depdi,z         7,7,3,prot
+	depdi           1,10,1,prot
+
+	/* Get rid of prot bits and convert to page addr for idtlbt */
+
+	depdi		0,63,12,pte
+	extrd,u         pte,56,52,pte
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
 #else
 
 dtlb_miss_11:
@@ -889,13 +1143,13 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dtlb_fault /* forward */
+	cmpb,<>,n       t0,spc,dtlb_fault /* forward */
 
 	/* First level page table lookup */
 
 	ldwx,s		t1(ptp),ptp
 	extru		va,19,10,t0	/* get second-level index */
-	bb,>=,n 	ptp,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11
 	depi		0,31,12,ptp	/* clear prot bits */
 
 	/* Second level page table lookup */
@@ -903,7 +1157,7 @@
 	sh2addl 	 t0,ptp,ptp
 	ldi		_PAGE_ACCESSED,t1
 	ldw		 0(ptp),pte
-	bb,>=,n 	 pte,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11
 
 	/* Check whether the "accessed" bit was set, otherwise do so */
 
@@ -911,8 +1165,8 @@
 	and,<>		t1,pte,%r0	/* test and nullify if already set */
 	stw		t0,0(ptp)	/* write back pte */
 
-	copy            spc,prot	/* init prot with faulting space */
-	dep		pte,8,7,prot
+	zdep            spc,30,15,prot  /* create prot id from space */
+	dep             pte,8,7,prot    /* add in prot bits from pte */
 
 	extru,=		pte,_PAGE_NO_CACHE_BIT,1,r0
 	depi		1,12,1,prot
@@ -937,9 +1191,108 @@
 	rfir
 	nop
 
-dtlb_miss_20:
-	.level 2.0
+dtlb_check_alias_11:
+
+	/* Check to see if fault is in the temporary alias region */
+
+	cmpib,<>,n      0,spc,dtlb_fault /* forward */
+	ldil            L%(TMPALIAS_MAP_START),t0
+	copy            va,t1
+	depwi           0,31,23,t1
+	cmpb,<>,n       t0,t1,dtlb_fault /* forward */
+	ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
+	depw,z          prot,8,7,prot
+
+	/*
+	 * OK, it is in the temp alias region, check whether "from" or "to".
+	 * Check "subtle" note in pacache.S re: r23/r26.
+	 */
+
+	extrw,u,=       va,9,1,r0
+	or,tr           %r23,%r0,pte    /* If "from" use "from" page */
+	or              %r26,%r0,pte    /* else "to", use "to" page  */
+
+	idtlba          pte,(va)
+	idtlbp          prot,(va)
+
+	rfir
+	nop
+
+nadtlb_miss_11:
+	mfctl           %cr25,ptp	/* Assume user space miss */
+	or,<>           %r0,spc,%r0	/* If it is user space, nullify */
+	mfctl           %cr24,ptp	/* Load kernel pgd instead */
+	extru		va,9,10,t1	/* Get pgd index */
+
+	mfsp            %sr7,t0		/* Get current space */
+	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
+	cmpb,<>,n       t0,spc,nadtlb_fault /* forward */
+
+	/* First level page table lookup */
+
+	ldwx,s		t1(ptp),ptp
+	extru		va,19,10,t0	/* get second-level index */
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+	depi		0,31,12,ptp	/* clear prot bits */
+
+	/* Second level page table lookup */
+
+	sh2addl 	 t0,ptp,ptp
+	ldi		_PAGE_ACCESSED,t1
+	ldw		 0(ptp),pte
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_11
+
+	zdep            spc,30,15,prot  /* create prot id from space */
+	dep             pte,8,7,prot    /* add in prot bits from pte */
+
+	extru,=		pte,_PAGE_NO_CACHE_BIT,1,r0
+	depi		1,12,1,prot
+	extru,=         pte,_PAGE_USER_BIT,1,r0
+	depi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
+	extru,= 	pte,_PAGE_GATEWAY_BIT,1,r0
+	depi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
+
+	/* Get rid of prot bits and convert to page addr for idtlba */
+
+	depi		0,31,12,pte
+	extru		pte,24,25,pte
+
+	mfsp		%sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+	mtsp		spc,%sr1
+
+	idtlba		pte,(%sr1,va)
+	idtlbp		prot,(%sr1,va)
+
+	mtsp		t0, %sr1	/* Restore sr1 */
+
+	rfir
+	nop
+
+nadtlb_check_flush_11:
+	bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
+
+	/* Insert a "flush only" translation */
+
+	zdepi           7,7,3,prot
+	depi            1,10,1,prot
+
+	/* Get rid of prot bits and convert to page addr for idtlba */
+
+	depi		0,31,12,pte
+	extru		pte,24,25,pte
 
+	mfsp		%sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+	mtsp		spc,%sr1
+
+	idtlba		pte,(%sr1,va)
+	idtlbp		prot,(%sr1,va)
+
+	mtsp		t0, %sr1	/* Restore sr1 */
+
+	rfir
+	nop
+
+dtlb_miss_20:
 	mfctl           %cr25,ptp	/* Assume user space miss */
 	or,<>           %r0,spc,%r0	/* If it is user space, nullify */
 	mfctl           %cr24,ptp	/* Load kernel pgd instead */
@@ -947,13 +1300,13 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dtlb_fault /* forward */
+	cmpb,<>,n       t0,spc,dtlb_fault /* forward */
 
 	/* First level page table lookup */
 
 	ldwx,s		t1(ptp),ptp
 	extru		va,19,10,t0	/* get second-level index */
-	bb,>=,n 	ptp,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20
 	depi		0,31,12,ptp	/* clear prot bits */
 
 	/* Second level page table lookup */
@@ -961,7 +1314,7 @@
 	sh2addl 	 t0,ptp,ptp
 	ldi		_PAGE_ACCESSED,t1
 	ldw		 0(ptp),pte
-	bb,>=,n 	 pte,_PAGE_PRESENT_BIT,dtlb_fault
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20
 
 	/* Check whether the "accessed" bit was set, otherwise do so */
 
@@ -969,11 +1322,9 @@
 	and,<>		t1,pte,%r0	/* test and nullify if already set */
 	stw		t0,0(ptp)	/* write back pte */
 
-	copy            spc,prot	/* init prot with faulting space */
-	
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -981,16 +1332,145 @@
 
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
-	depdi		0,63,12,pte
-	extrd,u		pte,56,25,pte
-	idtlbt		%r16,%r17
+	extrd,s         pte,35,4,t0
+	depdi		0,63,12,pte	/* clear lower 12 bits */
+        addi,=          1,t0,0 
+        extrd,u,*tr     pte,56,25,pte 
+	extrd,s		pte,56,25,pte	/* bit 31:8 >> 8  */ 
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
+dtlb_check_alias_20:
+
+	/* Check to see if fault is in the temporary alias region */
 
-	.level		1.1
+	cmpib,<>,n      0,spc,dtlb_fault /* forward */
+	ldil            L%(TMPALIAS_MAP_START),t0
+	copy            va,t1
+	depwi           0,31,23,t1
+	cmpb,<>,n       t0,t1,dtlb_fault /* forward */
+	ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
+	depd,z          prot,8,7,prot
+
+	/*
+	 * OK, it is in the temp alias region, check whether "from" or "to".
+	 * Check "subtle" note in pacache.S re: r23/r26.
+	 */
+
+	extrw,u,=       va,9,1,r0
+	or,tr           %r23,%r0,pte    /* If "from" use "from" page */
+	or              %r26,%r0,pte    /* else "to", use "to" page  */
+
+	idtlbt          pte,prot
+
+	rfir
+	nop
+
+nadtlb_miss_20:
+	mfctl           %cr25,ptp	/* Assume user space miss */
+	or,<>           %r0,spc,%r0	/* If it is user space, nullify */
+	mfctl           %cr24,ptp	/* Load kernel pgd instead */
+	extru		va,9,10,t1	/* Get pgd index */
+
+	mfsp            %sr7,t0		/* Get current space */
+	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
+	cmpb,<>,n       t0,spc,nadtlb_fault /* forward */
+
+	/* First level page table lookup */
+
+	ldwx,s		t1(ptp),ptp
+	extru		va,19,10,t0	/* get second-level index */
+	bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+	depi		0,31,12,ptp	/* clear prot bits */
+
+	/* Second level page table lookup */
+
+	sh2addl 	 t0,ptp,ptp
+	ldi		_PAGE_ACCESSED,t1
+	ldw		 0(ptp),pte
+	bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20
+
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
+	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
+	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
+	depdi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
+
+	/* Get rid of prot bits and convert to page addr for idtlbt */
+
+        extrd,s         pte,35,4,t0
+        depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0
+        extrd,u,*tr     pte,56,25,pte
+        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+        idtlbt          pte,prot
+
+	rfir
+	nop
+
+nadtlb_check_flush_20:
+	bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
+
+	/* Insert a "flush only" translation */
+
+	depdi,z         7,7,3,prot
+	depdi           1,10,1,prot
+
+	/* Get rid of prot bits and convert to page addr for idtlbt */
+
+	depdi		0,63,12,pte
+	extrd,u         pte,56,32,pte
+	idtlbt          pte,prot
 
 	rfir
 	nop
 #endif
 
+nadtlb_emulate:
+
+	/*
+	 * Non access misses can be caused by fdc,fic,pdc,lpa,probe and
+	 * probei instructions. We don't want to fault for these
+	 * instructions (not only does it not make sense, it can cause
+	 * deadlocks, since some flushes are done with the mmap
+	 * semaphore held). If the translation doesn't exist, we can't
+	 * insert a translation, so have to emulate the side effects
+	 * of the instruction. Since we don't insert a translation
+	 * we can get a lot of faults during a flush loop, so it makes
+	 * sense to try to do it here with minimum overhead. We only
+	 * emulate fdc,fic & pdc instructions whose base and index
+	 * registers are not shadowed. We defer everything else to the
+	 * "slow" path.
+	 */
+
+	mfctl           %cr19,%r9 /* Get iir */
+	ldi             0x280,%r16
+	and             %r9,%r16,%r17
+	cmpb,<>,n       %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */
+	bb,>=,n         %r9,26,nadtlb_nullify  /* m bit not set, just nullify */
+	b,l             get_register,%r25
+	extrw,u         %r9,15,5,%r8           /* Get index register # */
+	CMPIB=,n        -1,%r1,nadtlb_fault    /* have to use slow path */
+	copy            %r1,%r24
+	b,l             get_register,%r25
+	extrw,u         %r9,10,5,%r8           /* Get base register # */
+	CMPIB=,n        -1,%r1,nadtlb_fault    /* have to use slow path */
+	b,l             set_register,%r25
+	add,l           %r1,%r24,%r1           /* doesn't affect c/b bits */
+
+nadtlb_nullify:
+	mfctl           %cr22,%r8              /* Get ipsw */
+	ldil            L%PSW_N,%r9
+	or              %r8,%r9,%r8            /* Set PSW_N */
+	mtctl           %r8,%cr22
+
+	rfir
+	nop
+
 #ifdef __LP64__
 itlb_miss_20w:
 
@@ -999,9 +1479,9 @@
 	 * on the gateway page which is in the kernel address space.
 	 */
 
-	extrd,u         spc,31,7,t1     /* adjust va */
+	extrd,u         spc,63,7,t1     /* adjust va */
 	depd            t1,31,7,va      /* adjust va */
-	depdi           0,31,7,spc      /* adjust space */
+	depdi           0,63,7,spc      /* adjust space */
 	cmpib,*=        0,spc,itlb_miss_kernel_20w
 	extrd,u         va,33,9,t1      /* Get pgd index */
 
@@ -1039,11 +1519,9 @@
 	and,*<>         t1,pte,%r0      /* test and nullify if already set */
 	std             t0,0(ptp)       /* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -1053,7 +1531,7 @@
 
 	depdi		0,63,12,pte
 	extrd,u         pte,56,32,pte
-	iitlbt          %r16,%r17
+	iitlbt          pte,prot
 
 	rfir
 	nop
@@ -1070,14 +1548,14 @@
 	 * on the gateway page which is in the kernel address space.
 	 */
 
-	comib,=         0,spc,itlb_miss_kernel_11
+	cmpib,=         0,spc,itlb_miss_kernel_11
 	extru		va,9,10,t1	/* Get pgd index */
 
 	mfctl           %cr25,ptp	/* load user pgd */
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,itlb_fault /* forward */
+	cmpb,<>,n       t0,spc,itlb_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1100,8 +1578,8 @@
 	and,<>		t1,pte,%r0	/* test and nullify if already set */
 	stw		t0,0(ptp)	/* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	dep		pte,8,7,prot
+	zdep            spc,30,15,prot  /* create prot id from space */
+	dep             pte,8,7,prot    /* add in prot bits from pte */
 
 	extru,=		pte,_PAGE_NO_CACHE_BIT,1,r0
 	depi		1,12,1,prot
@@ -1137,14 +1615,14 @@
 	 * on the gateway page which is in the kernel address space.
 	 */
 
-	comib,=         0,spc,itlb_miss_kernel_20
+	cmpib,=         0,spc,itlb_miss_kernel_20
 	extru		va,9,10,t1	/* Get pgd index */
 
 	mfctl           %cr25,ptp	/* load user pgd */
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,itlb_fault /* forward */
+	cmpb,<>,n       t0,spc,itlb_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1167,13 +1645,9 @@
 	and,<>		t1,pte,%r0	/* test and nullify if already set */
 	stw		t0,0(ptp)	/* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	
-	.level 2.0
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
 
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -1181,10 +1655,12 @@
 
 	/* Get rid of prot bits and convert to page addr for iitlbt */
 
-	depdi		0,63,12,pte
-	extrd,u		pte,56,25,pte
-	iitlbt          %r16,%r17
-	.level		1.1
+        extrd,s         pte,35,4,t0 
+        depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0
+        extrd,u,*tr     pte,56,25,pte 
+        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+	iitlbt          pte,prot
 
 	rfir
 	nop
@@ -1198,11 +1674,10 @@
 #ifdef __LP64__
 
 dbit_trap_20w:
-
-	extrd,u         spc,31,7,t1     /* adjust va */
+	extrd,u         spc,63,7,t1     /* adjust va */
 	depd            t1,31,7,va      /* adjust va */
 	depdi           0,1,2,va        /* adjust va */
-	depdi           0,31,7,spc      /* adjust space */
+	depdi           0,63,7,spc      /* adjust space */
 	mfctl           %cr25,ptp	/* Assume user space miss */
 	or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
 	mfctl           %cr24,ptp	/* Load kernel pgd instead */
@@ -1210,7 +1685,7 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dbit_fault /* forward */
+	cmpb,*<>,n       t0,spc,dbit_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1229,6 +1704,18 @@
 	/* Third level page table lookup */
 
 	shladd           t0,3,ptp,ptp
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nolock_20w
+	ldil            L%PA(pa_dbit_lock),t0
+	ldo             R%PA(pa_dbit_lock)(t0),t0
+
+dbit_spin_20w:
+	ldcw            0(t0),t1
+	cmpib,=         0,t1,dbit_spin_20w
+	nop
+
+dbit_nolock_20w:
+#endif
 	ldi		(_PAGE_ACCESSED|_PAGE_DIRTY),t1
 	ldd              0(ptp),pte
 	bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
@@ -1238,11 +1725,9 @@
 	or		t1,pte,pte
 	std             pte,0(ptp)      /* write back pte */
 
-	copy            spc,prot	/* init prot with faulting space */
-	
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
+
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -1251,8 +1736,15 @@
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
 	depdi		0,63,12,pte
-	extrd,u         pte,56,32,pte
-	idtlbt		%r16,%r17
+	extrd,u         pte,56,52,pte
+	idtlbt          pte,prot
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nounlock_20w
+	ldi             1,t1
+	stw             t1,0(t0)
+
+dbit_nounlock_20w:
+#endif
 
 	rfir
 	nop
@@ -1266,7 +1758,7 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dbit_fault /* forward */
+	cmpb,<>,n       t0,spc,dbit_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1278,6 +1770,18 @@
 	/* Second level page table lookup */
 
 	sh2addl 	 t0,ptp,ptp
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nolock_11
+	ldil            L%PA(pa_dbit_lock),t0
+	ldo             R%PA(pa_dbit_lock)(t0),t0
+
+dbit_spin_11:
+	ldcw            0(t0),t1
+	cmpib,=         0,t1,dbit_spin_11
+	nop
+
+dbit_nolock_11:
+#endif
 	ldi		(_PAGE_ACCESSED|_PAGE_DIRTY),t1
 	ldw		 0(ptp),pte
 	bb,>=,n 	 pte,_PAGE_PRESENT_BIT,dbit_fault
@@ -1287,8 +1791,8 @@
 	or		t1,pte,pte
 	stw		pte,0(ptp)	/* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	dep		pte,8,7,prot
+	zdep            spc,30,15,prot  /* create prot id from space */
+	dep             pte,8,7,prot    /* add in prot bits from pte */
 
 	extru,=		pte,_PAGE_NO_CACHE_BIT,1,r0
 	depi		1,12,1,prot
@@ -1302,13 +1806,20 @@
 	depi		0,31,12,pte
 	extru		pte,24,25,pte
 
-	mfsp		%sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+	mfsp            %sr1,t1  /* Save sr1 so we can use it in tlb inserts */
 	mtsp		spc,%sr1
 
 	idtlba		pte,(%sr1,va)
 	idtlbp		prot,(%sr1,va)
 
-	mtsp		t0, %sr1     /* Restore sr1 */
+	mtsp            t1, %sr1     /* Restore sr1 */
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nounlock_11
+	ldi             1,t1
+	stw             t1,0(t0)
+
+dbit_nounlock_11:
+#endif
 
 	rfir
 	nop
@@ -1321,7 +1832,7 @@
 
 	mfsp            %sr7,t0		/* Get current space */
 	or,=            %r0,t0,%r0	/* If kernel, nullify following test */
-	comb,<>,n       t0,spc,dbit_fault /* forward */
+	cmpb,<>,n       t0,spc,dbit_fault /* forward */
 
 	/* First level page table lookup */
 
@@ -1333,6 +1844,18 @@
 	/* Second level page table lookup */
 
 	sh2addl 	 t0,ptp,ptp
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nolock_20
+	ldil            L%PA(pa_dbit_lock),t0
+	ldo             R%PA(pa_dbit_lock)(t0),t0
+
+dbit_spin_20:
+	ldcw            0(t0),t1
+	cmpib,=         0,t1,dbit_spin_20
+	nop
+
+dbit_nolock_20:
+#endif
 	ldi		(_PAGE_ACCESSED|_PAGE_DIRTY),t1
 	ldw		 0(ptp),pte
 	bb,>=,n 	 pte,_PAGE_PRESENT_BIT,dbit_fault
@@ -1342,25 +1865,28 @@
 	or		t1,pte,pte
 	stw		pte,0(ptp)	/* write back pte */
 
-	copy            spc,prot        /* init prot with faulting space */
-	
-	.level 2.0
+	space_to_prot   spc prot        /* create prot id from space */
+	depd            pte,8,7,prot    /* add in prot bits from pte */
 
-	depd		pte,8,7,prot
-	extrd,u,*=	pte,_PAGE_NO_CACHE_BIT+32,1,r0
-	depdi		1,12,1,prot
 	extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
 	depdi		7,11,3,prot   /* Set for user space (1 rsvd for read) */
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
 	depdi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
 
-	/* Get rid of prot bits and convert to page addr for idtlbt */
+        extrd,s         pte,35,4,t0 
+        depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0
+        extrd,u,*tr     pte,56,25,pte 
+        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+        idtlbt          pte,prot
 
-	depdi		0,63,12,pte
-	extrd,u		pte,56,25,pte
-	idtlbt		%r16,%r17
+#ifdef CONFIG_SMP
+	CMPIB=,n        0,spc,dbit_nounlock_20
+	ldi             1,t1
+	stw             t1,0(t0)
 
-	.level		1.1
+dbit_nounlock_20:
+#endif
 
 	rfir
 	nop
@@ -1369,50 +1895,24 @@
 	.import handle_interruption,code
 
 kernel_bad_space:
-	b		tlb_fault
-	ldi		31,%r1	/* Use an unused code */
+	b               intr_save
+	ldi             31,%r8  /* Use an unused code */
 
 dbit_fault:
-	b		tlb_fault
-	ldi		20,%r1
+	b               intr_save
+	ldi             20,%r8
 
 itlb_fault:
-	b		tlb_fault
-	ldi		6,%r1
-
-dtlb_fault:
-	ldi		15,%r1
+	b               intr_save
+	ldi             6,%r8
 
-	/* Fall Through */
+nadtlb_fault:
+	b               intr_save
+	ldi             17,%r8
 
-tlb_fault:
-	mtctl		%r1,%cr29
-	mtctl		%r29,%cr31
-
-	get_stack
-	save_specials	%r29		/* Note this saves a trashed r1 */
-
-	SAVE_CR		(%cr20, PT_ISR(%r29))
-	SAVE_CR		(%cr21, PT_IOR(%r29))
-
-	virt_map	rfir
-
-	STREG		%r1,PT_GR1(%r29)	/* save good value after rfir */
-
-	save_general	%r29
-
-	ldo	PT_FR0(%r29), %r25
-	save_fp		%r25
-	
-	loadgp
-
-	copy		%r29, %r25
-
-	bl		handle_interruption, %r2
-	copy		%r29, %r16
-
-	b		intr_return
-	nop
+dtlb_fault:
+	b               intr_save
+	ldi             15,%r8
 
 	/* Register saving semantics for system calls:
 
@@ -1475,21 +1975,23 @@
 	.endm
 
 	.export sys_fork_wrapper
+	.export child_return
 sys_fork_wrapper:
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1	/* get pt regs */
 	reg_save %r1
+	mfctl	%cr27, %r3
+	STREG	%r3, PT_CR27(%r1)
 
 	STREG	%r2,-RP_OFFSET(%r30)
 	ldo	FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 
 	/* These are call-clobbered registers and therefore
 	   also syscall-clobbered (we hope). */
 	STREG	%r2,PT_GR19(%r1)	/* save for child */
-	STREG	%r30,PT_GR20(%r1)
-	ldil	L%child_return, %r3
-	ldo	R%child_return(%r3), %r3
-	LDIL_FIXUP(%r3)
-	STREG	%r3,PT_GR21(%r1)	/* save for child */
+	STREG	%r30,PT_GR21(%r1)
 
 	LDREG	PT_GR30(%r1),%r25
 	copy	%r1,%r24
@@ -1501,14 +2003,21 @@
 	ldo	-FRAME_SIZE(%r30),%r30		/* get the stackframe */
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1    /* get pt regs */
 
+	LDREG	PT_CR27(%r1), %r3
+	mtctl	%r3, %cr27
 	reg_restore %r1
 
+	/* strace expects syscall # to be preserved in r20 */
+	ldi	__NR_fork,%r20
 	bv %r0(%r2)
-	nop
+	STREG	%r20,PT_GR20(%r1)
 
 	/* Set the return value for the child */
 child_return:
-	LDREG	TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
+	bl	schedule_tail, %r2
+	nop
+
+	LDREG	TASK_PT_GR19-TASK_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30),%r2
 	b	wrapper_exit
 	copy	%r0,%r28
 
@@ -1517,35 +2026,38 @@
 sys_clone_wrapper:
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1	/* get pt regs */
 	reg_save %r1
+	mfctl	%cr27, %r3
+	STREG	%r3, PT_CR27(%r1)
 
 	STREG	%r2,-RP_OFFSET(%r30)
 	ldo	FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 
-	STREG	%r30,PT_GR20(%r1)
-	ldil	L%child_return,%r3
-	ldo	R%child_return(%r3),%r3
-	LDIL_FIXUP(%r3)
-
+	STREG	%r2,PT_GR19(%r1)	/* save for child */
+	STREG	%r30,PT_GR21(%r1)
 	bl	sys_clone,%r2
-	STREG	%r3,PT_GR21(%r1)	/* save for child */
+	copy	%r1,%r24
 
 	b	wrapper_exit
 	LDREG	-RP_OFFSET-FRAME_SIZE(%r30),%r2
 
-
 	.export sys_vfork_wrapper
 sys_vfork_wrapper:
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1	/* get pt regs */
 	reg_save %r1
+	mfctl	%cr27, %r3
+	STREG	%r3, PT_CR27(%r1)
 
 	STREG	%r2,-RP_OFFSET(%r30)
 	ldo	FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 
-	STREG	%r30,PT_GR20(%r1)
-	ldil	L%child_return,%r3
-	ldo	R%child_return(%r3),%r3
-	LDIL_FIXUP(%r3)
-	STREG	%r3,PT_GR21(%r1)	/* save for child */
+	STREG	%r2,PT_GR19(%r1)	/* save for child */
+	STREG	%r30,PT_GR21(%r1)
 
 	bl	sys_vfork,%r2
 	copy	%r1,%r26
@@ -1567,6 +2079,9 @@
 
 	STREG %r2,-RP_OFFSET(%r30)
 	ldo FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#endif
 	bl \execve,%r2
 	copy %r1,%arg0
 
@@ -1576,7 +2091,7 @@
 	/* If exec succeeded we need to load the args */
 
 	ldo -1024(%r0),%r1
-	comb,>>= %r28,%r1,error_\execve
+	cmpb,>>= %r28,%r1,error_\execve
 	copy %r2,%r19
 
 error_\execve:
@@ -1603,8 +2118,14 @@
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r26
 	/* Don't save regs, we are going to restore them from sigcontext. */
 	STREG	%r2, -RP_OFFSET(%r30)
+#ifdef __LP64__
+	ldo	FRAME_SIZE(%r30), %r30
+	bl	sys_rt_sigreturn,%r2
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	bl	sys_rt_sigreturn,%r2
 	ldo	FRAME_SIZE(%r30), %r30
+#endif
 
 	ldo	-FRAME_SIZE(%r30), %r30
 	LDREG	-RP_OFFSET(%r30), %r2
@@ -1625,22 +2146,50 @@
 	/* Get the user stack pointer */
 	LDREG	-TASK_SZ_ALGN-FRAME_SIZE+TASK_PT_GR30(%r30), %r24
 	STREG	%r2, -RP_OFFSET(%r30)
+#ifdef __LP64__
+	ldo	FRAME_SIZE(%r30), %r30
+	bl	do_sigaltstack,%r2
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	bl	do_sigaltstack,%r2
 	ldo	FRAME_SIZE(%r30), %r30
+#endif
 
 	ldo	-FRAME_SIZE(%r30), %r30
 	LDREG	-RP_OFFSET(%r30), %r2
 	bv	%r0(%r2)
 	nop
 
+#ifdef __LP64__
+	.export sys32_sigaltstack_wrapper
+sys32_sigaltstack_wrapper:
+	/* Get the user stack pointer */
+	LDREG	-TASK_SZ_ALGN-FRAME_SIZE+TASK_PT_GR30(%r30), %r24
+	STREG	%r2, -RP_OFFSET(%r30)
+	ldo	FRAME_SIZE(%r30), %r30
+	bl	do_sigaltstack32,%r2
+	ldo	-16(%r30),%r29		/* Reference param save area */
+
+	ldo	-FRAME_SIZE(%r30), %r30
+	LDREG	-RP_OFFSET(%r30), %r2
+	bv	%r0(%r2)
+	nop
+#endif
+
 	.export sys_rt_sigsuspend_wrapper
 sys_rt_sigsuspend_wrapper:
 	ldo	TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r24
 	reg_save %r24
 
 	STREG	%r2, -RP_OFFSET(%r30)
+#ifdef __LP64__
+	ldo	FRAME_SIZE(%r30), %r30
+	bl	sys_rt_sigsuspend,%r2
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	bl	sys_rt_sigsuspend,%r2
 	ldo	FRAME_SIZE(%r30), %r30
+#endif
 
 	ldo	-FRAME_SIZE(%r30), %r30
 	LDREG	-RP_OFFSET(%r30), %r2
@@ -1658,66 +2207,80 @@
 	   values. */
 	/* NOTE: Not all syscalls exit this way.  rt_sigreturn will exit
 	 * via syscall_exit_rfi if the signal was received while the process
-	 * was running.  All traced processes will probably exit via
-	 * syscall_exit_rfi in the future.
+	 * was running.
 	 */
 
 	/* save return value now */
 
 	STREG     %r28,TASK_PT_GR28-TASK_SZ_ALGN-FRAME_SIZE(%r30)
 
+	/* Save other hpux returns if personality is PER_HPUX */
+
+#define PER_HPUX 0xe /* <linux/personality.h> cannot be easily included */
+
+	LDREG     TASK_PERSONALITY-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19
+	CMPIB<>,n PER_HPUX,%r19,1f
+	STREG     %r22,TASK_PT_GR22-TASK_SZ_ALGN-FRAME_SIZE(%r30)
+	STREG     %r29,TASK_PT_GR29-TASK_SZ_ALGN-FRAME_SIZE(%r30)
+1:
+
+	/* Seems to me that dp could be wrong here, if the syscall involved
+	 * calling a module, and nothing got round to restoring dp on return.
+	 */
+	loadgp
+
 syscall_check_bh:
 
-/* #ifdef NOTNOW */
 	/* Check for software interrupts */
 
 	.import irq_stat,data
 
 	ldil    L%irq_stat,%r19
 	ldo     R%irq_stat(%r19),%r19
-	LDIL_FIXUP(%r19)
 
 #ifdef CONFIG_SMP
 	/* sched.h: int processor */
-	ldw     TASK_PROCESSOR-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r20 /* get cpu # */
-#if (IRQSTAT_SZ == 32)
-	dep     %r20,26,27,%r20 /* shift left 5 bits */
-#else
-#error IRQSTAT_SZ changed, fix dep
-#endif /* IRQSTAT_SZ */
-	add     %r19,%r20,%r19
-#endif /* CONFIG_SMP */
+	/* %r26 is used as scratch register to index into irq_stat[] */
+	ldw     TASK_PROCESSOR-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
 
-	ldw     IRQSTAT_SI_ACTIVE(%r19),%r20	/* hardirq.h: unsigned int */
-	ldw     IRQSTAT_SI_MASK(%r19),%r19	/* hardirq.h: unsigned int */
-	and     %r19,%r20,%r20
-	comib,<>,n 0,%r20,syscall_do_softirq /* forward */
-/* #endif */
+	/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
+#ifdef __LP64__
+	shld	%r26, 6, %r20
+#else
+	shlw	%r26, 5, %r20
+#endif
+	add     %r19,%r20,%r19	/* now have &irq_stat[smp_processor_id()] */
+#endif /* CONFIG_SMP */
 
+	LDREG   IRQSTAT_SIRQ_PEND(%r19),%r20    /* hardirq.h: unsigned long */
+	cmpib,<>,n 0,%r20,syscall_do_softirq /* forward */
 
 syscall_check_resched:
 
 	/* check for reschedule */
 
 	LDREG  TASK_NEED_RESCHED-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19	/* long */
-	comib,<>,n 0,%r19,syscall_do_resched /* forward */
+	CMPIB<>,n 0,%r19,syscall_do_resched /* forward */
 
 syscall_check_sig:
 	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get task ptr */
 	/* check for pending signals */
 	ldw     TASK_SIGPENDING(%r1),%r19
-	comib,<>,n 0,%r19,syscall_do_signal  /* forward */
+	cmpib,<>,n 0,%r19,syscall_do_signal  /* forward */
 
 syscall_restore:
-	/* disable interrupts while dicking with the kernel stack, */
-	/* or life can become unpleasant */
-	rsm	PSW_SM_I, %r20
 	LDREG	TASK_PTRACE(%r1), %r19		/* Are we being ptraced? */
 	bb,<,n	%r19,31,syscall_restore_rfi
-	LDREG	TASK_PT_GR20(%r1),%r19
-	mtctl	%r19, %cr27
+
+	ldo	TASK_PT_FR31(%r1),%r19		   /* reload fpregs */
+	rest_fp	%r19
+
+	LDREG	TASK_PT_SAR(%r1),%r19		   /* restore SAR */
+	mtsar	%r19
 
 	LDREG	TASK_PT_GR2(%r1),%r2		   /* restore user rp */
+	LDREG	TASK_PT_GR19(%r1),%r19
+	LDREG   TASK_PT_GR20(%r1),%r20
 	LDREG	TASK_PT_GR21(%r1),%r21
 	LDREG	TASK_PT_GR22(%r1),%r22
 	LDREG	TASK_PT_GR23(%r1),%r23
@@ -1727,43 +2290,31 @@
 	LDREG	TASK_PT_GR27(%r1),%r27	   /* restore user dp */
 	LDREG	TASK_PT_GR28(%r1),%r28	   /* syscall return value */
 	LDREG	TASK_PT_GR29(%r1),%r29
-	LDREG	TASK_PT_GR30(%r1),%r30	   /* restore user sp */
 	LDREG	TASK_PT_GR31(%r1),%r31	   /* restore syscall rp */
-	ldo	TASK_PT_FR31(%r1),%r19		   /* reload fpregs */
-	rest_fp	%r19
-	LDREG	TASK_PT_SAR(%r1),%r19		   /* restore SAR */
-	mtsar	%r19
-	LDREG	TASK_PT_GR19(%r1),%r19
 
-	mtctl	%r1,%cr30			   /* intrhandler okay. */
+	rsm     PSW_SM_I, %r0
+	LDREG   TASK_PT_GR30(%r1),%r30             /* restore user sp */
 	mfsp	%sr3,%r1			   /* Get users space id */
+	mtsp    %r1,%sr7                           /* Restore sr7 */
+	ssm     PSW_SM_I, %r0
 	mtsp	%r1,%sr4			   /* Restore sr4 */
 	mtsp	%r1,%sr5			   /* Restore sr5 */
 	mtsp	%r1,%sr6			   /* Restore sr6 */
 
 	depi	3,31,2,%r31			   /* ensure return to user mode. */
 
-	mtsm	%r20				   /* restore irq state  */
-	mfctl	%cr27,%r20
-	
-	/*
-	 * Due to a dependency in the tlb miss handlers on sr7, it
-	 * is essential that sr7 get set in the delay slot.
-	 */
-
 #ifdef __LP64__
-
-	/* Note the be (and mtsp) is executed in narrow mode. This is OK
-	 * for 32 bit processes, but won't work once we support 64 bit
-	 * processes.
+	/* Since we are returning to a 32 bit user process, we always
+	 * clear the W bit. This means that the be (and mtsp) gets
+	 * executed in narrow mode, but that is OK, since we are
+	 * returning to a 32 bit process. When we support 64 bit processes
+	 * we won't clear the W bit, so the be will run in wide mode.
 	 */
 
-	rsm	PSW_SM_W, %r0
 	be	0(%sr3,%r31)			   /* return to user space */
-	mtsp	%r1,%sr7			   /* Restore sr7 */
+	rsm	PSW_SM_W, %r0
 #else
-	be	0(%sr3,%r31)			   /* return to user space */
-	mtsp	%r1,%sr7			   /* Restore sr7 */
+	be,n    0(%sr3,%r31)                       /* return to user space */
 #endif
 
 	/* We have to return via an RFI, so that PSW T and R bits can be set
@@ -1774,43 +2325,52 @@
 syscall_restore_rfi:
 	ldo	-1(%r0),%r2			   /* Set recovery cntr to -1 */
 	mtctl	%r2,%cr0			   /*   for immediate trap */
-	copy	%r0,%r2				   /* Create a reasonable PSW */
+	LDREG	TASK_PT_PSW(%r1),%r2		   /* Get old PSW */
+	ldi	0x0b,%r20			   /* Create new PSW */
+	depi	-1,13,1,%r20			   /* C, Q, D, and I bits */
+	bb,>=,n	%r19,15,try_tbit		   /* PT_SINGLESTEP */
+	depi	-1,27,1,%r20			   /* R bit */
+try_tbit:
+	bb,>=,n	%r19,14,psw_setup		   /* PT_BLOCKSTEP, see ptrace.c */
+	depi	-1,7,1,%r20			   /* T bit */
+psw_setup:
+	STREG	%r20,TASK_PT_PSW(%r1)
+
+	/* Always store space registers, since sr3 can be changed (e.g. fork) */
+
+	mfsp    %sr3,%r25
+	STREG   %r25,TASK_PT_SR3(%r1)
+	STREG   %r25,TASK_PT_SR4(%r1)
+	STREG   %r25,TASK_PT_SR5(%r1)
+	STREG   %r25,TASK_PT_SR6(%r1)
+	STREG   %r25,TASK_PT_SR7(%r1)
+	STREG   %r25,TASK_PT_IASQ0(%r1)
+	STREG   %r25,TASK_PT_IASQ1(%r1)
+
 	/* XXX W bit??? */
-	depi	-1,13,1,%r2
-	depi	-1,28,1,%r2
-	depi	-1,30,1,%r2
-	depi	-1,31,1,%r2
-	bb,<,n	%r19,15,set_rbit		   /* PT_SINGLESTEP */
-	bb,>=,n	%r19,14,set_nobit		   /* PT_BLOCKSTEP, see ptrace.c */
-set_tbit:
-	depi	-1,7,1,%r2
-	b,n	set_nobit
-set_rbit:
-	depi	-1,27,1,%r2
-set_nobit:
-	STREG	%r2,TASK_PT_PSW(%r1)
-	STREG	%r1,TASK_PT_CR30(%r1)
+	/* Now if old D bit is clear, it means we didn't save all registers
+	 * on syscall entry, so do that now.  This only happens on TRACEME
+	 * calls, or if someone attached to us while we were on a syscall.
+	 * We could make this more efficient by not saving r3-r18, but
+	 * then we wouldn't be able to use the common intr_restore path.
+	 * It is only for traced processes anyway, so performance is not
+	 * an issue.
+	 */
+	bb,<	%r2,30,pt_regs_ok		   /* Branch if D set */
+	ldo	TASK_REGS(%r1),%r25
+	reg_save %r25				   /* Save r3 to r18 */
 	mfsp	%sr0,%r2
 	STREG	%r2,TASK_PT_SR0(%r1)
 	mfsp	%sr1,%r2
 	STREG	%r2,TASK_PT_SR1(%r1)
 	mfsp	%sr2,%r2
 	STREG	%r2,TASK_PT_SR2(%r1)
-	mfsp	%sr3,%r2
-	STREG	%r2,TASK_PT_SR3(%r1)
-	STREG	%r2,TASK_PT_SR4(%r1)
-	STREG	%r2,TASK_PT_SR5(%r1)
-	STREG	%r2,TASK_PT_SR6(%r1)
-	STREG	%r2,TASK_PT_SR7(%r1)
-	STREG	%r2,TASK_PT_IASQ0(%r1)
-	STREG	%r2,TASK_PT_IASQ1(%r1)
+pt_regs_ok:
 	LDREG	TASK_PT_GR31(%r1),%r2
 	depi	3,31,2,%r2			   /* ensure return to user mode. */
 	STREG	%r2,TASK_PT_IAOQ0(%r1)
 	ldo	4(%r2),%r2
 	STREG	%r2,TASK_PT_IAOQ1(%r1)
-	ldo	TASK_REGS(%r1),%r25
-	reg_save %r25				   /* Save r3 to r18 */
 	copy	%r25,%r16
 	b	intr_restore
 	nop
@@ -1825,7 +2385,11 @@
 	.import schedule,code
 syscall_do_resched:
 	bl	schedule,%r2
+#ifdef __LP64__
+	ldo	-16(%r30),%r29		/* Reference param save area */
+#else
 	nop
+#endif
 	b       syscall_check_bh  /* if resched, we start over again */
 	nop
 
@@ -1840,6 +2404,9 @@
 
 	ldi	1, %r24				/* unsigned long in_syscall */
 
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#endif
 	bl	do_signal,%r2
 	copy	%r0, %r26			/* sigset_t *oldset = NULL */
 
@@ -1849,19 +2416,155 @@
 
 	b,n     syscall_restore
 
-#ifdef __LP64__
-unimplemented_64bitirq:
-	ssm PSW_SM_Q+PSW_SM_I, %r0
-	/* indicate that we had an interrupt */
-	ldi	0x77, %r28
-	ldi	0x77, %r29
-	/* save interrupt registers in GRs for diagnosis */
-	mfctl %cr17, %r17
-	mfctl %cr18, %r18
-	mfctl %cr19, %r19
-	mfctl %cr20, %r20
-	mfctl %cr21, %r21
-	mfctl %cr22, %r22
-	b,n .
-	nop
-#endif
+	/*
+	 * get_register is used by the non access tlb miss handlers to
+	 * copy the value of the general register specified in r8 into
+	 * r1. This routine can't be used for shadowed registers, since
+	 * the rfir will restore the original value. So, for the shadowed
+	 * registers we put a -1 into r1 to indicate that the register
+	 * should not be used (the register being copied could also have
+	 * a -1 in it, but that is OK, it just means that we will have
+	 * to use the slow path instead).
+	 */
+
+get_register:
+	blr     %r8,%r0
+	nop
+	bv      %r0(%r25)    /* r0 */
+	copy    %r0,%r1
+	bv      %r0(%r25)    /* r1 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r2 */
+	copy    %r2,%r1
+	bv      %r0(%r25)    /* r3 */
+	copy    %r3,%r1
+	bv      %r0(%r25)    /* r4 */
+	copy    %r4,%r1
+	bv      %r0(%r25)    /* r5 */
+	copy    %r5,%r1
+	bv      %r0(%r25)    /* r6 */
+	copy    %r6,%r1
+	bv      %r0(%r25)    /* r7 */
+	copy    %r7,%r1
+	bv      %r0(%r25)    /* r8 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r9 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r10 */
+	copy    %r10,%r1
+	bv      %r0(%r25)    /* r11 */
+	copy    %r11,%r1
+	bv      %r0(%r25)    /* r12 */
+	copy    %r12,%r1
+	bv      %r0(%r25)    /* r13 */
+	copy    %r13,%r1
+	bv      %r0(%r25)    /* r14 */
+	copy    %r14,%r1
+	bv      %r0(%r25)    /* r15 */
+	copy    %r15,%r1
+	bv      %r0(%r25)    /* r16 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r17 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r18 */
+	copy    %r18,%r1
+	bv      %r0(%r25)    /* r19 */
+	copy    %r19,%r1
+	bv      %r0(%r25)    /* r20 */
+	copy    %r20,%r1
+	bv      %r0(%r25)    /* r21 */
+	copy    %r21,%r1
+	bv      %r0(%r25)    /* r22 */
+	copy    %r22,%r1
+	bv      %r0(%r25)    /* r23 */
+	copy    %r23,%r1
+	bv      %r0(%r25)    /* r24 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r25 - shadowed */
+	ldi     -1,%r1
+	bv      %r0(%r25)    /* r26 */
+	copy    %r26,%r1
+	bv      %r0(%r25)    /* r27 */
+	copy    %r27,%r1
+	bv      %r0(%r25)    /* r28 */
+	copy    %r28,%r1
+	bv      %r0(%r25)    /* r29 */
+	copy    %r29,%r1
+	bv      %r0(%r25)    /* r30 */
+	copy    %r30,%r1
+	bv      %r0(%r25)    /* r31 */
+	copy    %r31,%r1
+
+	/*
+	 * set_register is used by the non access tlb miss handlers to
+	 * copy the value of r1 into the general register specified in
+	 * r8.
+	 */
+
+set_register:
+	blr     %r8,%r0
+	nop
+	bv      %r0(%r25)    /* r0 (silly, but it is a place holder) */
+	copy    %r1,%r0
+	bv      %r0(%r25)    /* r1 */
+	copy    %r1,%r1
+	bv      %r0(%r25)    /* r2 */
+	copy    %r1,%r2
+	bv      %r0(%r25)    /* r3 */
+	copy    %r1,%r3
+	bv      %r0(%r25)    /* r4 */
+	copy    %r1,%r4
+	bv      %r0(%r25)    /* r5 */
+	copy    %r1,%r5
+	bv      %r0(%r25)    /* r6 */
+	copy    %r1,%r6
+	bv      %r0(%r25)    /* r7 */
+	copy    %r1,%r7
+	bv      %r0(%r25)    /* r8 */
+	copy    %r1,%r8
+	bv      %r0(%r25)    /* r9 */
+	copy    %r1,%r9
+	bv      %r0(%r25)    /* r10 */
+	copy    %r1,%r10
+	bv      %r0(%r25)    /* r11 */
+	copy    %r1,%r11
+	bv      %r0(%r25)    /* r12 */
+	copy    %r1,%r12
+	bv      %r0(%r25)    /* r13 */
+	copy    %r1,%r13
+	bv      %r0(%r25)    /* r14 */
+	copy    %r1,%r14
+	bv      %r0(%r25)    /* r15 */
+	copy    %r1,%r15
+	bv      %r0(%r25)    /* r16 */
+	copy    %r1,%r16
+	bv      %r0(%r25)    /* r17 */
+	copy    %r1,%r17
+	bv      %r0(%r25)    /* r18 */
+	copy    %r1,%r18
+	bv      %r0(%r25)    /* r19 */
+	copy    %r1,%r19
+	bv      %r0(%r25)    /* r20 */
+	copy    %r1,%r20
+	bv      %r0(%r25)    /* r21 */
+	copy    %r1,%r21
+	bv      %r0(%r25)    /* r22 */
+	copy    %r1,%r22
+	bv      %r0(%r25)    /* r23 */
+	copy    %r1,%r23
+	bv      %r0(%r25)    /* r24 */
+	copy    %r1,%r24
+	bv      %r0(%r25)    /* r25 */
+	copy    %r1,%r25
+	bv      %r0(%r25)    /* r26 */
+	copy    %r1,%r26
+	bv      %r0(%r25)    /* r27 */
+	copy    %r1,%r27
+	bv      %r0(%r25)    /* r28 */
+	copy    %r1,%r28
+	bv      %r0(%r25)    /* r29 */
+	copy    %r1,%r29
+	bv      %r0(%r25)    /* r30 */
+	copy    %r1,%r30
+	bv      %r0(%r25)    /* r31 */
+	copy    %r1,%r31
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/firmware.c linux-2.4.20-pre2/arch/parisc/kernel/firmware.c
--- linux-2.4.20-pre1/arch/parisc/kernel/firmware.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/firmware.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,1111 @@
+/* arch/parisc/kernel/pdc.c  - safe pdc access routines
+ *
+ * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
+ * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
+ *
+ * only these routines should be used out of the real kernel (i.e. everything
+ * using virtual addresses) for obvious reasons */
+
+/*	I think it would be in everyone's best interest to follow this
+ *	guidelines when writing PDC wrappers:
+ *
+ *	 - the name of the pdc wrapper should match one of the macros
+ *	   used for the first two arguments
+ *	 - don't use caps for random parts of the name
+ *	 - use the static PDC result buffers and "copyout" to structs
+ *	   supplied by the caller to encapsulate alignment restrictions
+ *	 - hold pdc_lock while in PDC or using static result buffers
+ *	 - use __pa() to convert virtual (kernel) pointers to physical
+ *	   ones.
+ *	 - the name of the struct used for pdc return values should equal
+ *	   one of the macros used for the first two arguments to the
+ *	   corresponding PDC call
+ *	 - keep the order of arguments
+ *	 - don't be smart (setting trailing NUL bytes for strings, return
+ *	   something useful even if the call failed) unless you are sure
+ *	   it's not going to affect functionality or performance
+ *
+ *	Example:
+ *	int pdc_cache_info(struct pdc_cache_info *cache_info )
+ *	{
+ *		int retval;
+ *
+ *		spin_lock_irq(&pdc_lock);
+ *		retval = mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
+ *		convert_to_wide(pdc_result);
+ *		memcpy(cache_info, pdc_result, sizeof(*cache_info));
+ *		spin_unlock_irq(&pdc_lock);
+ *
+ *		return retval;
+ *	}
+ *					prumpf	991016	
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/system.h>
+#include <asm/processor.h>	/* for boot_cpu_data */
+
+#include <stdarg.h>
+
+static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long pdc_result[32] __attribute__ ((aligned (8)));
+static unsigned long pdc_result2[32] __attribute__ ((aligned (8)));
+
+/* on all currently-supported platforms, IODC I/O calls are always
+ * 32-bit calls, and MEM_PDC calls are always the same width as the OS.
+ * This means Cxxx boxes can't run wide kernels right now. -PB
+ *
+ * CONFIG_PDC_NARROW has been added to allow 64-bit kernels to run on
+ * systems with 32-bit MEM_PDC calls. This will allow wide kernels to
+ * run on Cxxx boxes now. -RB
+ *
+ * Note that some PAT boxes may have 64-bit IODC I/O...
+ */
+
+#ifdef __LP64__
+static long real64_call(unsigned long function, ...);
+#endif
+static long real32_call(unsigned long function, ...);
+
+#if defined(__LP64__) && ! defined(CONFIG_PDC_NARROW)
+#define MEM_PDC (unsigned long)(PAGE0->mem_pdc_hi) << 32 | PAGE0->mem_pdc
+#   define mem_pdc_call(args...) real64_call(MEM_PDC, args)
+#else
+#define MEM_PDC (unsigned long)PAGE0->mem_pdc
+#   define mem_pdc_call(args...) real32_call(MEM_PDC, args)
+#endif
+
+
+/**
+ * f_extend - Convert PDC addresses to kernel addresses.
+ * @address: Address returned from PDC.
+ *
+ * This function is used to convert PDC addresses into kernel addresses
+ * when the PDC address size and kernel address size are different.
+ */
+static unsigned long f_extend(unsigned long address)
+{
+#ifdef CONFIG_PDC_NARROW
+	if((address & 0xff000000) == 0xf0000000)
+		return 0xf0f0f0f000000000 | (u32)address;
+
+	if((address & 0xf0000000) == 0xf0000000)
+		return 0xffffffff00000000 | (u32)address;
+#endif
+	return address;
+}
+
+/**
+ * convert_to_wide - Convert the return buffer addresses into kernel addresses.
+ * @address: The return buffer from PDC.
+ *
+ * This function is used to convert the return buffer addresses retrieved from PDC
+ * into kernel addresses when the PDC address size and kernel address size are
+ * different.
+ */
+static void convert_to_wide(unsigned long *addr)
+{
+#ifdef CONFIG_PDC_NARROW
+	int i;
+	unsigned *p = (unsigned int *)addr;
+	for(i = 31; i >= 0; --i)
+		addr[i] = p[i];
+#endif
+}
+
+/**
+ * pdc_emergency_unlock - Unlock the linux pdc lock
+ *
+ * This call unlocks the linux pdc lock in case we need some PDC functions
+ * (like pdc_add_valid) during kernel stack dump.
+ */
+void pdc_emergency_unlock(void)
+{
+        spin_unlock(&pdc_lock);
+}
+
+
+/**
+ * pdc_add_valid - Verify address can be accessed without causing a HPMC.
+ * @address: Address to be verified.
+ *
+ * This PDC call attempts to read from the specified address and verifies
+ * if the address is valid.
+ * 
+ * The return value is PDC_OK (0) in case accessing this address is valid.
+ */
+int pdc_add_valid(unsigned long address)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, address);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_chassis_info - Return chassis information.
+ * @result: The return buffer.
+ * @chassis_info: The memory buffer address.
+ * @len: The size of the memory buffer address.
+ *
+ * An HVERSION dependent call for returning the chassis information.
+ */
+int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        memcpy(&pdc_result, chassis_info, sizeof(*chassis_info));
+        memcpy(&pdc_result2, led_info, len);
+        retval = mem_pdc_call(PDC_CHASSIS, PDC_RETURN_CHASSIS_INFO,
+                              __pa(pdc_result), __pa(pdc_result2), len);
+        memcpy(chassis_info, pdc_result, sizeof(*chassis_info));
+        memcpy(led_info, pdc_result2, len);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_coproc_cfg - To identify coprocessors attached to the processor.
+ * @pdc_coproc_info: Return buffer address.
+ *
+ * This PDC call returns the presence and status of all the coprocessors
+ * attached to the processor.
+ */
+int __init pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(pdc_result));
+        convert_to_wide(pdc_result);
+        pdc_coproc_info->ccr_functional = pdc_result[0];
+        pdc_coproc_info->ccr_present = pdc_result[1];
+        pdc_coproc_info->revision = pdc_result[17];
+        pdc_coproc_info->model = pdc_result[18];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_iodc_read - Read data from the modules IODC.
+ * @actcnt: The actual number of bytes.
+ * @hpa: The HPA of the module for the iodc read.
+ * @index: The iodc entry point.
+ * @iodc_data: A buffer memory for the iodc options.
+ * @iodc_data_size: Size of the memory buffer.
+ *
+ * This PDC call reads from the IODC of the module specified by the hpa
+ * argument.
+ */
+int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
+		  void *iodc_data, unsigned int iodc_data_size)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_IODC, PDC_IODC_READ, __pa(pdc_result), hpa, 
+			      index, __pa(pdc_result2), iodc_data_size);
+	convert_to_wide(pdc_result);
+	*actcnt = pdc_result[0];
+	memcpy(iodc_data, pdc_result2, iodc_data_size);
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_system_map_find_mods - Locate unarchitected modules.
+ * @pdc_mod_info: Return buffer address.
+ * @mod_path: pointer to dev path structure.
+ * @mod_index: fixed address module index.
+ *
+ * To locate and identify modules which reside at fixed I/O addresses, which
+ * do not self-identify via architected bus walks.
+ */
+int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
+			     struct pdc_module_path *mod_path, long mod_index)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result), 
+			      __pa(pdc_result2), mod_index);
+	convert_to_wide(pdc_result);
+	memcpy(pdc_mod_info, pdc_result, sizeof(*pdc_mod_info));
+	memcpy(mod_path, pdc_result2, sizeof(*mod_path));
+	spin_unlock_irq(&pdc_lock);
+
+	pdc_mod_info->mod_addr = f_extend(pdc_mod_info->mod_addr);
+	return retval;
+}
+
+/**
+ * pdc_system_map_find_addrs - Retrieve additional address ranges.
+ * @pdc_addr_info: Return buffer address.
+ * @mod_index: Fixed address module index.
+ * @addr_index: Address range index.
+ * 
+ * Retrieve additional information about subsequent address ranges for modules
+ * with multiple address ranges.  
+ */
+int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info, 
+			      long mod_index, long addr_index)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_ADDRESS, __pa(pdc_result),
+			      mod_index, addr_index);
+	convert_to_wide(pdc_result);
+	memcpy(pdc_addr_info, pdc_result, sizeof(*pdc_addr_info));
+	spin_unlock_irq(&pdc_lock);
+
+	pdc_addr_info->mod_addr = f_extend(pdc_addr_info->mod_addr);
+	return retval;
+}
+
+/**
+ * pdc_model_info - Return model information about the processor.
+ * @model: The return buffer.
+ *
+ * Returns the version numbers, identifiers, and capabilities from the processor module.
+ */
+int pdc_model_info(struct pdc_model *model) 
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_INFO, __pa(pdc_result), 0);
+	convert_to_wide(pdc_result);
+	memcpy(model, pdc_result, sizeof(*model));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_model_sysmodel - Get the system model name.
+ * @name: A char array of at least 81 characters.
+ *
+ * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L)
+ */
+int pdc_model_sysmodel(char *name)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_SYSMODEL, __pa(pdc_result),
+                              OS_ID_HPUX, __pa(name));
+        convert_to_wide(pdc_result);
+
+        if (retval == PDC_OK) {
+                name[pdc_result[0]] = '\0'; /* add trailing '\0' */
+        } else {
+                name[0] = 0;
+        }
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_model_versions - Identify the version number of each processor.
+ * @cpu_id: The return buffer.
+ * @id: The id of the processor to check.
+ *
+ * Returns the version number for each processor component.
+ *
+ * This comment was here before, but I do not know what it means :( -RB
+ * id: 0 = cpu revision, 1 = boot-rom-version
+ */
+int pdc_model_versions(unsigned long *versions, int id)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_VERSIONS, __pa(pdc_result), id);
+        convert_to_wide(pdc_result);
+        *versions = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_model_cpuid - Returns the CPU_ID.
+ * @cpu_id: The return buffer.
+ *
+ * Returns the CPU_ID value which uniquely identifies the cpu portion of
+ * the processor module.
+ */
+int pdc_model_cpuid(unsigned long *cpu_id)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CPU_ID, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        *cpu_id = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_model_capabilities - Returns the platform capabilities.
+ * @capabilities: The return buffer.
+ *
+ * Returns information about platform support for 32- and/or 64-bit
+ * OSes, IO-PDIR coherency, and virtual aliasing.
+ */
+int pdc_model_capabilities(unsigned long *capabilities)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        *capabilities = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_cache_info - Return cache and TLB information.
+ * @cache_info: The return buffer.
+ *
+ * Returns information about the processor's cache and TLB.
+ */
+int pdc_cache_info(struct pdc_cache_info *cache_info)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_INFO, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        memcpy(cache_info, pdc_result, sizeof(*cache_info));
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+#ifndef CONFIG_PA20
+/**
+ * pdc_btlb_info - Return block TLB information.
+ * @btlb: The return buffer.
+ *
+ * Returns information about the hardware Block TLB.
+ */
+int pdc_btlb_info(struct pdc_btlb_info *btlb) 
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_BLOCK_TLB, PDC_BTLB_INFO, __pa(pdc_result), 0);
+        memcpy(btlb, pdc_result, sizeof(*btlb));
+        spin_unlock_irq(&pdc_lock);
+
+        if(retval < 0) {
+                btlb->max_size = 0;
+        }
+        return retval;
+}
+
+/**
+ * pdc_mem_map_hpa - Find fixed module information.  
+ * @address: The return buffer
+ * @mod_path: pointer to dev path structure.
+ *
+ * This call was developed for S700 workstations to allow the kernel to find
+ * the I/O devices (Core I/O). In the future (Kittyhawk and beyond) this
+ * call will be replaced (on workstations) by the architected PDC_SYSTEM_MAP
+ * call.
+ *
+ * This call is supported by all existing S700 workstations (up to  Gecko).
+ */
+int pdc_mem_map_hpa(struct pdc_memory_map *address,
+		struct pdc_module_path *mod_path)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        memcpy(pdc_result2, mod_path, sizeof(*mod_path));
+        retval = mem_pdc_call(PDC_MEM_MAP, PDC_MEM_MAP_HPA, __pa(pdc_result),
+				__pa(pdc_result2));
+        memcpy(address, pdc_result, sizeof(*address));
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+#endif	/* !CONFIG_PA20 */
+
+/**
+ * pdc_lan_station_id - Get the LAN address.
+ * @lan_addr: The return buffer.
+ * @hpa: The network device HPA.
+ *
+ * Get the LAN station address when it is not directly available from the LAN hardware.
+ */
+int pdc_lan_station_id(char *lan_addr, unsigned long hpa)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ,
+			__pa(pdc_result), hpa);
+	if (retval < 0) {
+		/* FIXME: else read MAC from NVRAM */
+		memset(lan_addr, 0, PDC_LAN_STATION_ID_SIZE);
+	} else {
+		memcpy(lan_addr, pdc_result, PDC_LAN_STATION_ID_SIZE);
+	}
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+
+/**
+ * pdc_get_initiator - Get the SCSI Interface Card params (SCSI ID, SDTR, SE or LVD)
+ * @hwpath: fully bc.mod style path to the device.
+ * @scsi_id: what someone told firmware the ID should be.
+ * @period: time in cycles 
+ * @width: 8 or 16-bit wide bus
+ * @mode: 0,1,2 -> SE,HVD,LVD signalling mode
+ *
+ * Get the SCSI operational parameters from PDC.
+ * Needed since HPUX never used BIOS or symbios card NVRAM.
+ * Most ncr/sym cards won't have an entry and just use whatever
+ * capabilities of the card are (eg Ultra, LVD). But there are
+ * several cases where it's useful:
+ *    o set SCSI id for Multi-initiator clusters,
+ *    o cable too long (ie SE scsi 10Mhz won't support 6m length),
+ *    o bus width exported is less than what the interface chip supports.
+ */
+int pdc_get_initiator( struct hardware_path *hwpath, unsigned char *scsi_id,
+	unsigned long *period, char *width, char *mode)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+
+/* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */
+#define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \
+	strncmp(boot_cpu_data.pdc.sys_model_name, "9000/785", 9) == 0)
+
+	retval = mem_pdc_call(PDC_INITIATOR, PDC_GET_INITIATOR, 
+			      __pa(pdc_result), __pa(hwpath));
+
+
+	if (retval >= PDC_OK) {
+		*scsi_id = (unsigned char) pdc_result[0];
+
+		/* convert Bus speed in Mhz to period (in 1/10 ns) */
+		switch(pdc_result[1]) {
+		/*
+		** case  0:   driver determines rate
+		** case -1:   Settings are uninitialized.
+		*/
+		case  5:  *period = 2000; break;
+		case 10:  *period = 1000; break;
+		case 20:  *period = 500; break;
+		case 40:  *period = 250; break;
+		default: /* Do nothing */ break;
+		}
+
+		/* 
+		** pdc_result[2]	PDC suggested SCSI id
+		** pdc_result[3]	PDC suggested SCSI rate
+		*/
+
+		if (IS_SPROCKETS()) {
+			/*
+			** Revisit: PAT PDC do the same thing?
+			** A500 also exports 50-pin SE SCSI.
+			**	0 == 8-bit
+			**	1 == 16-bit
+			*/
+			*width = (char) pdc_result[4];
+
+			/* ...in case someone needs it in the future.
+			** sym53c8xx.c comments say it can't autodetect
+			** for 825/825A/875 chips.
+			**	0 == SE, 1 == HVD, 2 == LVD
+			*/
+			*mode = (char) pdc_result[5]; 
+		}
+	}
+
+	spin_unlock_irq(&pdc_lock);
+	return retval >= PDC_OK;
+}
+
+
+/**
+ * pdc_pci_irt_size - Get the number of entries in the interrupt routing table.
+ * @num_entries: The return value.
+ * @hpa: The HPA for the device.
+ *
+ * This PDC function returns the number of entries in the specified cell's
+ * interrupt table.
+ * Similar to PDC_PAT stuff - but added for Forte/Allegro boxes
+ */ 
+int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE, 
+			      __pa(pdc_result), hpa);
+	convert_to_wide(pdc_result);
+	*num_entries = pdc_result[0];
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/** 
+ * pdc_pci_irt - Get the PCI interrupt routing table.
+ * @num_entries: The number of entries in the table.
+ * @hpa: The Hard Physical Address of the device.
+ * @tbl: 
+ *
+ * Get the PCI interrupt routing table for the device at the given HPA.
+ * Similar to PDC_PAT stuff - but added for Forte/Allegro boxes
+ */
+int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	pdc_result[0] = num_entries;
+	retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, 
+			      __pa(pdc_result), hpa, __pa(tbl));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+
+/**
+ * pdc_tod_read - Read the Time-Of-Day clock.
+ * @tod: The return buffer:
+ *
+ * Read the Time-Of-Day clock
+ */
+int pdc_tod_read(struct pdc_tod *tod)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        memcpy(tod, pdc_result, sizeof(*tod));
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_tod_set - Set the Time-Of-Day clock.
+ * @sec: The number of seconds since epoch.
+ * @usec: The number of micro seconds.
+ *
+ * Set the Time-Of-Day clock.
+ */ 
+int pdc_tod_set(unsigned long sec, unsigned long usec)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+#ifdef __LP64__
+int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
+		struct pdc_memory_table *tbl, unsigned long entries)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_MEM, PDC_MEM_TABLE, __pa(pdc_result), __pa(pdc_result2), entries);
+	convert_to_wide(pdc_result);
+	memcpy(r_addr, pdc_result, sizeof(*r_addr));
+	memcpy(tbl, pdc_result2, entries * sizeof(*tbl));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+#endif /* __LP64__ */
+
+/* FIXME: Is this pdc used?  I could not find type reference to ftc_bitmap
+ * so I guessed at unsigned long.  Someone who knows what this does, can fix
+ * it later. :)
+ */
+int pdc_do_firm_test_reset(unsigned long ftc_bitmap)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_FIRM_TEST_RESET,
+                              PDC_FIRM_TEST_MAGIC, ftc_bitmap);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/*
+ * pdc_do_reset - Reset the system.
+ *
+ * Reset the system.
+ */
+int pdc_do_reset()
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/*
+ * pdc_soft_power_info - Enable soft power switch.
+ * @power_reg: address of soft power register
+ *
+ * Return the absolute address of the soft power switch register
+ */
+int __init pdc_soft_power_info(unsigned long *power_reg)
+{
+	int retval;
+
+	*power_reg = (unsigned long) (-1);
+	
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_INFO, __pa(pdc_result), 0);
+	if (retval == PDC_OK) {
+                convert_to_wide(pdc_result);
+                *power_reg = f_extend(pdc_result[0]);
+	}
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/*
+ * pdc_soft_power_button - Control the soft power button behaviour
+ * @sw_control: 0 for hardware control, 1 for software control 
+ *
+ *
+ * This PDC function places the soft power button under software or
+ * hardware control.
+ * Under software control the OS may control to when to allow to shut 
+ * down the system. Under hardware control pressing the power button 
+ * powers off the system immediately.
+ */
+int pdc_soft_power_button(int sw_control)
+{
+	int retval;
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control);
+	spin_unlock_irq(&pdc_lock);
+	return retval;
+}
+
+/*
+ * pdc_suspend_usb - Stop USB controller
+ *
+ * If PDC used the usb controller, the usb controller
+ * is still running and will crash the machines during iommu 
+ * setup, because of still running DMA. This PDC call
+ * stops the USB controller
+ */
+void pdc_suspend_usb(void)
+{
+	spin_lock_irq(&pdc_lock);  
+	mem_pdc_call(PDC_IO, PDC_IO_SUSPEND_USB, 0);
+	spin_unlock_irq(&pdc_lock);
+}
+
+/**
+ * pdc_iodc_putc - Console character print using IODC.
+ * @c: the character to output.
+ *
+ * Note that only these special chars are architected for console IODC io:
+ * BEL, BS, CR, and LF. Others are passed through.
+ * Since the HP console requires CR+LF to perform a 'newline', we translate
+ * "\n" to "\r\n".
+ */
+void pdc_iodc_putc(unsigned char c)
+{
+        /* XXX Should we spinlock posx usage */
+        static int posx;        /* for simple TAB-Simulation... */
+        static int __attribute__((aligned(8)))   iodc_retbuf[32];
+        static char __attribute__((aligned(64))) iodc_dbuf[4096];
+        unsigned int n;
+	unsigned int flags;
+
+        switch (c) {
+        case '\n':
+                iodc_dbuf[0] = '\r';
+                iodc_dbuf[1] = '\n';
+                n = 2;
+                posx = 0;
+                break;
+        case '\t':
+                pdc_iodc_putc(' ');
+                while (posx & 7)        /* expand TAB */
+                        pdc_iodc_putc(' ');
+                return;         /* return since IODC can't handle this */
+        case '\b':
+                posx-=2;                /* BS */
+        default:
+                iodc_dbuf[0] = c;
+                n = 1;
+                posx++;
+                break;
+        }
+
+        spin_lock_irqsave(&pdc_lock, flags);
+        real32_call(PAGE0->mem_cons.iodc_io,
+                    (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
+                    PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
+                    __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
+        spin_unlock_irqrestore(&pdc_lock, flags);
+}
+
+/**
+ * pdc_iodc_outc - Console character print using IODC (without conversions).
+ * @c: the character to output.
+ *
+ * Write the character directly to the IODC console.
+ */
+void pdc_iodc_outc(unsigned char c)
+{
+	unsigned int n, flags;
+
+	/* fill buffer with one caracter and print it */
+        static int __attribute__((aligned(8)))   iodc_retbuf[32];
+        static char __attribute__((aligned(64))) iodc_dbuf[4096];
+
+	n = 1;
+	iodc_dbuf[0] = c;
+
+	spin_lock_irqsave(&pdc_lock, flags);
+	real32_call(PAGE0->mem_cons.iodc_io,
+		    (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
+		    PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
+		    __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
+	spin_unlock_irqrestore(&pdc_lock, flags);
+}
+
+/**
+ * pdc_iodc_getc - Read a character (non-blocking) from the PDC console.
+ *
+ * Read a character (non-blocking) from the PDC console, returns -1 if
+ * key is not present.
+ */
+int pdc_iodc_getc(void)
+{
+	unsigned int flags;
+        static int __attribute__((aligned(8)))   iodc_retbuf[32];
+        static char __attribute__((aligned(64))) iodc_dbuf[4096];
+	int ch;
+	int status;
+
+	/* Bail if no console input device. */
+	if (!PAGE0->mem_kbd.iodc_io)
+		return 0;
+	
+	/* wait for a keyboard (rs232)-input */
+	spin_lock_irqsave(&pdc_lock, flags);
+	real32_call(PAGE0->mem_kbd.iodc_io,
+		    (unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN,
+		    PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers), 
+		    __pa(iodc_retbuf), 0, __pa(iodc_dbuf), 1, 0);
+
+	ch = *iodc_dbuf;
+	status = *iodc_retbuf;
+	spin_unlock_irqrestore(&pdc_lock, flags);
+
+	if (status == 0)
+	    return -1;
+	
+	return ch;
+}
+
+int pdc_sti_call(unsigned long func, unsigned long flags,
+                 unsigned long inptr, unsigned long outputr,
+                 unsigned long glob_cfg)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);  
+        retval = real32_call(func, flags, inptr, outputr, glob_cfg);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+#ifdef __LP64__
+/**
+ * pdc_pat_cell_get_number - Returns the cell number.
+ * @cell_info: The return buffer.
+ *
+ * This PDC call returns the cell number of the cell from which the call
+ * is made.
+ */
+int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_GET_NUMBER, __pa(pdc_result));
+	memcpy(cell_info, pdc_result, sizeof(*cell_info));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_cell_module - Retrieve the cell's module information.
+ * @actcnt: The number of bytes written to mem_addr.
+ * @ploc: The physical location.
+ * @mod: The module index.
+ * @view_type: The view of the address type.
+ * @mem_addr: The return buffer.
+ *
+ * This PDC call returns information about each module attached to the cell
+ * at the specified location.
+ */
+int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod,
+			unsigned long view_type, void *mem_addr)
+{
+	int retval;
+	static struct pdc_pat_cell_mod_maddr_block result __attribute__ ((aligned (8)));
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_MODULE, __pa(pdc_result), 
+			      ploc, mod, view_type, __pa(&result));
+	if(!retval) {
+		*actcnt = pdc_result[0];
+		memcpy(mem_addr, &result, *actcnt);
+	}
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_cpu_get_number - Retrieve the cpu number.
+ * @cpu_info: The return buffer.
+ * @hpa: The Hard Physical Address of the CPU.
+ *
+ * Retrieve the cpu number for the cpu at the specified HPA.
+ */
+int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
+			      __pa(&pdc_result), hpa);
+	memcpy(cpu_info, pdc_result, sizeof(*cpu_info));
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_get_irt_size - Retrieve the number of entries in the cell's interrupt table.
+ * @num_entries: The return value.
+ * @cell_num: The target cell.
+ *
+ * This PDC function returns the number of entries in the specified cell's
+ * interrupt table.
+ */
+int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE,
+			      __pa(pdc_result), cell_num);
+	*num_entries = pdc_result[0];
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_get_irt - Retrieve the cell's interrupt table.
+ * @r_addr: The return buffer.
+ * @cell_num: The target cell.
+ *
+ * This PDC function returns the actual interrupt table for the specified cell.
+ */
+int pdc_pat_get_irt(void *r_addr, unsigned long cell_num)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE,
+			      __pa(r_addr), cell_num);
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
+ * pdc_pat_pd_get_addr_map - Retrieve information about memory address ranges.
+ * @actlen: The return buffer.
+ * @mem_addr: Pointer to the memory buffer.
+ * @count: The number of bytes to read from the buffer.
+ * @offset: The offset with respect to the beginning of the buffer.
+ *
+ */
+int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, 
+			    unsigned long count, unsigned long offset)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_PD, PDC_PAT_PD_GET_ADDR_MAP, __pa(pdc_result), 
+			      __pa(pdc_result2), count, offset);
+	*actual_len = pdc_result[0];
+	memcpy(mem_addr, pdc_result2, *actual_len);
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+#endif /* __LP64__ */
+
+
+/***************** 32-bit real-mode calls ***********/
+/* The struct below is used
+ * to overlay real_stack (real2.S), preparing a 32-bit call frame.
+ * real32_call_asm() then uses this stack in narrow real mode
+ */
+
+struct narrow_stack {
+	/* use int, not long which is 64 bits */
+	unsigned int arg13;
+	unsigned int arg12;
+	unsigned int arg11;
+	unsigned int arg10;
+	unsigned int arg9;
+	unsigned int arg8;
+	unsigned int arg7;
+	unsigned int arg6;
+	unsigned int arg5;
+	unsigned int arg4;
+	unsigned int arg3;
+	unsigned int arg2;
+	unsigned int arg1;
+	unsigned int arg0;
+	unsigned int frame_marker[8];
+	unsigned int sp;
+	/* in reality, there's nearly 8k of stack after this */
+};
+
+static long real32_call(unsigned long fn, ...)
+{
+	va_list args;
+	extern struct narrow_stack real_stack;
+	extern unsigned long real32_call_asm(unsigned int *,
+					     unsigned int *, 
+					     unsigned int);
+	
+	va_start(args, fn);
+	real_stack.arg0 = va_arg(args, unsigned int);
+	real_stack.arg1 = va_arg(args, unsigned int);
+	real_stack.arg2 = va_arg(args, unsigned int);
+	real_stack.arg3 = va_arg(args, unsigned int);
+	real_stack.arg4 = va_arg(args, unsigned int);
+	real_stack.arg5 = va_arg(args, unsigned int);
+	real_stack.arg6 = va_arg(args, unsigned int);
+	real_stack.arg7 = va_arg(args, unsigned int);
+	real_stack.arg8 = va_arg(args, unsigned int);
+	real_stack.arg9 = va_arg(args, unsigned int);
+	real_stack.arg10 = va_arg(args, unsigned int);
+	real_stack.arg11 = va_arg(args, unsigned int);
+	real_stack.arg12 = va_arg(args, unsigned int);
+	real_stack.arg13 = va_arg(args, unsigned int);
+	va_end(args);
+	
+	return real32_call_asm(&real_stack.sp, &real_stack.arg0, fn);
+}
+
+#ifdef __LP64__
+/***************** 64-bit real-mode calls ***********/
+
+struct wide_stack {
+	unsigned long arg0;
+	unsigned long arg1;
+	unsigned long arg2;
+	unsigned long arg3;
+	unsigned long arg4;
+	unsigned long arg5;
+	unsigned long arg6;
+	unsigned long arg7;
+	unsigned long arg8;
+	unsigned long arg9;
+	unsigned long arg10;
+	unsigned long arg11;
+	unsigned long arg12;
+	unsigned long arg13;
+	unsigned long frame_marker[2];	/* rp, previous sp */
+	unsigned long sp;
+	/* in reality, there's nearly 8k of stack after this */
+};
+
+static long real64_call(unsigned long fn, ...)
+{
+	va_list args;
+	extern struct wide_stack real_stack;
+	extern unsigned long real64_call_asm(unsigned long *,
+					     unsigned long *, 
+					     unsigned long);
+    
+	va_start(args, fn);
+	real_stack.arg0 = va_arg(args, unsigned long);
+	real_stack.arg1 = va_arg(args, unsigned long);
+	real_stack.arg2 = va_arg(args, unsigned long);
+	real_stack.arg3 = va_arg(args, unsigned long);
+	real_stack.arg4 = va_arg(args, unsigned long);
+	real_stack.arg5 = va_arg(args, unsigned long);
+	real_stack.arg6 = va_arg(args, unsigned long);
+	real_stack.arg7 = va_arg(args, unsigned long);
+	real_stack.arg8 = va_arg(args, unsigned long);
+	real_stack.arg9 = va_arg(args, unsigned long);
+	real_stack.arg10 = va_arg(args, unsigned long);
+	real_stack.arg11 = va_arg(args, unsigned long);
+	real_stack.arg12 = va_arg(args, unsigned long);
+	real_stack.arg13 = va_arg(args, unsigned long);
+	va_end(args);
+	
+	return real64_call_asm(&real_stack.sp, &real_stack.arg0, fn);
+}
+
+#endif /* __LP64__ */
+
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/hardware.c linux-2.4.20-pre2/arch/parisc/kernel/hardware.c
--- linux-2.4.20-pre1/arch/parisc/kernel/hardware.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/hardware.c	Mon Aug 12 16:34:14 2002
@@ -5,7 +5,7 @@
  * 
  *    Based on the document "PA-RISC 1.1 I/O Firmware Architecture 
  *    Reference Specification", March 7, 1999, version 0.96.  This
- *    is available at ?.
+ *    is available at http://parisc-linux.org/documentation/
  *
  *    Copyright 1999 by Alex deVries <adevries@thepuffingroup.com>
  *    and copyright 1999 The Puffin Group Inc.
@@ -30,32 +30,15 @@
 #include <asm/hardware.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-
-#define HPHW_NUM_TYPES 3431
-
-static char * hw_type_name[16] = {
-	"Processor",
-	"Memory",
-	"B DMA",
-	"Obsolete",
-	"A DMA",
-	"A Direct",
-	"Obsolete",
-	"Bus Converter Port",
-	"HP CIO Adapter",
-	"Console",
-	"Foreign I/O Module",
-	"Bus Adapter",
-	"IOA (?)",
-	"Bus Bridge to Foreign Bus",
-	"HP Clothing: Fabric Component"
-};
+#include <linux/init.h>
 
 /*
- *	XXX	Could this be __init ??
+ *	HP PARISC Hardware Database
+ *	Access to this database is only possible during bootup
+ *	so don't reference this table after starting the init process
  */
  
-static struct hp_hardware hp_hardware_list[] = {
+static struct hp_hardware hp_hardware_list[] __initdata = {
 	{HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"},
 	{HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"},
 	{HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"},
@@ -169,9 +152,10 @@
 	{HPHW_NPROC,0x59A,0x4,0x91,"Unlisted but reserved"},
 	{HPHW_NPROC,0x59A,0x4,0x81,"Unlisted but reserved"},
 	{HPHW_NPROC,0x59B,0x4,0x81,"Raven U 160 (9000/780/C160)"},
+	{HPHW_NPROC,0x59C,0x4,0x81,"Raven U 180 (9000/780/C180)"},
 	{HPHW_NPROC,0x59D,0x4,0x81,"Raven U 200 (9000/780/C200)"},
 	{HPHW_NPROC,0x59E,0x4,0x91,"ThunderHawk T' 120"},
-	{HPHW_NPROC,0x59F,0x4,0x91,"Raven U 180+ (9000/780/\?\?\?\?)"},
+	{HPHW_NPROC,0x59F,0x4,0x91,"Raven U 180+ (9000/780)"},
 	{HPHW_NPROC,0x5A0,0x4,0x81,"UL 1w T120 1MB/1MB (841/D260,D360)"},
 	{HPHW_NPROC,0x5A1,0x4,0x91,"UL 2w T120 1MB/1MB (851/D260,D360)"},
 	{HPHW_NPROC,0x5A2,0x4,0x81,"UL 1w U160 512K/512K (861/D270,D370)"},
@@ -201,7 +185,7 @@
 	{HPHW_NPROC,0x5B8,0x4,0x91,"SPP2250 240 MHz"},
 	{HPHW_NPROC,0x5B9,0x4,0x81,"UL 1w U+/240 (350/550)"},
 	{HPHW_NPROC,0x5BA,0x4,0x91,"UL 2w U+/240 (350/550)"},
-	{HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W "},
+	{HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W"},
 	{HPHW_NPROC,0x5BC,0x4,0x91,"AllegroLow W"},
 	{HPHW_NPROC,0x5BD,0x4,0x91,"Forte W 2-way"},
 	{HPHW_NPROC,0x5BE,0x4,0x91,"Prelude W"},
@@ -212,12 +196,41 @@
 	{HPHW_NPROC,0x5C3,0x4,0x91,"Sonata 360"},
 	{HPHW_NPROC,0x5C4,0x4,0x91,"Rhapsody 440"},
 	{HPHW_NPROC,0x5C5,0x4,0x91,"Rhapsody 360"},
-	{HPHW_NPROC,0x5C6,0x4,0x91,"Raven W 360 (9000/780/\?\?\?\?)"},
+	{HPHW_NPROC,0x5C6,0x4,0x91,"Raven W 360 (9000/780)"},
 	{HPHW_NPROC,0x5C7,0x4,0x91,"Halfdome W 440"},
 	{HPHW_NPROC,0x5C8,0x4,0x81,"Lego 360 processor"},
 	{HPHW_NPROC,0x5C9,0x4,0x91,"Rhapsody DC- 440"},
 	{HPHW_NPROC,0x5CA,0x4,0x91,"Rhapsody DC- 360"},
 	{HPHW_NPROC,0x5CB,0x4,0x91,"Crescendo 440"},
+	{HPHW_NPROC,0x5CC,0x4,0x91,"Prelude W 440"},
+	{HPHW_NPROC,0x5CD,0x4,0x91,"SPP2600"},
+	{HPHW_NPROC,0x5CE,0x4,0x91,"M2600"},
+	{HPHW_NPROC,0x5CF,0x4,0x81,"Allegro W+"},
+	{HPHW_NPROC,0x5D0,0x4,0x81,"Kazoo W+"},
+	{HPHW_NPROC,0x5D1,0x4,0x91,"Forte W+ 2w"},
+	{HPHW_NPROC,0x5D2,0x4,0x91,"Forte W+ 4w"},
+	{HPHW_NPROC,0x5D3,0x4,0x91,"Prelude W+ 540"},
+	{HPHW_NPROC,0x5D4,0x4,0x91,"Duet W+"},
+	{HPHW_NPROC,0x5D5,0x4,0x91,"Crescendo 550"},
+	{HPHW_NPROC,0x5D6,0x4,0x81,"Crescendo DC- 440"},
+	{HPHW_NPROC,0x5D7,0x4,0x91,"Keystone W+"},
+	{HPHW_NPROC,0x5D8,0x4,0x91,"Rhapsody wave 2 W+ DC-"},
+	{HPHW_NPROC,0x5D9,0x4,0x91,"Rhapsody wave 2 W+"},
+	{HPHW_NPROC,0x5DA,0x4,0x91,"Marcato W+ DC-"},
+	{HPHW_NPROC,0x5DB,0x4,0x91,"Marcato W+"},
+	{HPHW_NPROC,0x5DC,0x4,0x91,"Allegro W2"},
+	{HPHW_NPROC,0x5DD,0x4,0x81,"Duet W2"},
+	{HPHW_NPROC,0x5DE,0x4,0x81,"Piccolo W+"},
+	{HPHW_NPROC,0x5DF,0x4,0x81,"Cantata W2"},
+	{HPHW_NPROC,0x5E0,0x4,0x91,"Cantata DC- W2"},
+	{HPHW_NPROC,0x5E1,0x4,0x91,"Crescendo DC- W2"},
+	{HPHW_NPROC,0x5E2,0x4,0x91,"Crescendo 650 W2"},
+	{HPHW_NPROC,0x5E3,0x4,0x91,"Crescendo 750 W2"},
+	{HPHW_NPROC,0x5E4,0x4,0x91,"Keystone/Matterhorn W2 750"},
+	{HPHW_NPROC,0x5E5,0x4,0x91,"PowerBar W+"},
+	{HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"},
+	{HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
+	{HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"},
 	{HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
 	{HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
 	{HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
@@ -243,7 +256,7 @@
 	{HPHW_NPROC,0x616,0x4,0x81,"Piranha 120"},
 	{HPHW_NPROC,0x617,0x4,0x81,"Jason 50"},
 	{HPHW_NPROC,0x618,0x4,0x81,"Jason 100"},
-	{HPHW_NPROC,0x619,0x4,0x81,"Mirage 80 "},
+	{HPHW_NPROC,0x619,0x4,0x81,"Mirage 80"},
 	{HPHW_NPROC,0x61A,0x4,0x81,"SAIC L-80"},
 	{HPHW_NPROC,0x61B,0x4,0x81,"Rocky1 L-60"},
 	{HPHW_NPROC,0x61C,0x4,0x81,"Anole T (743/T)"},
@@ -311,6 +324,7 @@
 	{HPHW_A_DMA, 0x004, 0x00050, 0x80, "Lanbrusca 802.3 (36967A)"}, 
 	{HPHW_A_DMA, 0x004, 0x00056, 0x80, "HP-PB LoQuix FDDI"}, 
 	{HPHW_A_DMA, 0x004, 0x00057, 0x80, "HP-PB LoQuix FDDI (28670A)"}, 
+	{HPHW_A_DMA, 0x004, 0x0005E, 0x00, "Gecko Add-on Token Ring"}, 
 	{HPHW_A_DMA, 0x012, 0x00089, 0x80, "Barracuda Add-on FW-SCSI"}, 
 	{HPHW_A_DMA, 0x013, 0x00089, 0x80, "Bluefish Add-on FW-SCSI"}, 
 	{HPHW_A_DMA, 0x014, 0x00089, 0x80, "Shrike Add-on FW-SCSI"}, 
@@ -319,6 +333,7 @@
 	{HPHW_A_DMA, 0x01F, 0x00089, 0x80, "SkyHawk 100/120 FW-SCSI"}, 
 	{HPHW_A_DMA, 0x027, 0x00089, 0x80, "Piranha 100 FW-SCSI"}, 
 	{HPHW_A_DMA, 0x032, 0x00089, 0x80, "Raven T' Core FW-SCSI"}, 
+	{HPHW_A_DMA, 0x03b, 0x00089, 0x80, "Raven U/L2 Core FW-SCSI"}, 
 	{HPHW_A_DMA, 0x03d, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"},
 	{HPHW_A_DMA, 0x044, 0x00089, 0x80, "Mohawk Core FW-SCSI"}, 
 	{HPHW_A_DMA, 0x051, 0x00089, 0x80, "Firehawk FW-SCSI"}, 
@@ -440,6 +455,8 @@
 	{HPHW_BA, 0x801, 0x00081, 0x0, "Hitachi Tiny 80 Core BA"}, 
 	{HPHW_BA, 0x004, 0x0008B, 0x0, "Anole Optional PCMCIA BA"}, 
 	{HPHW_BA, 0x004, 0x0008E, 0x0, "GSC ITR Wax BA"}, 
+	{HPHW_BA, 0x00C, 0x0008E, 0x0, "Gecko Optional Wax BA"}, 
+	{HPHW_BA, 0x010, 0x0008E, 0x0, "Pace Wax BA"}, 
 	{HPHW_BA, 0x011, 0x0008E, 0x0, "SuperPace Wax BA"}, 
 	{HPHW_BA, 0x012, 0x0008E, 0x0, "Mirage Jr Wax BA"}, 
 	{HPHW_BA, 0x013, 0x0008E, 0x0, "Mirage Wax BA"}, 
@@ -489,7 +506,7 @@
 	{HPHW_BA, 0x800, 0x00090, 0x0, "Hitachi Tiny 64 Wax EISA BA"}, 
 	{HPHW_BA, 0x801, 0x00090, 0x0, "Hitachi Tiny 80 Wax EISA BA"}, 
 	{HPHW_BA, 0x01A, 0x00093, 0x0, "Anole 64 TIMI BA"}, 
-	{HPHW_BA, 0x01B, 0x00093, 0x0, "Anole 64 TIMI BA"}, 
+	{HPHW_BA, 0x01B, 0x00093, 0x0, "Anole 100 TIMI BA"}, 
 	{HPHW_BA, 0x034, 0x00093, 0x0, "Anole T TIMI BA"}, 
 	{HPHW_BA, 0x04A, 0x00093, 0x0, "Anole L2 132 TIMI BA"}, 
 	{HPHW_BA, 0x04C, 0x00093, 0x0, "Anole L2 165 TIMI BA"}, 
@@ -551,6 +568,7 @@
 	{HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, 
 	{HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, 
 	{HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, 
+	{HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"}, 
 	{HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, 
 	{HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, 
 	{HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, 
@@ -588,14 +606,14 @@
 	{HPHW_FIO, 0x00D, 0x00072, 0x0, "Strider-33 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x00E, 0x00072, 0x0, "Trailways-50 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x00F, 0x00072, 0x0, "Trailways-33 Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x010, 0x00072, 0x0, "Pace Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x011, 0x00072, 0x0, "Sidewinder Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x010, 0x00072, 0x0, "Pace Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x011, 0x00072, 0x0, "Sidewinder Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x019, 0x00072, 0x0, "Scorpio Sr. Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x020, 0x00072, 0x0, "Scorpio 100 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x021, 0x00072, 0x0, "Spectra 50 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x022, 0x00072, 0x0, "Spectra 75 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x023, 0x00072, 0x0, "Spectra 100 Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x024, 0x00072, 0x0, "Fast Pace Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x024, 0x00072, 0x0, "Fast Pace Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x026, 0x00072, 0x0, "CoralII Jaguar Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x004, 0x00073, 0x0, "Cobra Core HIL"}, 
 	{HPHW_FIO, 0x005, 0x00073, 0x0, "Coral Core HIL"}, 
@@ -694,8 +712,8 @@
 	{HPHW_FIO, 0x04D, 0x00074, 0x0, "Anole L2 165 Core Centronics"}, 
 	{HPHW_FIO, 0x050, 0x00074, 0x0, "Merlin Jr 132 Core Centronics"}, 
 	{HPHW_FIO, 0x051, 0x00074, 0x0, "Firehawk Core Centronics"}, 
-	{HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ wSE FWSCSI Core Centronics"}, 
-	{HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ wDiff FWSCSI Core Centronics"}, 
+	{HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ w SE FWSCSI Core Centronics"}, 
+	{HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ w Diff FWSCSI Core Centronics"}, 
 	{HPHW_FIO, 0x058, 0x00074, 0x0, "FireHawk 200 Core Centronics"}, 
 	{HPHW_FIO, 0x05C, 0x00074, 0x0, "SummitHawk 230 Core Centronics"}, 
 	{HPHW_FIO, 0x800, 0x00074, 0x0, "Hitachi Tiny 64 Core Centronics"}, 
@@ -861,66 +879,66 @@
 	{HPHW_FIO, 0x02E, 0x00083, 0x0, "UL 350 Core PC Floppy"}, 
 	{HPHW_FIO, 0x02F, 0x00083, 0x0, "UL 550 Core PC Floppy"}, 
 	{HPHW_FIO, 0x032, 0x00083, 0x0, "Raven T' Core PC Floppy"}, 
-	{HPHW_FIO, 0x034, 0x00083, 0x0, "SAIC L-80 Core PC Floopy"}, 
-	{HPHW_FIO, 0x035, 0x00083, 0x0, "PCX-L2 712/132 Core Floopy"}, 
-	{HPHW_FIO, 0x036, 0x00083, 0x0, "PCX-L2 712/160 Core Floopy"}, 
-	{HPHW_FIO, 0x03B, 0x00083, 0x0, "Raven U/L2 Core PC Floopy"}, 
-	{HPHW_FIO, 0x03C, 0x00083, 0x0, "Merlin 132 Core PC Floopy"}, 
-	{HPHW_FIO, 0x03D, 0x00083, 0x0, "Merlin 160 Core PC Floopy"}, 
-	{HPHW_FIO, 0x03E, 0x00083, 0x0, "Merlin+ 132 Core PC Floopy"}, 
-	{HPHW_FIO, 0x03F, 0x00083, 0x0, "Merlin+ 180 Core PC Floopy"}, 
-	{HPHW_FIO, 0x045, 0x00083, 0x0, "Rocky1 Core PC Floopy"}, 
-	{HPHW_FIO, 0x046, 0x00083, 0x0, "Rocky2 120 Core PC Floopy"}, 
-	{HPHW_FIO, 0x047, 0x00083, 0x0, "Rocky2 150 Core PC Floopy"}, 
-	{HPHW_FIO, 0x04E, 0x00083, 0x0, "Kiji L2 132 Core PC Floopy"}, 
-	{HPHW_FIO, 0x050, 0x00083, 0x0, "Merlin Jr 132 Core PC Floopy"}, 
-	{HPHW_FIO, 0x056, 0x00083, 0x0, "Raven+ w SE FWSCSI Core PC Floopy"}, 
-	{HPHW_FIO, 0x057, 0x00083, 0x0, "Raven+ w Diff FWSCSI Core PC Floopy"}, 
-	{HPHW_FIO, 0x800, 0x00083, 0x0, "Hitachi Tiny 64 Core PC Floopy"}, 
-	{HPHW_FIO, 0x801, 0x00083, 0x0, "Hitachi Tiny 80 Core PC Floopy"}, 
-	{HPHW_FIO, 0x015, 0x00084, 0x0, "KittyHawk GSY Core PC Keyboard"}, 
-	{HPHW_FIO, 0x016, 0x00084, 0x0, "Gecko Core PC Keyboard"}, 
-	{HPHW_FIO, 0x018, 0x00084, 0x0, "Gecko Optional PC Keyboard"}, 
-	{HPHW_FIO, 0x01A, 0x00084, 0x0, "Anole 64 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x01B, 0x00084, 0x0, "Anole 100 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x01C, 0x00084, 0x0, "Gecko 80 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x01D, 0x00084, 0x0, "Gecko 100 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x01F, 0x00084, 0x0, "SkyHawk 100/120 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x027, 0x00084, 0x0, "Piranha 100 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x028, 0x00084, 0x0, "Mirage Jr Core PC Keyboard"}, 
-	{HPHW_FIO, 0x029, 0x00084, 0x0, "Mirage Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02A, 0x00084, 0x0, "Electra Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02B, 0x00084, 0x0, "Mirage 80 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02C, 0x00084, 0x0, "Mirage 100+ Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02E, 0x00084, 0x0, "UL 350 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x02F, 0x00084, 0x0, "UL 550 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x032, 0x00084, 0x0, "Raven T' Core PC Keyboard"}, 
-	{HPHW_FIO, 0x033, 0x00084, 0x0, "Anole T Core PC Keyboard"}, 
-	{HPHW_FIO, 0x034, 0x00084, 0x0, "SAIC L-80 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x035, 0x00084, 0x0, "PCX-L2 712/132 Core Keyboard"}, 
-	{HPHW_FIO, 0x036, 0x00084, 0x0, "PCX-L2 712/160 Core Keyboard"}, 
-	{HPHW_FIO, 0x03B, 0x00084, 0x0, "Raven U/L2 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x03C, 0x00084, 0x0, "Merlin 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x03D, 0x00084, 0x0, "Merlin 160 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x03E, 0x00084, 0x0, "Merlin+ 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x03F, 0x00084, 0x0, "Merlin+ 180 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x044, 0x00084, 0x0, "Mohawk Core PC Keyboard"}, 
-	{HPHW_FIO, 0x045, 0x00084, 0x0, "Rocky1 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x046, 0x00084, 0x0, "Rocky2 120 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x047, 0x00084, 0x0, "Rocky2 150 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x048, 0x00084, 0x0, "Rocky2 120 Dino PC Keyboard"}, 
-	{HPHW_FIO, 0x049, 0x00084, 0x0, "Rocky2 150 Dino PC Keyboard"}, 
-	{HPHW_FIO, 0x04B, 0x00084, 0x0, "Anole L2 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x04D, 0x00084, 0x0, "Anole L2 165 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x04E, 0x00084, 0x0, "Kiji L2 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x050, 0x00084, 0x0, "Merlin Jr 132 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x051, 0x00084, 0x0, "Firehawk Core PC Keyboard"}, 
-	{HPHW_FIO, 0x056, 0x00084, 0x0, "Raven+ w SE FWSCSI Core PC Keyboard"}, 
-	{HPHW_FIO, 0x057, 0x00084, 0x0, "Raven+ w Diff FWSCSI Core PC Keyboard"}, 
-	{HPHW_FIO, 0x058, 0x00084, 0x0, "FireHawk 200 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x05C, 0x00084, 0x0, "SummitHawk 230 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x800, 0x00084, 0x0, "Hitachi Tiny 64 Core PC Keyboard"}, 
-	{HPHW_FIO, 0x801, 0x00084, 0x0, "Hitachi Tiny 80 Core PC Keyboard"}, 
+	{HPHW_FIO, 0x034, 0x00083, 0x0, "SAIC L-80 Core PC Floppy"}, 
+	{HPHW_FIO, 0x035, 0x00083, 0x0, "PCX-L2 712/132 Core Floppy"}, 
+	{HPHW_FIO, 0x036, 0x00083, 0x0, "PCX-L2 712/160 Core Floppy"}, 
+	{HPHW_FIO, 0x03B, 0x00083, 0x0, "Raven U/L2 Core PC Floppy"}, 
+	{HPHW_FIO, 0x03C, 0x00083, 0x0, "Merlin 132 Core PC Floppy"}, 
+	{HPHW_FIO, 0x03D, 0x00083, 0x0, "Merlin 160 Core PC Floppy"}, 
+	{HPHW_FIO, 0x03E, 0x00083, 0x0, "Merlin+ 132 Core PC Floppy"}, 
+	{HPHW_FIO, 0x03F, 0x00083, 0x0, "Merlin+ 180 Core PC Floppy"}, 
+	{HPHW_FIO, 0x045, 0x00083, 0x0, "Rocky1 Core PC Floppy"}, 
+	{HPHW_FIO, 0x046, 0x00083, 0x0, "Rocky2 120 Core PC Floppy"}, 
+	{HPHW_FIO, 0x047, 0x00083, 0x0, "Rocky2 150 Core PC Floppy"}, 
+	{HPHW_FIO, 0x04E, 0x00083, 0x0, "Kiji L2 132 Core PC Floppy"}, 
+	{HPHW_FIO, 0x050, 0x00083, 0x0, "Merlin Jr 132 Core PC Floppy"}, 
+	{HPHW_FIO, 0x056, 0x00083, 0x0, "Raven+ w SE FWSCSI Core PC Floppy"}, 
+	{HPHW_FIO, 0x057, 0x00083, 0x0, "Raven+ w Diff FWSCSI Core PC Floppy"}, 
+	{HPHW_FIO, 0x800, 0x00083, 0x0, "Hitachi Tiny 64 Core PC Floppy"}, 
+	{HPHW_FIO, 0x801, 0x00083, 0x0, "Hitachi Tiny 80 Core PC Floppy"},
+	{HPHW_FIO, 0x015, 0x00084, 0x0, "KittyHawk GSY Core PS/2 Port"}, 
+	{HPHW_FIO, 0x016, 0x00084, 0x0, "Gecko Core PS/2 Port"}, 
+	{HPHW_FIO, 0x018, 0x00084, 0x0, "Gecko Optional PS/2 Port"}, 
+	{HPHW_FIO, 0x01A, 0x00084, 0x0, "Anole 64 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x01B, 0x00084, 0x0, "Anole 100 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x01C, 0x00084, 0x0, "Gecko 80 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x01D, 0x00084, 0x0, "Gecko 100 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x01F, 0x00084, 0x0, "SkyHawk 100/120 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x027, 0x00084, 0x0, "Piranha 100 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x028, 0x00084, 0x0, "Mirage Jr Core PS/2 Port"}, 
+	{HPHW_FIO, 0x029, 0x00084, 0x0, "Mirage Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02A, 0x00084, 0x0, "Electra Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02B, 0x00084, 0x0, "Mirage 80 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02C, 0x00084, 0x0, "Mirage 100+ Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02E, 0x00084, 0x0, "UL 350 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x02F, 0x00084, 0x0, "UL 550 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x032, 0x00084, 0x0, "Raven T' Core PS/2 Port"}, 
+	{HPHW_FIO, 0x033, 0x00084, 0x0, "Anole T Core PS/2 Port"}, 
+	{HPHW_FIO, 0x034, 0x00084, 0x0, "SAIC L-80 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x035, 0x00084, 0x0, "PCX-L2 712/132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x036, 0x00084, 0x0, "PCX-L2 712/160 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03B, 0x00084, 0x0, "Raven U/L2 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03C, 0x00084, 0x0, "Merlin 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03D, 0x00084, 0x0, "Merlin 160 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03E, 0x00084, 0x0, "Merlin+ 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x03F, 0x00084, 0x0, "Merlin+ 180 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x044, 0x00084, 0x0, "Mohawk Core PS/2 Port"}, 
+	{HPHW_FIO, 0x045, 0x00084, 0x0, "Rocky1 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x046, 0x00084, 0x0, "Rocky2 120 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x047, 0x00084, 0x0, "Rocky2 150 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x048, 0x00084, 0x0, "Rocky2 120 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x049, 0x00084, 0x0, "Rocky2 150 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x04B, 0x00084, 0x0, "Anole L2 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x04D, 0x00084, 0x0, "Anole L2 165 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x04E, 0x00084, 0x0, "Kiji L2 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x050, 0x00084, 0x0, "Merlin Jr 132 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x051, 0x00084, 0x0, "Firehawk Core PS/2 Port"}, 
+	{HPHW_FIO, 0x056, 0x00084, 0x0, "Raven+ w SE FWSCSI Core PS/2 Port"}, 
+	{HPHW_FIO, 0x057, 0x00084, 0x0, "Raven+ w Diff FWSCSI Core PS/2 Port"}, 
+	{HPHW_FIO, 0x058, 0x00084, 0x0, "FireHawk 200 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x05C, 0x00084, 0x0, "SummitHawk 230 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x800, 0x00084, 0x0, "Hitachi Tiny 64 Core PS/2 Port"}, 
+	{HPHW_FIO, 0x801, 0x00084, 0x0, "Hitachi Tiny 80 Core PS/2 Port"}, 
 	{HPHW_FIO, 0x004, 0x00085, 0x0, "Solo GSC Optional Graphics"}, 
 	{HPHW_FIO, 0x005, 0x00085, 0x0, "Duet GSC Optional Graphics"}, 
 	{HPHW_FIO, 0x008, 0x00085, 0x0, "Anole Artist Optional Graphics"}, 
@@ -969,18 +987,17 @@
 	{HPHW_FIO, 0x034, 0x00088, 0x0, "Anole T VME Networking"}, 
 	{HPHW_FIO, 0x04A, 0x00088, 0x0, "Anole L2 132 VME Networking"}, 
 	{HPHW_FIO, 0x04C, 0x00088, 0x0, "Anole L2 165 VME Networking"}, 
-	{HPHW_FIO, 0x03B, 0x00089, 0x0, "Raven U/L2 Core FW-SCSI"}, 
-	{HPHW_FIO, 0x011, 0x0008A, 0x0, "WB-96 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x012, 0x0008A, 0x0, "Orville Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x013, 0x0008A, 0x0, "Wilbur Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x014, 0x0008A, 0x0, "WB-80 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x015, 0x0008A, 0x0, "KittyHawk GSY Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x016, 0x0008A, 0x0, "Gecko Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x018, 0x0008A, 0x0, "Gecko Optional Lan (802.3)"}, 
-	{HPHW_FIO, 0x01A, 0x0008A, 0x0, "Anole 64 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x01B, 0x0008A, 0x0, "Anole 100 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x01C, 0x0008A, 0x0, "Gecko 80 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x01D, 0x0008A, 0x0, "Gecko 100 Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x011, 0x0008A, 0x0, "WB-96 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x012, 0x0008A, 0x0, "Orville Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x013, 0x0008A, 0x0, "Wilbur Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x014, 0x0008A, 0x0, "WB-80 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x015, 0x0008A, 0x0, "KittyHawk GSY Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x016, 0x0008A, 0x0, "Gecko Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x018, 0x0008A, 0x0, "Gecko Optional LAN (802.3)"}, 
+	{HPHW_FIO, 0x01A, 0x0008A, 0x0, "Anole 64 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x01B, 0x0008A, 0x0, "Anole 100 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x01C, 0x0008A, 0x0, "Gecko 80 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x01D, 0x0008A, 0x0, "Gecko 100 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x01F, 0x0008A, 0x0, "SkyHawk 100/120 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x027, 0x0008A, 0x0, "Piranha 100 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x028, 0x0008A, 0x0, "Mirage Jr Core LAN (802.3)"}, 
@@ -991,24 +1008,24 @@
 	{HPHW_FIO, 0x02E, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x02F, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x032, 0x0008A, 0x0, "Raven T' Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x033, 0x0008A, 0x0, "Anole T Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x034, 0x0008A, 0x0, "SAIC L-80 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x035, 0x0008A, 0x0, "PCX-L2 712/132 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x036, 0x0008A, 0x0, "PCX-L2 712/160 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x03B, 0x0008A, 0x0, "Raven U/L2 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x03C, 0x0008A, 0x0, "Merlin 132 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x03D, 0x0008A, 0x0, "Merlin 160 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x044, 0x0008A, 0x0, "Mohawk Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x033, 0x0008A, 0x0, "Anole T Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x034, 0x0008A, 0x0, "SAIC L-80 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x035, 0x0008A, 0x0, "PCX-L2 712/132 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x036, 0x0008A, 0x0, "PCX-L2 712/160 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x03B, 0x0008A, 0x0, "Raven U/L2 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x03C, 0x0008A, 0x0, "Merlin 132 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x03D, 0x0008A, 0x0, "Merlin 160 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x044, 0x0008A, 0x0, "Mohawk Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x045, 0x0008A, 0x0, "Rocky1 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x046, 0x0008A, 0x0, "Rocky2 120 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x047, 0x0008A, 0x0, "Rocky2 150 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x04B, 0x0008A, 0x0, "Anole L2 132 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x04D, 0x0008A, 0x0, "Anole L2 165 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x04E, 0x0008A, 0x0, "Kiji L2 132 Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x050, 0x0008A, 0x0, "Merlin Jr 132 Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x050, 0x0008A, 0x0, "Merlin Jr 132 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x058, 0x0008A, 0x0, "FireHawk 200 Core LAN (802.3)"}, 
-	{HPHW_FIO, 0x800, 0x0008A, 0x0, "Hitachi Tiny 64 Core Lan (802.3)"}, 
-	{HPHW_FIO, 0x801, 0x0008A, 0x0, "Hitachi Tiny 80 Core Lan (802.3)"}, 
+	{HPHW_FIO, 0x800, 0x0008A, 0x0, "Hitachi Tiny 64 Core LAN (802.3)"}, 
+	{HPHW_FIO, 0x801, 0x0008A, 0x0, "Hitachi Tiny 80 Core LAN (802.3)"}, 
 	{HPHW_FIO, 0x004, 0x0008C, 0x0, "SkyHawk 100/120 Wax RS-232"}, 
 	{HPHW_FIO, 0x005, 0x0008C, 0x0, "SAIC L-80 Wax RS-232"}, 
 	{HPHW_FIO, 0x006, 0x0008C, 0x0, "Raven U/L2 Dino RS-232"}, 
@@ -1099,14 +1116,15 @@
 	{HPHW_FIO, 0x005, 0x0008F, 0x0, "Rocky1 Boot Rom"}, 
 	{HPHW_FIO, 0x006, 0x0008F, 0x0, "Rocky2 120 Boot Rom"}, 
 	{HPHW_FIO, 0x007, 0x0008F, 0x0, "Rocky2 150 Boot Rom"}, 
-	{HPHW_FIO, 0x006, 0x00096, 0x0, "Raven U/L2 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x007, 0x00096, 0x0, "Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x008, 0x00096, 0x0, "Merlin 132 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x009, 0x00096, 0x0, "Merlin 160 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x00A, 0x00096, 0x0, "Merlin Jr 132 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x019, 0x00096, 0x0, "Merlin+ 180 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x022, 0x00096, 0x0, "Merlin+ 132 Dino PS2 Keyboard"}, 
-	{HPHW_FIO, 0x004, 0x00097, 0x0, "Cascade EISA 100VG lan"}, 
+	{HPHW_FIO, 0x01B, 0x0008F, 0x0, "Anole 100 Boot Rom"}, 
+	{HPHW_FIO, 0x006, 0x00096, 0x0, "Raven U/L2 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x007, 0x00096, 0x0, "Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x008, 0x00096, 0x0, "Merlin 132 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x009, 0x00096, 0x0, "Merlin 160 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x00A, 0x00096, 0x0, "Merlin Jr 132 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x019, 0x00096, 0x0, "Merlin+ 180 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x022, 0x00096, 0x0, "Merlin+ 132 Dino PS/2 Port"}, 
+	{HPHW_FIO, 0x004, 0x00097, 0x0, "Cascade EISA 100VG LAN"}, 
 	{HPHW_FIO, 0x023, 0x00099, 0x0, "Rocky1 Wax HPIB"}, 
 	{HPHW_FIO, 0x048, 0x00099, 0x0, "Rocky2 120 Clark/Dino HPIB"}, 
 	{HPHW_FIO, 0x049, 0x00099, 0x0, "Rocky2 150 Clark/Dino HPIB"}, 
@@ -1114,14 +1132,14 @@
 	{HPHW_FIO, 0x004, 0x000A2, 0x0, "Forte Core PCI 10/100BT LAN"}, 
 	{HPHW_FIO, 0x005, 0x000A2, 0x0, "AllegroLow PCI 10/100BT LAN"}, 
 	{HPHW_FIO, 0x006, 0x000A2, 0x0, "AllegroHIgh Core PCI 10/100BT LAN"}, 
-	{HPHW_FIO, 0x007, 0x000A2, 0x0, "PCI Plug-in Lan"}, 
-	{HPHW_FIO, 0x00A, 0x000A2, 0x0, "Lego 360 Core PCI 10/100BT Lan"}, 
-	{HPHW_FIO, 0x03E, 0x000A2, 0x0, "Merlin+ 132 Core PCI Lan"}, 
-	{HPHW_FIO, 0x03F, 0x000A2, 0x0, "Merlin+ 180 Core PCI Lan"}, 
-	{HPHW_FIO, 0x056, 0x000A2, 0x0, "Raven+ w SE FWSCSI Core PCI Lan"}, 
-	{HPHW_FIO, 0x057, 0x000A2, 0x0, "Raven+ w Diff FWSCSI Core PCI Lan"}, 
-	{HPHW_FIO, 0x05E, 0x000A2, 0x0, "Staccato 132 PCI Lan"}, 
-	{HPHW_FIO, 0x05F, 0x000A2, 0x0, "Staccato 180 PCI Lan"}, 
+	{HPHW_FIO, 0x007, 0x000A2, 0x0, "PCI Plug-in LAN"}, 
+	{HPHW_FIO, 0x00A, 0x000A2, 0x0, "Lego 360 Core PCI 10/100BT LAN"}, 
+	{HPHW_FIO, 0x03E, 0x000A2, 0x0, "Merlin+ 132 Core PCI LAN"}, 
+	{HPHW_FIO, 0x03F, 0x000A2, 0x0, "Merlin+ 180 Core PCI LAN"}, 
+	{HPHW_FIO, 0x056, 0x000A2, 0x0, "Raven+ w SE FWSCSI Core PCI LAN"}, 
+	{HPHW_FIO, 0x057, 0x000A2, 0x0, "Raven+ w Diff FWSCSI Core PCI LAN"}, 
+	{HPHW_FIO, 0x05E, 0x000A2, 0x0, "Staccato 132 PCI LAN"}, 
+	{HPHW_FIO, 0x05F, 0x000A2, 0x0, "Staccato 180 PCI LAN"}, 
 	{HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI LVD Ultra2 SCSI"}, 
 	{HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI SE UltraSCSI"}, 
 	{HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI IDE/ATAPI CD-ROM"}, 
@@ -1157,160 +1175,19 @@
 	{HPHW_IOA, 0x185, 0x0000B, 0x00, "Java BC Summit Port"}, 
 	{HPHW_IOA, 0x1FF, 0x0000B, 0x00, "Hitachi Ghostview Summit Port"}, 
 	{HPHW_IOA, 0x580, 0x0000B, 0x10, "U2-IOA BC Runway Port"}, 
-	{HPHW_IOA, 0x581, 0x0000B, 0x10, "Uturn-IOA BC Runway Port"}, 
-	{HPHW_IOA, 0x582, 0x0000B, 0x10, "Astro BC Runway Port"}, 
-	{HPHW_IOA, 0x700, 0x0000B, 0x00, "NEC-IOS BC System Bus Port"}, 
+	{HPHW_IOA, 0x581, 0x0000B, 0x10, "Uturn-IOA BC Runway Port"},
+	{HPHW_IOA, 0x582, 0x0000B, 0x10, "Astro BC Runway Port"},
+	{HPHW_IOA, 0x700, 0x0000B, 0x00, "NEC-IOS BC System Bus Port"},
 	{HPHW_MEMORY, 0x002, 0x00008, 0x00, "MID_BUS"}, 
-	{HPHW_MEMORY, 0x00C, 0x00008, 0x08, "Kahlua 8MB"}, 
-	{HPHW_MEMORY, 0x00D, 0x00008, 0x08, "Kahlua 4MB"}, 
-	{HPHW_MEMORY, 0x00E, 0x00008, 0x08, "Tequila 16MB"}, 
-	{HPHW_MEMORY, 0x00F, 0x00008, 0x08, "Tequila 32MB"}, 
-	{HPHW_MEMORY, 0x040, 0x00008, 0x00, "Hitachi"}, 
-	{HPHW_MEMORY, 0x004, 0x00009, 0x00, "Cheetah"}, 
-	{HPHW_MEMORY, 0x005, 0x00009, 0x00, "Emerald"}, 
-	{HPHW_MEMORY, 0x008, 0x00009, 0x00, "Indigo 3MB/5MB"}, 
-	{HPHW_MEMORY, 0x00C, 0x00009, 0x00, "Indigo 8MB"}, 
-	{HPHW_MEMORY, 0x00D, 0x00009, 0x00, "Paradise 4MB"}, 
-	{HPHW_MEMORY, 0x00E, 0x00009, 0x00, "Burgundy Onboard"}, 
-	{HPHW_MEMORY, 0x012, 0x00009, 0x00, "Indigo 12MB/20MB"}, 
-	{HPHW_MEMORY, 0x013, 0x00009, 0x00, "Cobra"}, 
-	{HPHW_MEMORY, 0x014, 0x00009, 0x00, "Nova"}, 
-	{HPHW_MEMORY, 0x015, 0x00009, 0x00, "Coral"}, 
-	{HPHW_MEMORY, 0x016, 0x00009, 0x00, "Bushmaster"}, 
-	{HPHW_MEMORY, 0x017, 0x00009, 0x00, "Scorpio"}, 
-	{HPHW_MEMORY, 0x018, 0x00009, 0x00, "Flounder"}, 
-	{HPHW_MEMORY, 0x019, 0x00009, 0x00, "Hardball"}, 
-	{HPHW_MEMORY, 0x01A, 0x00009, 0x00, "CoralII 99"}, 
-	{HPHW_MEMORY, 0x01B, 0x00009, 0x00, "Scorpio Jr."}, 
-	{HPHW_MEMORY, 0x01C, 0x00009, 0x00, "Strider-50 (715T)"}, 
-	{HPHW_MEMORY, 0x01D, 0x00009, 0x00, "Strider-33 (707T)"}, 
-	{HPHW_MEMORY, 0x01E, 0x00009, 0x00, "Trailways-50 (715S)"}, 
-	{HPHW_MEMORY, 0x01F, 0x00009, 0x00, "Trailways-33 (707S)"}, 
-	{HPHW_MEMORY, 0x020, 0x00009, 0x00, "Pace"}, 
-	{HPHW_MEMORY, 0x021, 0x00009, 0x00, "Sidewinder"}, 
-	{HPHW_MEMORY, 0x022, 0x00009, 0x00, "Orville"}, 
-	{HPHW_MEMORY, 0x023, 0x00009, 0x00, "Wilbur"}, 
-	{HPHW_MEMORY, 0x026, 0x00009, 0x00, "Gecko"}, 
-	{HPHW_MEMORY, 0x027, 0x00009, 0x00, "Scorpio Sr."}, 
-	{HPHW_MEMORY, 0x028, 0x00009, 0x00, "Scorpio 100"}, 
-	{HPHW_MEMORY, 0x029, 0x00009, 0x00, "Spectra 50"}, 
-	{HPHW_MEMORY, 0x02A, 0x00009, 0x00, "CoralII 132"}, 
-	{HPHW_MEMORY, 0x02F, 0x00009, 0x00, "KittyHawk DC2-"}, 
-	{HPHW_MEMORY, 0x030, 0x00009, 0x00, "Spectra 75"}, 
-	{HPHW_MEMORY, 0x031, 0x00009, 0x00, "Spectra 100"}, 
-	{HPHW_MEMORY, 0x032, 0x00009, 0x00, "KittyHawk DC3"}, 
-	{HPHW_MEMORY, 0x033, 0x00009, 0x00, "Fast Pace"}, 
-	{HPHW_MEMORY, 0x034, 0x00009, 0x00, "Snake Eagle"}, 
-	{HPHW_MEMORY, 0x035, 0x00009, 0x00, "Anole 64"}, 
-	{HPHW_MEMORY, 0x036, 0x00009, 0x00, "Anole 100"}, 
-	{HPHW_MEMORY, 0x037, 0x00009, 0x00, "Snake Cheetah"}, 
-	{HPHW_MEMORY, 0x038, 0x00009, 0x00, "Gecko 80"}, 
-	{HPHW_MEMORY, 0x039, 0x00009, 0x00, "Gecko 100"}, 
-	{HPHW_MEMORY, 0x03A, 0x00009, 0x00, "Gecko 120"}, 
-	{HPHW_MEMORY, 0x03B, 0x00009, 0x00, "Gila 80"}, 
-	{HPHW_MEMORY, 0x03C, 0x00009, 0x00, "Gila 100"}, 
-	{HPHW_MEMORY, 0x03D, 0x00009, 0x00, "Gila 120"}, 
-	{HPHW_MEMORY, 0x03E, 0x00009, 0x00, "Scorpio-L 80"}, 
-	{HPHW_MEMORY, 0x03F, 0x00009, 0x00, "Scorpio-L 100"}, 
-	{HPHW_MEMORY, 0x040, 0x00009, 0x00, "Scorpio-L 120"}, 
-	{HPHW_MEMORY, 0x041, 0x00009, 0x00, "Spectra-L 80"}, 
-	{HPHW_MEMORY, 0x042, 0x00009, 0x00, "Spectra-L 100"}, 
-	{HPHW_MEMORY, 0x043, 0x00009, 0x00, "Spectra-L 120"}, 
-	{HPHW_MEMORY, 0x044, 0x00009, 0x00, "Piranha 100"}, 
-	{HPHW_MEMORY, 0x045, 0x00009, 0x00, "Piranha 120"}, 
-	{HPHW_MEMORY, 0x046, 0x00009, 0x00, "Jason 50"}, 
-	{HPHW_MEMORY, 0x047, 0x00009, 0x00, "Jason 100"}, 
-	{HPHW_MEMORY, 0x049, 0x00009, 0x00, "SkyHawk 100/120"}, 
-	{HPHW_MEMORY, 0x04A, 0x00009, 0x00, "Mirage Jr"}, 
-	{HPHW_MEMORY, 0x04B, 0x00009, 0x00, "Mirage 100"}, 
-	{HPHW_MEMORY, 0x04C, 0x00009, 0x00, "Mirage 100+"}, 
-	{HPHW_MEMORY, 0x04D, 0x00009, 0x00, "Electra 100"}, 
-	{HPHW_MEMORY, 0x04E, 0x00009, 0x00, "Electra 120"}, 
-	{HPHW_MEMORY, 0x04F, 0x00009, 0x00, "Mirage 80"}, 
-	{HPHW_MEMORY, 0x050, 0x00009, 0x00, "UL Proc 1 way T'100"}, 
-	{HPHW_MEMORY, 0x051, 0x00009, 0x00, "UL Proc 1 way T'120"}, 
-	{HPHW_MEMORY, 0x052, 0x00009, 0x00, "UL Proc 2 way T'100"}, 
-	{HPHW_MEMORY, 0x053, 0x00009, 0x00, "KittyHawk DC3-"}, 
-	{HPHW_MEMORY, 0x054, 0x00009, 0x00, "UL Proc 2 way T'120"}, 
-	{HPHW_MEMORY, 0x055, 0x00009, 0x00, "Raven 120 mem"}, 
-	{HPHW_MEMORY, 0x056, 0x00009, 0x00, "UL Proc L 75"}, 
-	{HPHW_MEMORY, 0x057, 0x00009, 0x00, "UL Proc L 100"}, 
-	{HPHW_MEMORY, 0x058, 0x00009, 0x00, "Anole T"}, 
-	{HPHW_MEMORY, 0x059, 0x00009, 0x00, "SAIC L-80"}, 
-	{HPHW_MEMORY, 0x05A, 0x00009, 0x00, "Merlin+ L2 180"}, 
-	{HPHW_MEMORY, 0x05B, 0x00009, 0x00, "Raven U 200 2-way"}, 
-	{HPHW_MEMORY, 0x05C, 0x00009, 0x00, "Raven U 180+"}, 
-	{HPHW_MEMORY, 0x05D, 0x00009, 0x00, "Raven U 200"}, 
-	{HPHW_MEMORY, 0x05E, 0x00009, 0x00, "Rocky2 150 Memory"}, 
-	{HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, 
-	{HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, 
-	{HPHW_MEMORY, 0x05F, 0x00009, 0x00, "SPP2000 Memory"}, 
-	{HPHW_MEMORY, 0x060, 0x00009, 0x00, "Merlin L2 132"}, 
-	{HPHW_MEMORY, 0x061, 0x00009, 0x00, "Merlin+ L2 132"}, 
 	{HPHW_MEMORY, 0x063, 0x00009, 0x00, "712/132 L2 Upgrade"}, 
 	{HPHW_MEMORY, 0x064, 0x00009, 0x00, "712/160 L2 Upgrade"}, 
 	{HPHW_MEMORY, 0x065, 0x00009, 0x00, "715/132 L2 Upgrade"}, 
-	{HPHW_MEMORY, 0x066, 0x00009, 0x00, "715/160 L2 Upgrade"}, 
-	{HPHW_MEMORY, 0x067, 0x00009, 0x00, "Merlin 160/ThunderHawk Memory"}, 
-	{HPHW_MEMORY, 0x068, 0x00009, 0x00, "LightningHawk Memory"}, 
-	{HPHW_MEMORY, 0x069, 0x00009, 0x00, "Rocky1 Memory"}, 
-	{HPHW_MEMORY, 0x06A, 0x00009, 0x00, "Raven L2 132"}, 
-	{HPHW_MEMORY, 0x06B, 0x00009, 0x00, "Raven L2 160"}, 
-	{HPHW_MEMORY, 0x06C, 0x00009, 0x00, "Raven L2 187"}, 
-	{HPHW_MEMORY, 0x06D, 0x00009, 0x00, "Raven L2 200"}, 
-	{HPHW_MEMORY, 0x06E, 0x00009, 0x00, "Raven U 230"}, 
-	{HPHW_MEMORY, 0x06F, 0x00009, 0x00, "Raven U 240"}, 
-	{HPHW_MEMORY, 0x070, 0x00009, 0x00, "Rocky2 120 Memory"}, 
-	{HPHW_MEMORY, 0x071, 0x00009, 0x00, "Raven U 160"}, 
-	{HPHW_MEMORY, 0x072, 0x00009, 0x00, "Raven U 180"}, 
-	{HPHW_MEMORY, 0x072, 0x00009, 0x00, "UL Proc 1 way T'120 1MB/1MB"}, 
-	{HPHW_MEMORY, 0x073, 0x00009, 0x00, "UL Proc 2 way T'120 1MB/1MB"}, 
-	{HPHW_MEMORY, 0x074, 0x00009, 0x00, "Anole L2 132 memory"}, 
-	{HPHW_MEMORY, 0x075, 0x00009, 0x00, "Anole L2 165 memory"}, 
-	{HPHW_MEMORY, 0x076, 0x00009, 0x00, "UL 1 way U160 512K/512K memory"}, 
-	{HPHW_MEMORY, 0x077, 0x00009, 0x00, "UL 2 way U160 512K/512K memory"}, 
-	{HPHW_MEMORY, 0x078, 0x00009, 0x00, "Kiji L2 132 memory"}, 
-	{HPHW_MEMORY, 0x079, 0x00009, 0x00, "UL 1 way U160 1M/1M memory"}, 
-	{HPHW_MEMORY, 0x07A, 0x00009, 0x00, "UL 2 way U160 1M/1M memory"}, 
-	{HPHW_MEMORY, 0x07B, 0x00009, 0x00, "UL 1 way U180 1M/1M memory"}, 
-	{HPHW_MEMORY, 0x07C, 0x00009, 0x00, "UL 2 way U180 1M/1M memory"}, 
-	{HPHW_MEMORY, 0x07D, 0x00009, 0x00, "UL 1 way U240 U+ 2M/2M memory"}, 
-	{HPHW_MEMORY, 0x07E, 0x00009, 0x00, "UL 2 way U240 U+ 2M/2M memory"}, 
-	{HPHW_MEMORY, 0x07F, 0x00009, 0x00, "UL L2 132 memory"}, 
-	{HPHW_MEMORY, 0x080, 0x00009, 0x00, "UL L2 160 memory"}, 
-	{HPHW_MEMORY, 0x081, 0x00009, 0x00, "Merlin Jr 132 memory"}, 
-	{HPHW_MEMORY, 0x082, 0x00009, 0x00, "FireHawk 200 Memory"}, 
-	{HPHW_MEMORY, 0x083, 0x00009, 0x00, "SummitHawk Memory"}, 
-	{HPHW_MEMORY, 0x084, 0x00009, 0x00, "Jade Upgrade Memory"}, 
-	{HPHW_MEMORY, 0x085, 0x00009, 0x00, "SPP2500 Memory"}, 
-	{HPHW_MEMORY, 0x086, 0x00009, 0x00, "AllegroHigh Memory"}, 
-	{HPHW_MEMORY, 0x087, 0x00009, 0x00, "AllegroLow Memory"}, 
-	{HPHW_MEMORY, 0x088, 0x00009, 0x00, "Forte 2w Memory"}, 
-	{HPHW_MEMORY, 0x089, 0x00009, 0x00, "Forte 4w Memory"}, 
-	{HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, 
-	{HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, 
-	{HPHW_MEMORY, 0x090, 0x00009, 0x00, "Prelude SMC Memory"}, 
-	{HPHW_MEMORY, 0x091, 0x00009, 0x00, "Lego 360 Memory"}, 
-	{HPHW_MEMORY, 0x7FF, 0x00009, 0x00, "NEC Aska memory"}, 
-	{HPHW_MEMORY, 0x800, 0x00009, 0x00, "Hitachi Tiny 64"}, 
-	{HPHW_MEMORY, 0x801, 0x00009, 0x00, "Hitachi Tiny 80"}, 
-	{HPHW_MEMORY, 0x8FF, 0x00009, 0x00, "Hitachi X memory"}, 
-	{HPHW_MEMORY, 0x091, 0x00009, 0x00, "M2250 Memory"}, 
-	{HPHW_MEMORY, 0x092, 0x00009, 0x00, "M2500 Memory"}, 
-	{HPHW_MEMORY, 0x093, 0x00009, 0x00, "Sonata 440 Memory"}, 
-	{HPHW_MEMORY, 0x094, 0x00009, 0x00, "Sonata 360 Memory"}, 
-	{HPHW_MEMORY, 0x095, 0x00009, 0x00, "Rhapsody 440 Memory"}, 
-	{HPHW_MEMORY, 0x096, 0x00009, 0x00, "Rhapsody 360 Memory"}, 
-	{HPHW_MEMORY, 0x097, 0x00009, 0x00, "Raven W 360 Memory"}, 
-	{HPHW_MEMORY, 0x098, 0x00009, 0x00, "Halfdome W 440 Memory"}, 
-	{HPHW_MEMORY, 0x099, 0x00009, 0x00, "Rhapsody DC- 440 Memory"}, 
-	{HPHW_MEMORY, 0x09A, 0x00009, 0x00, "Rhapsody DC- 360 Memory"}, 
-	{HPHW_MEMORY, 0x09B, 0x00009, 0x00, "Crescendo Memory"}, 
+	{HPHW_MEMORY, 0x066, 0x00009, 0x00, "715/160 L2 Upgrade"},
 	{HPHW_OTHER, 0x004, 0x00030, 0x00, "Master"}, 
 	{HPHW_OTHER, 0x004, 0x00034, 0x00, "Slave"}, 
 	{HPHW_OTHER, 0x004, 0x00038, 0x00, "EDU"}, 
 	{HPHW_OTHER, 0x004, 0x00049, 0x00, "LGB Control"}, 
-        {0, }			/* leave the last entry empty ! */
+	{HPHW_FAULTY, 0, }  /* Special Marker for last entry */
 };
 
 
@@ -1318,7 +1195,7 @@
 	unsigned short model;
 	unsigned short mask;
 	enum cpu_type cpu;
-} hp_cpu_type_mask_list[] = {
+} hp_cpu_type_mask_list[] __initdata = {
 
 	{ 0x0000, 0x0ff0, pcx    },  /* 0x0000 - 0x000f */
 	{ 0x0048, 0x0ff0, pcxl   },  /* 0x0040 - 0x004f */
@@ -1350,8 +1227,10 @@
 	{ 0x0592, 0x0fff, pcxt_  },  /* 0x0592 - 0x0592 */
 	{ 0x0593, 0x0fff, pcxu   },  /* 0x0593 - 0x0593 */
 	{ 0x0594, 0x0ffc, pcxu   },  /* 0x0594 - 0x0597 */
-	{ 0x0598, 0x0ffc, pcxu   },  /* 0x0598 - 0x059b */
-	{ 0x059c, 0x0ffe, pcxu_  },  /* 0x059c - 0x059d */
+	{ 0x0598, 0x0ffe, pcxu_  },  /* 0x0598 - 0x0599 */
+	{ 0x059a, 0x0ffe, pcxu   },  /* 0x059a - 0x059b */
+	{ 0x059c, 0x0fff, pcxu   },  /* 0x059c - 0x059c */
+	{ 0x059d, 0x0fff, pcxu_  },  /* 0x059d - 0x059d */
 	{ 0x059e, 0x0fff, pcxt_  },  /* 0x059e - 0x059e */
 	{ 0x059f, 0x0fff, pcxu   },  /* 0x059f - 0x059f */
 	{ 0x05a0, 0x0ffe, pcxt_  },  /* 0x05a0 - 0x05a1 */
@@ -1370,7 +1249,27 @@
 	{ 0x05ba, 0x0fff, pcxu_  },  /* 0x05ba - 0x05ba */
 	{ 0x05bb, 0x0fff, pcxw   },  /* 0x05bb - 0x05bb */
 	{ 0x05bc, 0x0ffc, pcxw   },  /* 0x05bc - 0x05bf */
-	{ 0x05c0, 0x0fc0, pcxw   },  /* 0x05c0 - 0x05ff */
+	{ 0x05c0, 0x0ffc, pcxw 	 },  /* 0x05c0 - 0x05c3 */
+	{ 0x05c4, 0x0ffe, pcxw 	 },  /* 0x05c4 - 0x05c5 */
+	{ 0x05c6, 0x0fff, pcxw 	 },  /* 0x05c6 - 0x05c6 */
+	{ 0x05c7, 0x0fff, pcxw_  },  /* 0x05c7 - 0x05c7 */
+	{ 0x05c8, 0x0ffc, pcxw 	 },  /* 0x05c8 - 0x05cb */
+	{ 0x05cc, 0x0ffe, pcxw 	 },  /* 0x05cc - 0x05cd */
+	{ 0x05ce, 0x0ffe, pcxw_  },  /* 0x05ce - 0x05cf */
+	{ 0x05d0, 0x0ffc, pcxw_  },  /* 0x05d0 - 0x05d3 */
+	{ 0x05d4, 0x0ffe, pcxw_  },  /* 0x05d4 - 0x05d5 */
+	{ 0x05d6, 0x0fff, pcxw 	 },  /* 0x05d6 - 0x05d6 */
+	{ 0x05d7, 0x0fff, pcxw_  },  /* 0x05d7 - 0x05d7 */
+	{ 0x05d8, 0x0ffc, pcxw_  },  /* 0x05d8 - 0x05db */
+	{ 0x05dc, 0x0ffe, pcxw2  },  /* 0x05dc - 0x05dd */
+	{ 0x05de, 0x0fff, pcxw_  },  /* 0x05de - 0x05de */
+	{ 0x05df, 0x0fff, pcxw2  },  /* 0x05df - 0x05df */
+	{ 0x05e0, 0x0ffc, pcxw2  },  /* 0x05e0 - 0x05e3 */
+	{ 0x05e4, 0x0fff, pcxw2  },  /* 0x05e4 - 0x05e4 */
+	{ 0x05e5, 0x0fff, pcxw_  },  /* 0x05e5 - 0x05e5 */
+	{ 0x05e6, 0x0ffe, pcxw2  },  /* 0x05e6 - 0x05e7 */
+	{ 0x05e8, 0x0ff8, pcxw2  },  /* 0x05e8 - 0x05ef */
+	{ 0x05f0, 0x0ff0, pcxw2  },  /* 0x05f0 - 0x05ff */
 	{ 0x0600, 0x0ff0, pcxl   },  /* 0x0600 - 0x060f */
 	{ 0x0610, 0x0ff0, pcxl   },  /* 0x0610 - 0x061f */
 	{ 0x0000, 0x0000, pcx    }	/* terminate table */
@@ -1386,36 +1285,51 @@
 	[pcxu]	{ "PA8000 (PCX-U)",	"2.0" },
 	[pcxu_]	{ "PA8200 (PCX-U+)",	"2.0" },
 	[pcxw]	{ "PA8500 (PCX-W)",	"2.0" },
-	[pcxw_]	{ "PA8600 (PCX-W+)",	"2.0" }
+	[pcxw_]	{ "PA8600 (PCX-W+)",	"2.0" },
+	[pcxw2]	{ "PA8700 (PCX-W2)",	"2.0" }
 };
 
-char *parisc_getHWtype(unsigned short hw_type)
-{
-	if (hw_type <= HPHW_CIO) {
-		return hw_type_name[hw_type];
-	} else {
-		return "Unknown Type";
-	}
-}
-
-char *parisc_getHWdescription(unsigned short hw_type, unsigned long hversion,
-		unsigned long sversion)
+const char * __init
+parisc_hardware_description(struct parisc_device_id *id)
 {
 	struct hp_hardware *listptr;
 	
-	for (listptr = hp_hardware_list; listptr->name; listptr++) {
-		if ((listptr->hw_type==hw_type) &&
-				(listptr->hversion==hversion) &&
-				(listptr->sversion==sversion)){
+	for (listptr = hp_hardware_list; listptr->hw_type != HPHW_FAULTY; listptr++) {
+		if ((listptr->hw_type == id->hw_type) &&
+				(listptr->hversion == id->hversion) &&
+				(listptr->sversion == id->sversion)){
 			return listptr->name;
 		}
 	}
+
+	/*
+	 * ok, the above hardware table isn't complete, and we haven't found
+	 * our device in this table. So let's now try to find a generic name
+	 * to describe the given hardware...
+	 */
+	switch (id->hw_type) {
+		case HPHW_NPROC:
+			return "Unknown machine";
+
+		case HPHW_A_DIRECT:
+			switch (id->sversion) {
+				case 0x0D: return "MUX port";
+				case 0x0E: return "RS-232 port";
+			}
+			break;
+			
+		case HPHW_MEMORY:
+			return "Memory";
+			
+	}
+	
 	return "unknown device";
 }
 
 
 /* Interpret hversion (ret[0]) from PDC_MODEL(4)/PDC_MODEL_INFO(0) */
-enum cpu_type parisc_get_cpu_type(unsigned long hversion)
+enum cpu_type __init
+parisc_get_cpu_type(unsigned long hversion)
 {
 	struct hp_cpu_type_mask *ptr;
 	unsigned short model = ((unsigned short) (hversion)) >> 4;
@@ -1424,23 +1338,8 @@
 		if (ptr->model == (model & ptr->mask))
 			return ptr->cpu;
 	}
-	panic("parisc_get_cpu_type() could not identify CPU type\n");
+	panic("could not identify CPU type\n");
 
 	return pcx;	/* not reached: */
 }
 
-
-struct hp_hardware *parisc_get_reference(unsigned short hw_type,
-		unsigned long hversion, unsigned long sversion)
-{
-	struct hp_hardware *listptr = hp_hardware_list;
-
-	for (listptr = hp_hardware_list; listptr->name; listptr++) {
-		if ((listptr->hw_type == hw_type) &&
-				(listptr->hversion == hversion) &&
-				(listptr->sversion == sversion)) {
-			return listptr;
-		}
-	}
-	return NULL;
-}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/head.S linux-2.4.20-pre2/arch/parisc/kernel/head.S
--- linux-2.4.20-pre1/arch/parisc/kernel/head.S	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/head.S	Mon Aug 12 16:34:14 2002
@@ -8,17 +8,14 @@
  * Copyright 1999 SuSE GmbH (Philipp Rumpf)
  * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
  *
- * Initial Version 04-23-1999 by Helge Deller (helge.deller@ruhr-uni-bochum.de)
+ * Initial Version 04-23-1999 by Helge Deller <deller@gmx.de>
  */
 
+#include <linux/autoconf.h>	/* for CONFIG_SMP */
 
 #include <asm/offset.h>
 #include <asm/psw.h>
 
-#define __ASSEMBLY__
-/*********
-#include <asm/pdc.h>
-*********/
 #include <asm/assembly.h>
 #include <asm/pgtable.h>
 
@@ -36,6 +33,15 @@
 	.export __setup_end
 __setup_end:
 
+	.data
+
+	.export boot_args
+boot_args:
+	.word 0 /* arg0 */
+	.word 0 /* arg1 */
+	.word 0 /* arg2 */
+	.word 0 /* arg3 */
+
 	.text
 	.align	4	
 	.import init_task_union,data
@@ -52,43 +58,129 @@
 	.callinfo
 
 	/* Make sure sr4-sr7 are set to zero for the kernel address space */
-
-	mtsp		%r0,%sr4
-	mtsp		%r0,%sr5
-	mtsp		%r0,%sr6
-	mtsp		%r0,%sr7
+	mtsp	%r0,%sr4
+	mtsp	%r0,%sr5
+	mtsp	%r0,%sr6
+	mtsp	%r0,%sr7
+
+	/* Clear BSS (shouldn't the boot loader do this?) */
+
+	.import _edata,data
+	.import _end,data
+
+	ldil            L%PA(_edata),%r3
+	ldo             R%PA(_edata)(%r3),%r3
+	ldil            L%PA(_end),%r4
+	ldo             R%PA(_end)(%r4),%r4
+$bss_loop:
+	cmpb,<<,n       %r3,%r4,$bss_loop
+	stb,ma          %r0,1(%r3)
+
+	/* Save away the arguments the boot loader passed in (32 bit args) */
+
+	ldil            L%PA(boot_args),%r1
+	ldo             R%PA(boot_args)(%r1),%r1
+	stw,ma          %arg0,4(%r1)
+	stw,ma          %arg1,4(%r1)
+	stw,ma          %arg2,4(%r1)
+	stw,ma          %arg3,4(%r1)
 
 	/* Initialize startup VM. Just map first 8 MB of memory */
-
 	ldil		L%PA(pg0),%r1
 	ldo		R%PA(pg0)(%r1),%r1
 	ldo		_PAGE_TABLE(%r1),%r3
+
 	ldil		L%PA(swapper_pg_dir),%r4
 	ldo		R%PA(swapper_pg_dir)(%r4),%r4
 	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
 	mtctl		%r4,%cr25	/* Initialize user root pointer */
-	stw		%r3,0xc00(%r4)	/* Hardwired 0xc0000000 kernel vaddr start */
+
+#if (__PAGE_OFFSET != 0x10000000UL)
+Error! Code below (the next two stw's) needs to be changed
+#endif
+
+	stw             %r3,0x100(%r4)  /* Hardwired 0x1... kernel Vaddr start*/
 	ldo		0x1000(%r3),%r3
-	stw		%r3,0xc04(%r4)
-	ldo		_PAGE_KERNEL(%r0),%r3 /* Hardwired 0x0 phys addr start */
+	stw             %r3,0x104(%r4)
+	ldo		_PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
 $pgt_fill_loop:
 	stwm		%r3,4(%r1)
 	ldo		0x1000(%r3),%r3
 	bb,>=		%r3,8,$pgt_fill_loop
 	nop
 
+
+	/* Load the return address...er...crash 'n burn */
+	copy		%r0,%r2
+
+	/* And the RFI Target address too */
+	ldil            L%start_kernel,%r11
+	ldo             R%start_kernel(%r11),%r11
+
+	/* And the initial task pointer */
+
+	ldil            L%init_task_union,%r6
+	ldo             R%init_task_union(%r6),%r6
+	mtctl           %r6,%cr30
+
+	/* And the stack pointer too */
+
+	ldo             TASK_SZ_ALGN(%r6),%sp
+
+	/* And the interrupt stack */
+
+	ldil            L%interrupt_stack,%r6
+	ldo             R%interrupt_stack(%r6),%r6
+	mtctl           %r6,%cr31
+
+#ifdef CONFIG_SMP
+	/* Set the smp rendevous address into page zero.
+	** It would be safer to do this in init_smp_config() but
+	** it's just way easier to deal with here because
+	** of 64-bit function ptrs and the address is local to this file.
+	*/
+	ldil		L%PA(smp_slave_stext),%r10
+	ldo		R%PA(smp_slave_stext)(%r10),%r10
+	stw		%r10,0x10(%r0)	/* MEM_RENDEZ */
+	stw		%r0,0x28(%r0)	/* MEM_RENDEZ_HI - assume addr < 4GB */
+
+	/* FALLTHROUGH */
+	.procend
+
+	/*
+	** Code Common to both Monarch and Slave processors.
+	** Entry:
+	**    %r11 must contain RFI target address.
+	**    %r25/%r26 args to pass to target function
+	**    %r2  in case rfi target decides it didn't like something
+	**
+	** Caller must init: SR4-7, %sp, %r10, %cr24/25, 
+	*/
+common_stext:
+	.proc
+	.callinfo
+#else
+	/* Clear PDC entry point - we won't use it */
+	stw		%r0,0x10(%r0)	/* MEM_RENDEZ */
+	stw		%r0,0x28(%r0)	/* MEM_RENDEZ_HI */
+#endif
+
+	/* PARANOID: clear user scratch/user space SR's */
+	mtsp	%r0,%sr0
+	mtsp	%r0,%sr1
+	mtsp	%r0,%sr2
+	mtsp	%r0,%sr3
+
+	/* Initialize Protection Registers */
+	mtctl	%r0,%cr8
+	mtctl	%r0,%cr9
+	mtctl	%r0,%cr12
+	mtctl	%r0,%cr13
+
 	/* Initialize the global data pointer */
 	ldil		L%$global$,%dp
 	ldo		R%$global$(%dp),%dp
-	
-	/* And the stack pointer, physical too */
-	ldil		L%init_task_union+TASK_SZ_ALGN,%sp
-	ldo		R%init_task_union+TASK_SZ_ALGN(%sp),%sp
-
-	/* we need this to take interruptions directly after the rfi below */
-	/* (which we need for PA2.0 boxes) */
-	mtctl		%r0, %cr30
-	
+
 	/*
 	 * Set up our interrupt table.  HPMCs might not work after this! 
 	 *
@@ -96,7 +188,6 @@
 	 * following short sequence of instructions can determine this
 	 * (without being illegal on a PA1.1 machine).
 	 */
-	
 	ldi		32,%r10
 	mtctl		%r10,%cr11
 	.level 2.0
@@ -114,30 +205,30 @@
 $install_iva:
 	mtctl		%r10,%cr14
 
-	/* Disable (most) interruptions */
-	mtsm		%r0			
-	
+	/* Disable Q bit so we can load the iia queue */
+	rsm            PSW_SM_Q,%r0
+
 	/* kernel PSW:
-	 *  - no interruptions except for HPMC and TOC (which are handled by PDC)
+	 *  - no interruptions except HPMC and TOC (which are handled by PDC)
 	 *  - Q bit set (IODC / PDC interruptions)
 	 *  - big-endian
 	 *  - virtually mapped
 	 */
-
 	ldil		L%KERNEL_PSW,%r10
 	ldo		R%KERNEL_PSW(%r10),%r10
 	mtctl		%r10,%ipsw
-	
-	/* Set the space pointers for the post-RFI world */
-	mtctl		%r0,%cr17		/* Clear two-level IIA Space Queue */
-	mtctl		%r0,%cr17		/*    effectively setting kernel space. */
-
-	/* And the return address(es) too */
-	ldil		L%start_parisc,%r10
-	ldo		R%start_parisc(%r10),%r10
-	mtctl		%r10,%cr18
-	ldo		4(%r10),%r10
-	mtctl		%r10,%cr18
+
+	/* Set the space pointers for the post-RFI world
+	** Clear the two-level IIA Space Queue, effectively setting
+	** Kernel space.
+	*/
+	mtctl		%r0,%cr17
+	mtctl		%r0,%cr17
+
+	/* Load RFI target into PC queue */
+	mtctl		%r11,%cr18
+	ldo		4(%r11),%r11
+	mtctl		%r11,%cr18
 
 	/* Jump to hyperspace */
 	rfi
@@ -145,6 +236,71 @@
 
 	.procend
 
+#ifdef CONFIG_SMP
+
+	.import smp_init_current_idle_task,data
+	.import	smp_callin,code
+
+smp_callin_rtn:
+        .proc
+	.callinfo
+	break	1,1		/*  Break if returned from start_secondary */
+	nop
+	nop
+        .procend
+
+/***************************************************************************
+*
+* smp_slave_stext is executed by all non-monarch Processors when the Monarch
+* pokes the slave CPUs in smp.c:smp_boot_cpus().
+*
+* Once here, registers values are initialized in order to branch to virtual
+* mode. Once all available/eligible CPUs are in virtual mode, all are
+* released and start out by executing their own idle task.
+*****************************************************************************/
+
+
+smp_slave_stext:
+        .proc
+	.callinfo
+
+	/*
+	** Initialize Space registers
+	*/
+	mtsp	   %r0,%sr4
+	mtsp	   %r0,%sr5
+	mtsp	   %r0,%sr6
+	mtsp	   %r0,%sr7
+
+	/*  Initialize the SP - monarch sets up smp_init_current_idle_task */
+	ldil		L%PA(smp_init_current_idle_task),%sp
+	ldo		R%PA(smp_init_current_idle_task)(%sp),%sp
+	ldw		0(%sp),%sp	/* load task address */
+	mtctl           %sp,%cr30       /* store in cr30 */
+	addil		L%TASK_SZ_ALGN,%sp	/* stack is above task */
+	ldo		R%TASK_SZ_ALGN(%r1),%sp
+
+	/* point CPU to kernel page tables */
+	ldil		L%PA(swapper_pg_dir),%r4
+	ldo		R%PA(swapper_pg_dir)(%r4),%r4
+	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
+	mtctl		%r4,%cr25	/* Initialize user root pointer */
+
+	/* Load RFI *return* address in case smp_callin bails */
+	ldil		L%smp_callin_rtn,%r2
+	ldo		R%smp_callin_rtn(%r2),%r2
+
+	/* Load RFI target address.  */
+	ldil		L%smp_callin,%r11
+	ldo		R%smp_callin(%r11),%r11
+	
+	/* ok...common code can handle the rest */
+	b		common_stext
+	nop
+
+	.procend
+#endif /* CONFIG_SMP */
+
 	.data
 
 	.align	4
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/head64.S linux-2.4.20-pre2/arch/parisc/kernel/head64.S
--- linux-2.4.20-pre1/arch/parisc/kernel/head64.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/head64.S	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,333 @@
+/*
+ *
+ * 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) 1999 by Helge Deller
+ * Copyright 1999 SuSE GmbH (Philipp Rumpf)
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ * Copyright 2000 Hewlett Packard (Paul Bame, bame@puffin.external.hp.com)
+ * Copyright (C) 2001 Grant Grundler (Hewlett Packard)
+ *
+ * Initial Version 04-23-1999 by Helge Deller <deller@gmx.de>
+ */
+
+
+#include <linux/autoconf.h>	/* for CONFIG_SMP */
+
+#include <asm/offset.h>
+#include <asm/psw.h>
+
+#include <asm/assembly.h>
+#include <asm/pgtable.h>
+#include <asm/pdc.h>		/* for PDC_PSW defines */
+
+
+	.level 2.0
+
+	.section	.initcall.init
+	.align		4
+	.export __initcall_start
+__initcall_start:
+	.export __initcall_end
+__initcall_end:
+	.export __setup_start
+__setup_start:
+	.export __setup_end
+__setup_end:
+
+	.data
+
+	.export boot_args
+boot_args:
+	.word 0 /* arg0 */
+	.word 0 /* arg1 */
+	.word 0 /* arg2 */
+	.word 0 /* arg3 */
+
+	.text
+	.align	4	
+
+	.export stext
+	.export _stext,data		/* Kernel want it this way! */
+_stext:
+stext:
+	.proc
+	.callinfo
+
+	/* Make sure sr4-sr7 are set to zero for the kernel address space */
+	mtsp	%r0,%sr4
+	mtsp	%r0,%sr5
+	mtsp	%r0,%sr6
+	mtsp	%r0,%sr7
+
+	/* Clear BSS (shouldn't the boot loader do this?) */
+
+	.import _edata,data
+	.import _end,data
+
+	ldil            L%PA(_edata),%r3
+	ldo             R%PA(_edata)(%r3),%r3
+	ldil            L%PA(_end),%r4
+	ldo             R%PA(_end)(%r4),%r4
+$bss_loop:
+	cmpb,<<,n       %r3,%r4,$bss_loop
+	stb,ma          %r0,1(%r3)
+
+	/* Save away the arguments the boot loader passed in (32 bit args) */
+
+	ldil            L%PA(boot_args),%r1
+	ldo             R%PA(boot_args)(%r1),%r1
+	stw,ma          %arg0,4(%r1)
+	stw,ma          %arg1,4(%r1)
+	stw,ma          %arg2,4(%r1)
+	stw,ma          %arg3,4(%r1)
+
+	/* Initialize startup VM. Just map first 8 MB of memory */
+
+	ldil		L%PA(pg0),%r1
+	ldo		R%PA(pg0)(%r1),%r1
+
+	ldil		L%PA(pmd0),%r5
+	ldo		R%PA(pmd0)(%r5),%r5
+	ldo		_PAGE_TABLE(%r5),%r3
+
+	ldil		L%PA(swapper_pg_dir),%r4
+	ldo		R%PA(swapper_pg_dir)(%r4),%r4
+
+	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
+	mtctl		%r4,%cr25	/* Initialize user root pointer */
+
+#if (__PAGE_OFFSET != 0x10000000UL)
+Error! Code below (the next five std's) needs to be changed
+#endif
+
+	std             %r3,0x00(%r4)   /* Hardwired 0x1... kernel Vaddr start*/
+
+	ldo		_PAGE_TABLE(%r1),%r3
+	std             %r3,0x400(%r5)  /* Hardwired 0x1... kernel Vaddr start*/
+	ldo		0x1000(%r3),%r3
+	std             %r3,0x408(%r5)
+	ldo		0x1000(%r3),%r3
+	std             %r3,0x410(%r5)
+	ldo		0x1000(%r3),%r3
+	std             %r3,0x418(%r5)
+
+	ldo		_PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
+$pgt_fill_loop:
+	std,ma		%r3,8(%r1)
+	ldo		0x1000(%r3),%r3
+	bb,>=		%r3,8,$pgt_fill_loop
+	nop
+
+	/* And the RFI Target address too */
+	load32          start_kernel, %r11
+
+	/* And the stack pointer too */
+	load32		PA(init_task_union+TASK_SZ_ALGN),%sp
+
+	/* And the initial task pointer */
+
+	load32          init_task_union,%r6
+	mtctl           %r6,%cr30
+
+	/* And the interrupt stack */
+
+	load32          interrupt_stack,%r6
+	mtctl           %r6,%cr31
+
+	/* Act like PDC just called us - that's how slave CPUs enter */
+#define MEM_PDC_LO 0x388
+#define MEM_PDC_HI 0x35C
+	ldw		MEM_PDC_LO(%r0),%r3
+	ldw		MEM_PDC_HI(%r0),%r6
+	depd		%r6, 31, 32, %r3	/* move to upper word */
+
+#ifdef CONFIG_SMP
+	/* Set the smp rendevous address into page zero.
+	** It would be safer to do this in init_smp_config() but
+	** it's just way easier to deal with here because
+	** of 64-bit function ptrs and the address is local to this file.
+	*/
+	ldil		L%PA(smp_slave_stext),%r10
+	ldo		R%PA(smp_slave_stext)(%r10),%r10
+	stw		%r10,0x10(%r0)	/* MEM_RENDEZ */
+	stw		%r0,0x28(%r0)	/* MEM_RENDEZ_HI - assume addr < 4GB */
+
+	/* FALLTHROUGH */
+	.procend
+
+	/*
+	** Code Common to both Monarch and Slave processors.
+	** Entry:
+	**    %r3	PDCE_PROC address
+	**    %r11	RFI target address.
+	**
+	** Caller must init: SR4-7, %sp, %r10, %cr24/25, 
+	*/
+common_stext:
+	.proc
+	.callinfo
+#else /* CONFIG_SMP */
+	/* Clear PDC's CPU handoff address - we won't use it */
+	stw		%r0,0x10(%r0)	/* MEM_RENDEZ */
+	stw		%r0,0x28(%r0)	/* MEM_RENDEZ_HI */
+#endif /* CONFIG_SMP */
+
+	/* Save the rfi target address */
+	std		%r11,  TASK_PT_GR11-TASK_SZ_ALGN(%sp)
+
+#ifndef CONFIG_PDC_NARROW
+	/* Switch to wide mode; Superdome doesn't support narrow PDC
+	** calls.
+	*/
+1:	mfia		%rp		/* clear upper part of pcoq */
+	ldo		2f-1b(%rp),%rp
+	depdi		0,31,32,%rp
+	bv		(%rp)
+	ssm		PSW_SM_W,%r0
+2:
+#endif /* CONFIG_PDC_NARROW */
+
+	/* Set Wide mode as the "Default" (eg for traps)
+	** First trap occurs *right* after (or part of) rfi for slave CPUs.
+	** Someday, palo might not do this for the Monarch either.
+	*/
+
+	ldo		PDC_PSW(%r0),%arg0		/* 21 */
+	ldo		PDC_PSW_SET_DEFAULTS(%r0),%arg1	/* 2 */
+	ldo		PDC_PSW_WIDE_BIT(%r0),%arg2	/* 2 */
+
+	load32		PA(stext_pdc_ret), %rp
+
+	bv		(%r3)
+	copy		%r0,%arg3
+
+stext_pdc_ret:
+	/* restore rfi target address*/
+	ldd		TASK_PT_GR11-TASK_SZ_ALGN(%sp), %r11
+
+	/* PARANOID: clear user scratch/user space SR's */
+	mtsp	%r0,%sr0
+	mtsp	%r0,%sr1
+	mtsp	%r0,%sr2
+	mtsp	%r0,%sr3
+
+	/* Initialize Protection Registers */
+	mtctl	%r0,%cr8
+	mtctl	%r0,%cr9
+	mtctl	%r0,%cr12
+	mtctl	%r0,%cr13
+
+	/* Prepare to RFI! Man all the cannons! */
+	tovirt_r1       %sp
+
+	/* Initialize the global data pointer */
+	load32		__gp,%dp
+
+	/* Set up our interrupt table.  HPMCs might not work after this! */
+	ldil		L%PA(fault_vector_20),%r10
+	ldo		R%PA(fault_vector_20)(%r10),%r10
+	mtctl		%r10,%cr14
+
+	b		aligned_rfi
+	nop
+
+	/* the magic spell */
+	.align          256
+aligned_rfi:
+	ssm		0,0
+	nop		/* 1 */
+	nop		/* 2 */
+	nop		/* 3 */
+	nop		/* 4 */
+	nop		/* 5 */
+	nop		/* 6 */
+	nop		/* 7 */
+	nop		/* 8 */
+
+	/* turn off troublesome PSW bits */
+	rsm		PSW_Q+PSW_I+PSW_D+PSW_P+PSW_R, %r0
+
+	/* kernel PSW:
+	 *  - no interruptions except HPMC and TOC (which are handled by PDC)
+	 *  - Q bit set (IODC / PDC interruptions)
+	 *  - big-endian
+	 *  - virtually mapped
+	 */
+	load32		KERNEL_PSW,%r10
+	mtctl		%r10,%ipsw
+
+	/* Set the space pointers for the post-RFI world
+	** Clear the two-level IIA Space Queue, effectively setting
+	** Kernel space.
+	*/
+	mtctl		%r0,%cr17
+	mtctl		%r0,%cr17
+
+	/* Load RFI target into PC queue */
+	mtctl		%r11,%cr18
+	ldo		4(%r11),%r11
+	mtctl		%r11,%cr18
+
+	/* Jump to hyperspace */
+	rfi
+	nop
+
+	.procend
+
+
+#ifdef CONFIG_SMP
+
+	.import smp_init_current_idle_task,data
+	.import	smp_callin,code
+
+/***************************************************************************
+*
+* smp_slave_stext is executed by all non-monarch Processors when the Monarch
+* pokes the slave CPUs in smp.c:smp_boot_cpus().
+*
+* Once here, registers values are initialized in order to branch to virtual
+* mode. Once all available/eligible CPUs are in virtual mode, all are
+* released and start out by executing their own idle task.
+*****************************************************************************/
+
+
+smp_slave_stext:
+        .proc
+	.callinfo
+
+	/*
+	** Initialize Space registers
+	*/
+	mtsp	   %r0,%sr4
+	mtsp	   %r0,%sr5
+	mtsp	   %r0,%sr6
+	mtsp	   %r0,%sr7
+
+	/*  Initialize the SP - monarch sets up smp_init_current_idle_task */
+	load32		PA(smp_init_current_idle_task),%sp
+	ldd		0(%sp),%sp	/* load task address */
+	mtctl           %sp,%cr30       /* store in cr30 */
+	ldo             TASK_SZ_ALGN(%sp),%sp
+	tophys_r1       %sp
+
+	/* point CPU to kernel page tables */
+	load32		PA(swapper_pg_dir),%r4
+	mtctl		%r4,%cr24	/* Initialize kernel root pointer */
+	mtctl		%r4,%cr25	/* Initialize user root pointer */
+
+	/* Setup PDCE_PROC entry */
+	copy		%arg0,%r3
+
+	/* Load RFI target address.  */
+	load32		smp_callin, %r11
+	
+	/* ok...common code can handle the rest */
+	b		common_stext
+	nop
+
+	.procend
+#endif /* CONFIG_SMP */
+
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/hpmc.S linux-2.4.20-pre2/arch/parisc/kernel/hpmc.S
--- linux-2.4.20-pre1/arch/parisc/kernel/hpmc.S	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/hpmc.S	Mon Aug 12 16:34:14 2002
@@ -43,7 +43,6 @@
 	.level		1.1
 	.data
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/pdc.h>
 
@@ -262,12 +261,10 @@
 	mtsp	%r0, %sr6
 	mtsp	%r0, %sr7
 
-	tovirt  %r30        /* make sp virtual */
+	tovirt_r1 %r30      /* make sp virtual */
 
 	rsm 8,%r0           /* Clear Q bit */
-	ldi     1,%r1
-	mtctl   %r1,%cr29   /* Set trap code to "1" for HPMC */
-	mtctl   %r0,%cr30   /* Force interruptions to use hpmc stack */
+	ldi     1,%r8       /* Set trap code to "1" for HPMC */
 	ldil    L%PA(intr_save), %r1
 	ldo     R%PA(intr_save)(%r1), %r1
 	be      0(%sr7,%r1)
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/init_task.c linux-2.4.20-pre2/arch/parisc/kernel/init_task.c
--- linux-2.4.20-pre1/arch/parisc/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/init_task.c	Mon Aug 12 16:34:14 2002
@@ -18,10 +18,11 @@
  * way process stacks are handled. This is done by having a special
  * "init_task" linker map entry..
  */
+unsigned char interrupt_stack[ISTACK_SIZE] __attribute__ ((section("init_istack"), aligned(4096)));
 union task_union init_task_union 
 	__attribute__((section("init_task"), aligned(4096))) = { INIT_TASK(init_task_union.task) };
 
-unsigned long swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(4096))) = { 0, };
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(4096))) = { {0}, };
 #ifdef __LP64__
 unsigned long pmd0[PTRS_PER_PMD] __attribute__ ((aligned(4096))) = { 0, };
 #endif
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/inventory.c linux-2.4.20-pre2/arch/parisc/kernel/inventory.c
--- linux-2.4.20-pre1/arch/parisc/kernel/inventory.c	Wed Dec  6 11:46:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/inventory.c	Mon Aug 12 16:34:14 2002
@@ -1,40 +1,157 @@
-
-/* Copyright (c) 1999 The Puffin Group */
-/* Written by David Kennedy and Alex deVries */
+/*
+ * inventory.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.
+ *
+ * Copyright (c) 1999 The Puffin Group (David Kennedy and Alex deVries)
+ * Copyright (c) 2001 Matthew Wilcox for Hewlett-Packard
+ *
+ * These are the routines to discover what hardware exists in this box.
+ * This task is complicated by there being 3 different ways of
+ * performing an inventory, depending largely on the age of the box.
+ * The recommended way to do this is to check to see whether the machine
+ * is a `Snake' first, then try System Map, then try PAT.  We try System
+ * Map before checking for a Snake -- this probably doesn't cause any
+ * problems, but...
+ */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/pdc.h>
+#include <asm/processor.h>
+#include <asm/page.h>
 
 /*
 ** Debug options
-**    DEBUG_PAT	Dump details which PDC PAT provides about ranges/devices.
+** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices.
 */
 #undef DEBUG_PAT
 
-extern char *parisc_getHWtype(unsigned short hw_type);
+int pdc_type = PDC_TYPE_ILLEGAL;
+
+void __init setup_pdc(void)
+{
+	long status;
+	unsigned int bus_id;
+	struct pdc_system_map_mod_info module_result;
+	struct pdc_module_path module_path;
+	struct pdc_model model;
+#ifdef __LP64__
+	struct pdc_pat_cell_num cell_info;
+#endif
 
-extern struct hp_device * register_module(void *hpa);
-extern void print_devices(char * buf);
+	/* Determine the pdc "type" used on this machine */
 
+	printk(KERN_INFO "Determining PDC firmware type: ");
 
-int pdc_hpa_processor(void *address);
+	status = pdc_system_map_find_mods(&module_result, &module_path, 0);
+	if (status == PDC_OK) {
+		pdc_type = PDC_TYPE_SYSTEM_MAP;
+		printk("System Map.\n");
+		return;
+	}
 
-#ifndef __LP64__ 
-static	u8 iodc_data[32] __attribute__ ((aligned (64)));
-static	struct pdc_model model __attribute__ ((aligned (8)));
+	/*
+	 * If the machine doesn't support PDC_SYSTEM_MAP then either it
+	 * is a pdc pat box, or it is an older box. All 64 bit capable
+	 * machines are either pdc pat boxes or they support PDC_SYSTEM_MAP.
+	 */
+
+	/*
+	 * TODO: We should test for 64 bit capability and give a
+	 * clearer message.
+	 */
+
+#ifdef __LP64__
+	status = pdc_pat_cell_get_number(&cell_info);
+	if (status == PDC_OK) {
+		pdc_type = PDC_TYPE_PAT;
+		printk("64 bit PAT.\n");
+		return;
+	}
 #endif
-static	unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
-static	struct pdc_hpa processor_hpa __attribute__ ((aligned (8)));
-static	struct pdc_system_map module_result __attribute__ ((aligned (8)));
-static	struct pdc_module_path module_path __attribute__ ((aligned (8)));
+
+	/* Check the CPU's bus ID.  There's probably a better test.  */
+
+	status = pdc_model_info(&model);
+
+	bus_id = (model.hversion >> (4 + 7)) & 0x1f;
+
+	switch (bus_id) {
+	case 0x4:		/* 720, 730, 750, 735, 755 */
+	case 0x6:		/* 705, 710 */
+	case 0x7:		/* 715, 725 */
+	case 0x8:		/* 745, 747, 742 */
+	case 0xA:		/* 712 and similiar */
+	case 0xC:		/* 715/64, at least */
+
+		pdc_type = PDC_TYPE_SNAKE;
+		printk("Snake.\n");
+		return;
+
+	default:		/* Everything else */
+
+		printk("Unsupported.\n");
+		panic("If this is a 64-bit machine, please try a 64-bit kernel.\n");
+	}
+}
+
+#define PDC_PAGE_ADJ_SHIFT (PAGE_SHIFT - 12) /* pdc pages are always 4k */
+
+static void __init
+set_pmem_entry(physmem_range_t *pmem_ptr, unsigned long start,
+	       unsigned long pages4k)
+{
+	/* Rather than aligning and potentially throwing away
+	 * memory, we'll assume that any ranges are already
+	 * nicely aligned with any reasonable page size, and
+	 * panic if they are not (it's more likely that the
+	 * pdc info is bad in this case).
+	 */
+
+	if (   ((start & (PAGE_SIZE - 1)) != 0)
+	    || ((pages4k & ((1UL << PDC_PAGE_ADJ_SHIFT) - 1)) != 0) ) {
+
+		panic("Memory range doesn't align with page size!\n");
+	}
+
+	pmem_ptr->start_pfn = (start >> PAGE_SHIFT);
+	pmem_ptr->pages = (pages4k >> PDC_PAGE_ADJ_SHIFT);
+}
+
+static void __init pagezero_memconfig(void)
+{
+	unsigned long npages;
+
+	/* Use the 32 bit information from page zero to create a single
+	 * entry in the pmem_ranges[] table.
+	 *
+	 * We currently don't support machines with contiguous memory
+	 * >= 4 Gb, who report that memory using 64 bit only fields
+	 * on page zero. It's not worth doing until it can be tested,
+	 * and it is not clear we can support those machines for other
+	 * reasons.
+	 *
+	 * If that support is done in the future, this is where it
+	 * should be done.
+	 */
+
+	npages = (PAGE_ALIGN(PAGE0->imm_max_mem) >> PAGE_SHIFT);
+	set_pmem_entry(pmem_ranges,0UL,npages);
+	npmem_ranges = 1;
+}
 
 #ifdef __LP64__
-#include <asm/pdcpat.h>
 
-int pdc_pat = 0;
+/* All of the PDC PAT specific code is 64-bit only */
 
 /*
 **  The module object is filled via PDC_PAT_CELL[Return Cell Module].
@@ -47,30 +164,37 @@
 **
 */
 
-static int
-pat_query_module( ulong pcell_loc, ulong mod_index)
+static int __init 
+pat_query_module(ulong pcell_loc, ulong mod_index)
 {
-	extern int num_devices;
-	extern struct hp_device devices[];
-
 	pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
-        struct hp_device * dev = &devices[num_devices];
-	uint64_t temp;             /* 64-bit scratch value */
-	long status;               /* PDC return value status */
+	pdc_pat_cell_mod_maddr_block_t io_pdc_cell;
+	unsigned long bytecnt;
+	unsigned long temp;	/* 64-bit scratch value */
+	long status;		/* PDC return value status */
+	struct parisc_device *dev;
 
 	/* return cell module (PA or Processor view) */
-	status = pdc_pat_cell_module(& pdc_result, pcell_loc, mod_index,
-		PA_VIEW, & pa_pdc_cell);
+	status = pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+				     PA_VIEW, &pa_pdc_cell);
 
-	if (status != PDC_RET_OK) {
+	if (status != PDC_OK) {
 		/* no more cell modules or error */
 		return status;
 	}
 
+	temp = pa_pdc_cell.cba;
+	dev = alloc_pa_dev(PAT_GET_CBA(temp), &pa_pdc_cell.mod_path);
+	if (!dev) {
+		return PDC_NE_MOD;
+	}
+
+	/* alloc_pa_dev sets dev->hpa */
+
 	/*
-	** save parameters in the hp_device
+	** save parameters in the parisc_device
 	** (The idea being the device driver will call pdc_pat_cell_module()
-	** and store the results in it's own data structure.)
+	** and store the results in its own data structure.)
 	*/
 	dev->pcell_loc = pcell_loc;
 	dev->mod_index = mod_index;
@@ -79,319 +203,410 @@
 	/* REVISIT: who is the consumer of this? not sure yet... */
 	dev->mod_info = pa_pdc_cell.mod_info;	/* pass to PAT_GET_ENTITY() */
 	dev->pmod_loc = pa_pdc_cell.mod_location;
-	dev->mod_path = pa_pdc_cell.mod_path;
 
-	temp = pa_pdc_cell.cba;
-	register_module((void *) PAT_GET_CBA(temp));	/* fills in dev->hpa */
+	register_parisc_device(dev);	/* advertise device */
 
 #ifdef DEBUG_PAT
 	/* dump what we see so far... */
 	switch (PAT_GET_ENTITY(dev->mod_info)) {
-		ulong i;
+		unsigned long i;
 
 	case PAT_ENTITY_PROC:
-		printk ("PAT_ENTITY_PROC: id_eid 0x%lx\n", pa_pdc_cell.mod[0]);
+		printk(KERN_DEBUG "PAT_ENTITY_PROC: id_eid 0x%lx\n",
+			pa_pdc_cell.mod[0]);
 		break;
 
 	case PAT_ENTITY_MEM:
-		printk ("PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
-			pa_pdc_cell.mod[0],
-			pa_pdc_cell.mod[1],
+		printk(KERN_DEBUG 
+			"PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
+			pa_pdc_cell.mod[0], pa_pdc_cell.mod[1], 
 			pa_pdc_cell.mod[2]);
 		break;
 	case PAT_ENTITY_CA:
-		printk ("PAT_ENTITY_CA: %ld\n",pcell_loc);
+		printk(KERN_DEBUG "PAT_ENTITY_CA: %ld\n", pcell_loc);
 		break;
 
 	case PAT_ENTITY_PBC:
-		printk ("PAT_ENTITY_PBC: ");
+		printk(KERN_DEBUG "PAT_ENTITY_PBC: ");
 		goto print_ranges;
 
 	case PAT_ENTITY_SBA:
-		printk ("PAT_ENTITY_SBA: ");
+		printk(KERN_DEBUG "PAT_ENTITY_SBA: ");
 		goto print_ranges;
 
 	case PAT_ENTITY_LBA:
-		printk ("PAT_ENTITY_LBA: ");
+		printk(KERN_DEBUG "PAT_ENTITY_LBA: ");
 
-print_ranges:
-		printk ("ranges %ld\n", pa_pdc_cell.mod[1]);
+ print_ranges:
+		pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+				    IO_VIEW, &io_pdc_cell);
+		printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell.mod[1]);
 		for (i = 0; i < pa_pdc_cell.mod[1]; i++) {
-			printk ("	%ld: 0x%016lx 0x%016lx 0x%016lx\n", i,
-				pa_pdc_cell.mod[2+i*3],	/* type */
-				pa_pdc_cell.mod[3+i*3],	/* start */
-				pa_pdc_cell.mod[4+i*3]);	/* finish (ie end) */
+			printk(KERN_DEBUG 
+				"  PA_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
+				i, pa_pdc_cell.mod[2 + i * 3],	/* type */
+				pa_pdc_cell.mod[3 + i * 3],	/* start */
+				pa_pdc_cell.mod[4 + i * 3]);	/* finish (ie end) */
+			printk(KERN_DEBUG 
+				"  IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
+				i, io_pdc_cell.mod[2 + i * 3],	/* type */
+				io_pdc_cell.mod[3 + i * 3],	/* start */
+				io_pdc_cell.mod[4 + i * 3]);	/* finish (ie end) */
 		}
-		printk("\n");
+		printk(KERN_DEBUG "\n");
 		break;
 	}
 #endif /* DEBUG_PAT */
-	return PDC_RET_OK;
+	return PDC_OK;
 }
 
 
-static int do_pat_inventory(void)
-{
-	ulong mod_index=0;
-	int status;
-	ulong cell_num;
-	ulong pcell_loc;
+/* pat pdc can return information about a variety of different
+ * types of memory (e.g. firmware,i/o, etc) but we only care about
+ * the usable physical ram right now. Since the firmware specific
+ * information is allocated on the stack, we'll be generous, in
+ * case there is a lot of other information we don't care about.
+ */
 
-	pdc_pat = (pdc_pat_cell_get_number(&pdc_result) == PDC_OK);
-	if (!pdc_pat)
-	{
-		return 0;
-	}
-
-	cell_num = pdc_result[0];	/* Cell number call was made */
-
-	/* As of PDC PAT ARS 2.5, ret[1] is NOT architected! */
-	pcell_loc = pdc_result[1];	/* Physical location of the cell */
-
-#ifdef DEBUG_PAT
-	printk("CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_num, pcell_loc);
-#endif
-
-        status = pdc_pat_cell_num_to_loc(&pdc_result, cell_num);
-        if (status == PDC_BAD_OPTION)
-	{
-		/* Prelude (and it's successors: Lclass, A400/500) only
-		** implement PDC_PAT_CELL sub-options 0 and 2.
-		** "Home cook'n is best anyhow!"
-		*/
-	} else if (PDC_OK == status) {
-		/* so far only Halfdome supports this */
-		pcell_loc = pdc_result[0];
-	} else {
-		panic("WTF? CELL_GET_NUMBER give me invalid cell number?");
-	}
-
-	while (PDC_RET_OK == pat_query_module(pcell_loc, mod_index))
-	{
-		mod_index++;
-	}
-
-	return mod_index;
-}
-#endif /* __LP64__ */
+#define PAT_MAX_RANGES (4 * MAX_PHYSMEM_RANGES)
 
-static int do_newer_workstation_inventory(void)
+static void __init pat_memconfig(void)
 {
+	unsigned long actual_len;
+	struct pdc_pat_pd_addr_map_entry mem_table[PAT_MAX_RANGES+1];
+	struct pdc_pat_pd_addr_map_entry *mtbl_ptr;
+	physmem_range_t *pmem_ptr;
 	long status;
-	int i, num = 0;
+	int entries;
+	unsigned long length;
+	int i;
+
+	length = (PAT_MAX_RANGES + 1) * sizeof(struct pdc_pat_pd_addr_map_entry);
+
+	status = pdc_pat_pd_get_addr_map(&actual_len, mem_table, length, 0L);
+
+	if ((status != PDC_OK)
+	    || ((actual_len % sizeof(struct pdc_pat_pd_addr_map_entry)) != 0)) {
+
+		/* The above pdc call shouldn't fail, but, just in
+		 * case, just use the PAGE0 info.
+		 */
+
+		printk("\n\n\n");
+		printk(KERN_WARNING "WARNING! Could not get full memory configuration. "
+			"All memory may not be used!\n\n\n");
+		pagezero_memconfig();
+		return;
+	}
 
-	/* So the idea here is to simply try one SYSTEM_MAP call.  If 
-	   that one works, great, otherwise do it another way */
+	entries = actual_len / sizeof(struct pdc_pat_pd_addr_map_entry);
 
-	status = pdc_system_map_find_mods(&module_result,&module_path,0);
+	if (entries > PAT_MAX_RANGES) {
+		printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+		printk(KERN_WARNING "Some memory may not be used!\n");
+	}
 
-	if (status == PDC_RET_OK) {
-		/* This is for newer non-PDC-PAT boxes */
+	/* Copy information into the firmware independent pmem_ranges
+	 * array, skipping types we don't care about. Notice we said
+	 * "may" above. We'll use all the entries that were returned.
+	 */
+
+	npmem_ranges = 0;
+	mtbl_ptr = mem_table;
+	pmem_ptr = pmem_ranges; /* Global firmware independent table */
+	for (i = 0; i < entries; i++,mtbl_ptr++) {
+		if (   (mtbl_ptr->entry_type != PAT_MEMORY_DESCRIPTOR)
+		    || (mtbl_ptr->memory_type != PAT_MEMTYPE_MEMORY)
+		    || (mtbl_ptr->pages == 0)
+		    || (   (mtbl_ptr->memory_usage != PAT_MEMUSE_GENERAL)
+			&& (mtbl_ptr->memory_usage != PAT_MEMUSE_GI)
+			&& (mtbl_ptr->memory_usage != PAT_MEMUSE_GNI) ) ) {
 
-		printk("a newer box...\n");
-		for(i=0, status=PDC_RET_OK; status != PDC_RET_NE_PROC && 
-			status != PDC_RET_NE_MOD ;i++) {
+			continue;
+		}
 
-			status = pdc_system_map_find_mods(&module_result,&module_path,i);
-			if (status == PDC_RET_OK) {
-				num++;
-				register_module(module_result.mod_addr);
-			}
+		if (npmem_ranges == MAX_PHYSMEM_RANGES) {
+			printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+			printk(KERN_WARNING "Some memory will not be used!\n");
+			break;
 		}
-	}
 
-	return (num > 0);
+		set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
+		npmem_ranges++;
+	}
 }
 
-#ifndef __LP64__
-static	struct  pdc_memory_map r_addr __attribute__ ((aligned (8)));
-
-static int really_do_oldhw_inventory(void)
+static int __init pat_inventory(void)
 {
-	int i, mod, num = 0;
 	int status;
-	unsigned int hw_type;
-	unsigned int func;
+	ulong mod_index = 0;
+	struct pdc_pat_cell_num cell_info;
 
-	/* This is undocumented at the time of writing, but basically 
-	   we're setting up mod_path so that bc[0..4]=0xff, and step
-	   through mod to get the "Path Structure for GSC Modules".  If
-	   it works, use the returned HPA and determine the hardware type.  */
+	/*
+	** Note:  Prelude (and it's successors: Lclass, A400/500) only
+	**        implement PDC_PAT_CELL sub-options 0 and 2.
+	*/
+	status = pdc_pat_cell_get_number(&cell_info);
+	if (status != PDC_OK) {
+		return 0;
+	}
 
-	for (i=0;i<6;i++) module_path.bc[i]=0xff;
+#ifdef DEBUG_PAT
+	printk(KERN_DEBUG "CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_info.cell_num, 
+	       cell_info.cell_loc);
+#endif
 
-	for (mod=0;mod<16;mod++) {
-		char *stype = NULL;
+	while (PDC_OK == pat_query_module(cell_info.cell_loc, mod_index)) {
+		mod_index++;
+	}
 
-		module_path.mod=mod;
-		status = pdc_mem_map_hpa(&r_addr, &module_path);
-		if (status!=PDC_RET_OK) continue;
-	
-		status = pdc_iodc_read(&pdc_result,(void *) r_addr.hpa,
-			0, &iodc_data,32 );
-		if (status!=PDC_RET_OK) continue;
-		hw_type = iodc_data[3]&0x1f;
+	return mod_index;
+}
 
-		switch (hw_type)
-		{
-		case HPHW_NPROC:	/* 0 */
-			stype="Processor"; break;
+/* We only look for extended memory ranges on a 64 bit capable box */
+static void __init sprockets_memconfig(void)
+{
+	struct pdc_memory_table_raddr r_addr;
+	struct pdc_memory_table mem_table[MAX_PHYSMEM_RANGES];
+	struct pdc_memory_table *mtbl_ptr;
+	physmem_range_t *pmem_ptr;
+	long status;
+	int entries;
+	int i;
 
-		case HPHW_MEMORY:	/* 1 */
-			stype="Memory"; break;
+	status = pdc_mem_mem_table(&r_addr,mem_table,
+				(unsigned long)MAX_PHYSMEM_RANGES);
 
-		case HPHW_B_DMA:	/* 2 */
-			stype="Type B DMA"; break;
+	if (status != PDC_OK) {
 
-		case HPHW_A_DMA:	/* 4 */
-			stype="Type A DMA"; break;
+		/* The above pdc call only works on boxes with sprockets
+		 * firmware (newer B,C,J class). Other non PAT PDC machines
+		 * do support more than 3.75 Gb of memory, but we don't
+		 * support them yet.
+		 */
 
-		case HPHW_A_DIRECT:	/* 5 */
-			stype="Type A Direct"; break;
+		pagezero_memconfig();
+		return;
+	}
+
+	if (r_addr.entries_total > MAX_PHYSMEM_RANGES) {
+		printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+		printk(KERN_WARNING "Some memory will not be used!\n");
+	}
 
-		case HPHW_BCPORT:	/* 7 */
-			stype="Bus Converter Port"; break;
+	entries = (int)r_addr.entries_returned;
 
-		case HPHW_CONSOLE:	/* 9 */
-			stype="Console"; break;
+	npmem_ranges = 0;
+	mtbl_ptr = mem_table;
+	pmem_ptr = pmem_ranges; /* Global firmware independent table */
+	for (i = 0; i < entries; i++,mtbl_ptr++) {
+		set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
+		npmem_ranges++;
+	}
+}
 
-		case HPHW_FIO:		/* 10 - Graphics */
-			stype="Foreign I/O (Graphics)"; break;
+#else   /* !__LP64__ */
 
-		case HPHW_BA:		/* 11 - Bus Adapter */
-			stype="Bus Adapter"; break;
+#define pat_inventory() do { } while (0)
+#define pat_memconfig() do { } while (0)
+#define sprockets_memconfig() pagezero_memconfig()
 
-		case HPHW_IOA:		/* 12 */
-			stype="I/O Adapter"; break;
+#endif	/* !__LP64__ */
 
-		case HPHW_BRIDGE:	/* 13 */
-			stype="Bridge"; break;
 
-		case HPHW_FABRIC:	/* 14 */
-			stype="Fabric"; break;
+#ifndef CONFIG_PA20
 
-		case HPHW_FAULTY:	/* 31 */
-			stype="Faulty HW"; break;
+/* Code to support Snake machines (7[2350], 7[235]5, 715/Scorpio) */
 
-		case HPHW_OTHER:	/* 42 */
-		default:	
-			printk("Don't know this hw_type: %d\n", hw_type);
-			break;
-		}
+static struct parisc_device * __init
+legacy_create_device(struct pdc_memory_map *r_addr,
+		struct pdc_module_path *module_path)
+{
+	struct parisc_device *dev;
+	int status = pdc_mem_map_hpa(r_addr, module_path);
+	if (status != PDC_OK)
+		return NULL;
+
+	dev = alloc_pa_dev(r_addr->hpa, &module_path->path);
+	if (dev == NULL)
+		return NULL;
 
-		// This is kluged. But don't want to replicate code for
-		// most of the above cases.
-		if (stype) {
-#ifdef DBG_PDC_QUERY
-			// parisc/kernel/drivers.c
-			extern int num_devices; 
-			extern struct hp_device devices[];
-			struct hp_hardware *h;
-#endif
+	register_parisc_device(dev);
+	return dev;
+}
 
-			status = pdc_mem_map_hpa(&r_addr, &module_path);
-			if (status==PDC_RET_OK && register_module((void *) r_addr.hpa) != NULL)
-					num++;
-
-
-		    if (hw_type == HPHW_BA) {
-			/* Now, we're checking for devices for each
-			   module.  I seem to think that the
-			   modules in question are Lasi (2), 2nd Lasi (6)
-			   Wax (5).  To do this, set bc[5]=0, and set
-			   bc[4] to the module, and step through the
-			   functions. */
-
-			for (i=0;i<4;i++) module_path.bc[i]=0xff;
-			module_path.bc[4]=mod;
-			for (func=0;func<16;func++) {
-				module_path.mod = func;
-				module_path.bc[5]=0;
-				status = pdc_mem_map_hpa(&r_addr, &module_path);
-				if (status!=PDC_RET_OK) continue;
-				if (register_module((void *) r_addr.hpa) != NULL) 
-					num++;
-			}
+/**
+ * snake_inventory
+ *
+ * Before PDC_SYSTEM_MAP was invented, the PDC_MEM_MAP call was used.
+ * To use it, we initialise the mod_path.bc to 0xff and try all values of
+ * mod to get the HPA for the top-level devices.  Bus adapters may have
+ * sub-devices which are discovered by setting bc[5] to 0 and bc[4] to the
+ * module, then trying all possible functions.
+ */
+static void __init snake_inventory(void)
+{
+	int mod;
+	for (mod = 0; mod < 16; mod++) {
+		struct parisc_device *dev;
+		struct pdc_module_path module_path;
+		struct pdc_memory_map r_addr;
+		unsigned int func;
+
+		memset(module_path.path.bc, 0xff, 6);
+		module_path.path.mod = mod;
+		dev = legacy_create_device(&r_addr, &module_path);
+		if ((!dev) || (dev->id.hw_type != HPHW_BA))
+			continue;
+
+		memset(module_path.path.bc, 0xff, 4);
+		module_path.path.bc[4] = mod;
+
+		for (func = 0; func < 16; func++) {
+			module_path.path.bc[5] = 0;
+			module_path.path.mod = func;
+			legacy_create_device(&r_addr, &module_path);
 		}
-		// reset module_path.bc[]
-		for (i=0;i<6;i++) module_path.bc[i]=0xff;
+	}
+}
 
+#else /* CONFIG_PA20 */
+#define snake_inventory() do { } while (0)
+#endif  /* CONFIG_PA20 */
+
+/* Common 32/64 bit based code goes here */
+
+/**
+ * add_system_map_addresses - Add additional addresses to the parisc device.
+ * @dev: The parisc device.
+ * @num_addrs: Then number of addresses to add;
+ * @module_instance: The system_map module instance.
+ *
+ * This function adds any additional addresses reported by the system_map
+ * firmware to the parisc device.
+ */
+static void __init
+add_system_map_addresses(struct parisc_device *dev, int num_addrs, 
+			 int module_instance)
+{
+	int i;
+	long status;
+	struct pdc_system_map_addr_info addr_result;
 
-#ifdef DBG_PDC_QUERY
-//
-// Let print_devices() dump everything which is registered.
-//
-			h = devices[num_devices-1].reference;
+	dev->addr = kmalloc(num_addrs * sizeof(unsigned long), GFP_KERNEL);
+	if(!dev->addr) {
+		printk(KERN_ERR "%s %s(): memory allocation failure\n",
+		       __FILE__, __FUNCTION__);
+		return;
+	}
 
-			if (h) stype = h->name;
-			printk("Found %s at %d\n", stype, module_path.mod);
-#endif
+	for(i = 1; i <= num_addrs; ++i) {
+		status = pdc_system_map_find_addrs(&addr_result, 
+						   module_instance, i);
+		if(PDC_OK == status) {
+			dev->addr[dev->num_addrs] = (unsigned long)addr_result.mod_addr;
+			dev->num_addrs++;
+		} else {
+			printk(KERN_WARNING 
+			       "Bad PDC_FIND_ADDRESS status return (%ld) for index %d\n",
+			       status, i);
 		}
 	}
-	return num;
 }
 
-static int
-do_old_inventory(void)
+/**
+ * do_system_map_inventory - Retrieve firmware devices via SYSTEM_MAP.
+ *
+ * This function attempts to retrieve and register all the devices firmware
+ * knows about via the SYSTEM_MAP PDC call.
+ */
+static void __init system_map_inventory(void)
 {
-        unsigned int bus_id;
-	long status;
-	int ok = 0;
-
-	printk(" an older box...\n");
+	int i;
+	long status = PDC_OK;
+    
+	/*
+	 * first stop the usb controller, otherwise the machine
+	 * might crash during iommu setup
+	 */
+	pdc_suspend_usb();
+
+	for (i = 0; status != PDC_BAD_PROC && status != PDC_NE_MOD; i++) {
+		struct parisc_device *dev;
+		struct pdc_system_map_mod_info module_result;
+		struct pdc_module_path module_path;
+
+		status = pdc_system_map_find_mods(&module_result,
+				&module_path, i);
+		if (status != PDC_OK)
+			continue;
+		
+		dev = alloc_pa_dev(module_result.mod_addr, &module_path.path);
+		if (!dev)
+			continue;
+		
+		register_parisc_device(dev);
+
+		/* if available, get the additional addresses for a module */
+		if (!module_result.add_addrs)
+			continue;
 
-	/* Here, we're going to check the model, and decide
-	   if we should even bother trying. */
+		add_system_map_addresses(dev, module_result.add_addrs, i);
+	}
 
-	status = pdc_model_info(&model);
+	walk_central_bus();
+	return;
+}
 
-	bus_id = (model.hversion >> (4+7) ) &0x1f;
+void __init do_memory_inventory(void)
+{
+	switch (pdc_type) {
 
-	/* Here, we're checking the HVERSION of the CPU.
-	   We're only checking the 0th CPU, since it'll
-	   be the same on an SMP box. */
+	case PDC_TYPE_PAT:
+		pat_memconfig();
+		break;
 
-	switch (bus_id) {
-		case 0x4: 	/* 720, 730, 750, 735, 755 */
-		case 0x6: 	/* 705, 710 */
-		case 0x7: 	/* 715, 725 */
-		case 0x8: 	/* 745, 747, 742 */
-		case 0xA: 	/* 712 and similiar */
-		case 0xC: 	/* 715/64, at least */
-
-		/* Do inventory using MEM_MAP */
-		really_do_oldhw_inventory();
-		ok = 1;
+	case PDC_TYPE_SYSTEM_MAP:
+		sprockets_memconfig();
 		break;
-	default: 	/* Everything else */
-		printk("This is a very very old machine, with a bus_id of 0x%x.\n",bus_id);
-		panic("This will probably never run Linux.\n");
+
+	case PDC_TYPE_SNAKE:
+		pagezero_memconfig();
+		return;
+
+	default:
+		panic("Unknown PDC type!\n");
 	}
 
-	return ok;
+	if (npmem_ranges == 0 || pmem_ranges[0].start_pfn != 0) {
+		printk(KERN_WARNING "Bad memory configuration returned!\n");
+		printk(KERN_WARNING "Some memory may not be used!\n");
+		pagezero_memconfig();
+	}
 }
 
-#endif /* !__LP64__ */
+void __init do_device_inventory(void)
+{
+	printk(KERN_INFO "Searching for devices...\n");
 
-void do_inventory(void){
-	if((pdc_hpa_processor(&processor_hpa))<0){
-		printk(KERN_INFO "Couldn't get the HPA of the processor.\n" );
-	}
+	switch (pdc_type) {
+
+	case PDC_TYPE_PAT:
+		pat_inventory();
+		break;
 
-	printk("Searching for devices in PDC firmware... ");
-	printk("processor hpa 0x%lx\n", processor_hpa.hpa);
+	case PDC_TYPE_SYSTEM_MAP:
+		system_map_inventory();
+		break;
 
-	if (!(
-		do_newer_workstation_inventory()
-#ifdef __LP64__
-		|| do_pat_inventory()
-#else /* __LP64__ */
-		|| do_old_inventory()
-#endif /* __LP64__ */
-	    ))
-	{
-	    panic("I can't get the hardware inventory on this machine");
+	case PDC_TYPE_SNAKE:
+		snake_inventory();
+		break;
+
+	default:
+		panic("Unknown PDC type!\n");
 	}
-	print_devices(NULL);
-}
 
+	printk(KERN_INFO "Found devices:\n");
+	print_parisc_devices();
+}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/ioctl32.c linux-2.4.20-pre2/arch/parisc/kernel/ioctl32.c
--- linux-2.4.20-pre1/arch/parisc/kernel/ioctl32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/ioctl32.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,3758 @@
+/* $Id: ioctl32.c,v 1.12 2002/07/08 20:52:15 grundler Exp $
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ *
+ * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
+ * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * ioctls.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include "sys32.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/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/serial.h>
+#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
+/* Ugh. This header really is not clean */
+/* #define min min
+#define max max */
+#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 <asm/perf.h>
+#include <linux/ethtool.h>
+#include <linux/soundcard.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 <asm/module.h>	/* get #define module_map() */
+
+/* Use this to get at 32-bit user passed pointers. 
+   See sys_sparc32.c for description about these. */
+#define A(__x) ((unsigned long)(__x))
+
+/* 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 int 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 siocprivate(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	int err = sys_ioctl(fd, cmd, arg);
+	if ((unsigned) err > -4095)
+		printk(KERN_WARNING 
+			"ioctl(%d, 0x%x, %p) -- SIOCDEVPRIVATE-based ioctls aren't really\n"
+			"supported, though some will work by accident.\n",
+		    fd, cmd, (void *)arg);
+	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);
+}
+ 
+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;
+};
+
+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);
+}
+
+static inline 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 (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 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;
+	case SIOCGPPPSTATS:
+	case SIOCGPPPCSTATS:
+	case SIOCGPPPVER:
+	case SIOCETHTOOL:
+		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;
+		if(cmd == SIOCETHTOOL) {
+			u32 data;
+
+			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+			if(copy_from_user(ifr.ifr_data,
+					  (char *)A(data),
+					  sizeof(struct ethtool_cmd))) {
+				free_page((unsigned long)ifr.ifr_data);
+				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 SIOCGPPPSTATS:
+		case SIOCGPPPCSTATS:
+		case SIOCGPPPVER:
+		case SIOCETHTOOL:
+		{
+			u32 data;
+			int len;
+
+			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+			if(cmd == SIOCETHTOOL)
+				len = sizeof(struct ethtool_cmd);
+			if(cmd == SIOCGPPPVER)
+				len = strlen((char *)ifr.ifr_data) + 1;
+			else if(cmd == SIOCGPPPCSTATS)
+				len = sizeof(struct ppp_comp_stats);
+			else
+				len = sizeof(struct ppp_stats);
+
+			len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+			free_page((unsigned long)ifr.ifr_data);
+			if(len)
+				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                  */
+
+};
+
+static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct rtentry r;
+	char devname[16];
+	u32 rtdev;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	ret = copy_from_user (&r.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr));
+	ret |= __get_user (r.rt_flags, &(((struct rtentry32 *)arg)->rt_flags));
+	ret |= __get_user (r.rt_metric, &(((struct rtentry32 *)arg)->rt_metric));
+	ret |= __get_user (r.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu));
+	ret |= __get_user (r.rt_window, &(((struct rtentry32 *)arg)->rt_window));
+	ret |= __get_user (r.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);
+		r.rt_dev = devname; devname[15] = 0;
+	} else
+		r.rt_dev = 0;
+	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 inline 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;
+}
+
+
+#if 0
+/* looks like SPARC only - eg sbus video */
+struct  fbcmap32 {
+	int             index;          /* first element (0 origin) */
+	int             count;
+	u32		red;
+	u32		green;
+	u32		blue;
+};
+
+
+static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct fbcmap f;
+	int ret;
+	char red[256], green[256], blue[256];
+	u32 r, g, b;
+	mm_segment_t old_fs = get_fs();
+	
+	ret = get_user(f.index, &(((struct fbcmap32 *)arg)->index));
+	ret |= __get_user(f.count, &(((struct fbcmap32 *)arg)->count));
+	ret |= __get_user(r, &(((struct fbcmap32 *)arg)->red));
+	ret |= __get_user(g, &(((struct fbcmap32 *)arg)->green));
+	ret |= __get_user(b, &(((struct fbcmap32 *)arg)->blue));
+	if (ret)
+		return -EFAULT;
+	if ((f.index < 0) || (f.index > 255)) return -EINVAL;
+	if (f.index + f.count > 256)
+		f.count = 256 - f.index;
+	if (cmd == FBIOPUTCMAP32) {
+		ret = copy_from_user (red, (char *)A(r), f.count);
+		ret |= copy_from_user (green, (char *)A(g), f.count);
+		ret |= copy_from_user (blue, (char *)A(b), f.count);
+		if (ret)
+			return -EFAULT;
+	}
+	f.red = red; f.green = green; f.blue = blue;
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP_SPARC : FBIOGETCMAP_SPARC, (long)&f);
+	set_fs (old_fs);
+	if (!ret && cmd == FBIOGETCMAP32) {
+		ret = copy_to_user ((char *)A(r), red, f.count);
+		ret |= copy_to_user ((char *)A(g), green, f.count);
+		ret |= copy_to_user ((char *)A(b), blue, f.count);
+	}
+	return ret ? -EFAULT : 0;
+}
+
+struct fbcursor32 {
+	short set;		/* what to set, choose from the list above */
+	short enable;		/* cursor on/off */
+	struct fbcurpos pos;	/* cursor position */
+	struct fbcurpos hot;	/* cursor hot spot */
+	struct fbcmap32 cmap;	/* color map info */
+	struct fbcurpos size;	/* cursor bit map size */
+	u32	image;		/* cursor image bits */
+	u32	mask;		/* cursor mask bits */
+};
+	
+static inline int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct fbcursor f;
+	int ret;
+	char red[2], green[2], blue[2];
+	char image[128], mask[128];
+	u32 r, g, b;
+	u32 m, i;
+	mm_segment_t old_fs = get_fs();
+	
+	ret = copy_from_user (&f, (struct fbcursor32 *)arg, 2 * sizeof (short) + 2 * sizeof(struct fbcurpos));
+	ret |= __get_user(f.size.fbx, &(((struct fbcursor32 *)arg)->size.fbx));
+	ret |= __get_user(f.size.fby, &(((struct fbcursor32 *)arg)->size.fby));
+	ret |= __get_user(f.cmap.index, &(((struct fbcursor32 *)arg)->cmap.index));
+	ret |= __get_user(f.cmap.count, &(((struct fbcursor32 *)arg)->cmap.count));
+	ret |= __get_user(r, &(((struct fbcursor32 *)arg)->cmap.red));
+	ret |= __get_user(g, &(((struct fbcursor32 *)arg)->cmap.green));
+	ret |= __get_user(b, &(((struct fbcursor32 *)arg)->cmap.blue));
+	ret |= __get_user(m, &(((struct fbcursor32 *)arg)->mask));
+	ret |= __get_user(i, &(((struct fbcursor32 *)arg)->image));
+	if (ret)
+		return -EFAULT;
+	if (f.set & FB_CUR_SETCMAP) {
+		if ((uint) f.size.fby > 32)
+			return -EINVAL;
+		ret = copy_from_user (mask, (char *)A(m), f.size.fby * 4);
+		ret |= copy_from_user (image, (char *)A(i), f.size.fby * 4);
+		if (ret)
+			return -EFAULT;
+		f.image = image; f.mask = mask;
+	}
+	if (f.set & FB_CUR_SETCMAP) {
+		ret = copy_from_user (red, (char *)A(r), 2);
+		ret |= copy_from_user (green, (char *)A(g), 2);
+		ret |= copy_from_user (blue, (char *)A(b), 2);
+		if (ret)
+			return -EFAULT;
+		f.cmap.red = red; f.cmap.green = green; f.cmap.blue = blue;
+	}
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl (fd, FBIOSCURSOR, (long)&f);
+	set_fs (old_fs);
+	return ret;
+}
+#endif /* 0 */
+
+struct fb_fix_screeninfo32 {
+	char			id[16];
+        __kernel_caddr_t32	smem_start;
+	__u32			smem_len;
+	__u32			type;
+	__u32			type_aux;
+	__u32			visual;
+	__u16			xpanstep;
+	__u16			ypanstep;
+	__u16			ywrapstep;
+	__u32			line_length;
+        __kernel_caddr_t32	mmio_start;
+	__u32			mmio_len;
+	__u32			accel;
+	__u16			reserved[3];
+};
+
+struct fb_cmap32 {
+	__u32			start;
+	__u32			len;
+	__kernel_caddr_t32	red;
+	__kernel_caddr_t32	green;
+	__kernel_caddr_t32	blue;
+	__kernel_caddr_t32	transp;
+};
+
+static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	u32 red = 0, green = 0, blue = 0, transp = 0;
+	struct fb_fix_screeninfo fix;
+	struct fb_cmap cmap;
+	void *karg;
+	int err = 0;
+
+	memset(&cmap, 0, sizeof(cmap));
+	switch (cmd) {
+	case FBIOGET_FSCREENINFO:
+		karg = &fix;
+		break;
+	case FBIOGETCMAP:
+	case FBIOPUTCMAP:
+		karg = &cmap;
+		err = __get_user(cmap.start, &((struct fb_cmap32 *)arg)->start);
+		err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len);
+		err |= __get_user(red, &((struct fb_cmap32 *)arg)->red);
+		err |= __get_user(green, &((struct fb_cmap32 *)arg)->green);
+		err |= __get_user(blue, &((struct fb_cmap32 *)arg)->blue);
+		err |= __get_user(transp, &((struct fb_cmap32 *)arg)->transp);
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+		err = -ENOMEM;
+		cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+		if (!cmap.red)
+			goto out;
+		cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+		if (!cmap.green)
+			goto out;
+		cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+		if (!cmap.blue)
+			goto out;
+		if (transp) {
+			cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+			if (!cmap.transp)
+				goto out;
+		}
+			
+		if (cmd == FBIOGETCMAP)
+			break;
+
+		err = __copy_from_user(cmap.red, (char *)A(red), cmap.len * sizeof(__u16));
+		err |= __copy_from_user(cmap.green, (char *)A(green), cmap.len * sizeof(__u16));
+		err |= __copy_from_user(cmap.blue, (char *)A(blue), cmap.len * sizeof(__u16));
+		if (cmap.transp) err |= __copy_from_user(cmap.transp, (char *)A(transp), cmap.len * sizeof(__u16));
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+		break;
+	default:
+		do {
+			static int count = 0;
+			if (++count <= 20)
+				printk(KERN_WARNING
+					"%s: Unknown fb ioctl cmd fd(%d) "
+					"cmd(%08x) arg(%08lx)\n",
+					__FUNCTION__, fd, cmd, arg);
+		} while(0);
+		return -ENOSYS;
+	}
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)karg);
+	set_fs(old_fs);
+	if (err)
+		goto out;
+	switch (cmd) {
+		struct fb_fix_screeninfo32 fix32;
+	case FBIOGET_FSCREENINFO:
+		memset(&fix32, 0, sizeof(fix32));
+		memcpy(fix32.id, fix.id, sizeof(fix32.id));
+		fix32.smem_start = (__u32)(unsigned long)fix.smem_start;
+		fix32.smem_len	= fix.smem_len;
+		fix32.type	= fix.type;
+		fix32.type_aux	= fix.type_aux;
+		fix32.visual	= fix.visual;
+		fix32.xpanstep	= fix.xpanstep;
+		fix32.ypanstep	= fix.ypanstep;
+		fix32.ywrapstep = fix.ywrapstep;
+		fix32.line_length = fix.line_length;
+		fix32.mmio_start = (__u32)(unsigned long)fix.mmio_start;
+		fix32.mmio_len	= fix.mmio_len;
+		fix32.accel	= fix.accel;
+		memcpy(fix32.reserved, fix.reserved, sizeof(fix32.reserved));
+		err = __copy_to_user((void *) arg, (const void *) &fix32, sizeof(fix32));
+
+printk("fix  : %lx %x  %x %x %x  %x %x %x %x  %lx %x %x\n",
+	fix.smem_start, fix.smem_len,
+	fix.type, fix.type_aux, fix.visual,
+	fix.xpanstep, fix.ypanstep, fix.ywrapstep, fix.line_length,
+	fix.mmio_start, fix.mmio_len, fix.accel);
+printk("fix32: %x %x  %x %x %x  %x %x %x %x  %x %x %x\n",
+	fix32.smem_start, fix32.smem_len,
+	fix32.type, fix32.type_aux, fix32.visual,
+	fix32.xpanstep, fix32.ypanstep, fix32.ywrapstep, fix32.line_length,
+	fix32.mmio_start, fix32.mmio_len, fix32.accel);
+
+		break;
+	case FBIOGETCMAP:
+		err = __copy_to_user((char *)A(red), cmap.red, cmap.len * sizeof(__u16));
+		err |= __copy_to_user((char *)A(green), cmap.blue, cmap.len * sizeof(__u16));
+		err |= __copy_to_user((char *)A(blue), cmap.blue, cmap.len * sizeof(__u16));
+		if (cmap.transp)
+			err |= __copy_to_user((char *)A(transp), cmap.transp, cmap.len * sizeof(__u16));
+		break;
+	case FBIOPUTCMAP:
+		break;
+	}
+	if (err)
+		err = -EFAULT;
+
+out:	if (cmap.red) kfree(cmap.red);
+	if (cmap.green) kfree(cmap.green);
+	if (cmap.blue) kfree(cmap.blue);
+	if (cmap.transp) kfree(cmap.transp);
+	return err;
+}
+
+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(KERN_WARNING
+					"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(KERN_WARNING
+					"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_read32 {
+	int			cdread_lba;
+	__kernel_caddr_t32	cdread_bufaddr;
+	int			cdread_buflen;
+};
+
+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 cdread;
+	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 CDROMREADMODE2:
+	case CDROMREADMODE1:
+	case CDROMREADRAW:
+	case CDROMREADCOOKED:
+		karg = &cdread;
+		err = __get_user(cdread.cdread_lba, &((struct cdrom_read32 *)arg)->cdread_lba);
+		err |= __get_user(addr, &((struct cdrom_read32 *)arg)->cdread_bufaddr);
+		err |= __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)arg)->cdread_buflen);
+		if (err)
+			return -EFAULT;
+		data = kmalloc(cdread.cdread_buflen, GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+		cdread.cdread_bufaddr = data;
+		break;
+	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(KERN_WARNING
+					"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 CDROMREADMODE2:
+	case CDROMREADMODE1:
+	case CDROMREADRAW:
+	case CDROMREADCOOKED:
+		err = copy_to_user((char *)A(addr), data, cdread.cdread_buflen);
+		break;
+	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(KERN_WARNING
+				"%s: Unknown loop ioctl cmd, fd(%d) "
+				"cmd(%08x) arg(%08lx)\n",
+				__FUNCTION__, fd, cmd, arg);
+	}
+	}
+	return err;
+}
+
+#ifdef CONFIG_VT
+extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
+
+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 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
+
+#if 0
+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;
+}
+#endif
+
+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, 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(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, 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(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)) {
+			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]->bd = 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);
+		err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
+		if (err)
+			return err;
+		u.lv_bydev.lv = get_lv_t(ptr, &err);
+		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.bd = 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.bd = 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
+
+#ifdef CONFIG_GENRTC
+#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 serial_struct32 {
+	int	type;
+	int	line;
+	unsigned int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	io_type;
+	char	reserved_char[1];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	unsigned int	iomem_base;	/* char * really */
+	unsigned short	iomem_reg_shift;
+	unsigned int	port_high;
+	int	reserved[1];
+};
+
+static int do_tiocgserial(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct serial_struct ss;
+	int ret;
+	struct serial_struct32 * uptr = (struct serial_struct32 *)arg;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl(fd, cmd, (unsigned long) &ss);
+	set_fs(old_fs);
+
+	if (!ret) {
+		/* structs match up to iomem_base */
+		ret = copy_to_user(uptr, &ss, sizeof(struct serial_struct32));
+		ret |= put_user(ss.iomem_base, &uptr->iomem_base);
+		ret |= put_user(ss.iomem_reg_shift, &uptr->iomem_reg_shift);
+		ret |= put_user(ss.port_high, &uptr->port_high);
+		if (ret)
+			ret = -EFAULT;
+	}
+	return ret;
+}
+
+
+struct ioctl_trans {
+	unsigned long handler;
+	unsigned int cmd;
+	unsigned int next;
+};
+#define HANDLE_IOCTL(cmd, handler) asm volatile(".dword %1\n.word %0, 0" : : "i" (cmd), "i" (handler));
+
+#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd, sys_ioctl) 
+
+
+#define IOCTL_TABLE_START void ioctl32_foo(void) { asm volatile(".data\nioctl_translations:");
+#define IOCTL_TABLE_END asm volatile("\nioctl_translations_end:\n\t.previous"); }
+
+IOCTL_TABLE_START
+/* List here exlicitly which ioctl's are known to have
+ * compatable types passed or none at all...
+ */
+/* 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)
+/* 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(TIOCSSERIAL)
+COMPATIBLE_IOCTL(TIOCSERGETLSR)
+/* Big F */
+#if 0
+COMPATIBLE_IOCTL(FBIOGTYPE)
+COMPATIBLE_IOCTL(FBIOSATTR)
+COMPATIBLE_IOCTL(FBIOGATTR)
+COMPATIBLE_IOCTL(FBIOSVIDEO)
+COMPATIBLE_IOCTL(FBIOGVIDEO)
+COMPATIBLE_IOCTL(FBIOGCURSOR32)  /* This is not implemented yet. Later it should be converted... */
+COMPATIBLE_IOCTL(FBIOSCURPOS)
+COMPATIBLE_IOCTL(FBIOGCURPOS)
+COMPATIBLE_IOCTL(FBIOGCURMAX)
+#endif
+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)
+/* 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)
+
+/* 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(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)
+/* Little k */
+#if 0
+COMPATIBLE_IOCTL(KIOCTYPE)
+COMPATIBLE_IOCTL(KIOCLAYOUT)
+COMPATIBLE_IOCTL(KIOCGTRANS)
+COMPATIBLE_IOCTL(KIOCTRANS)
+COMPATIBLE_IOCTL(KIOCCMD)
+COMPATIBLE_IOCTL(KIOCSDIRECT)
+COMPATIBLE_IOCTL(KIOCSLED)
+COMPATIBLE_IOCTL(KIOCGLED)
+COMPATIBLE_IOCTL(KIOCSRATE)
+COMPATIBLE_IOCTL(KIOCGRATE)
+#endif
+/* Big S */
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
+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 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_IO)
+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(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)
+/* PPPOX */
+COMPATIBLE_IOCTL(PPPOEIOCSFWD);
+COMPATIBLE_IOCTL(PPPOEIOCDFWD);
+/* CDROM stuff */
+COMPATIBLE_IOCTL(CDROMPAUSE)
+COMPATIBLE_IOCTL(CDROMRESUME)
+COMPATIBLE_IOCTL(CDROMPLAYMSF)
+COMPATIBLE_IOCTL(CDROMPLAYTRKIND)
+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)
+/* 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_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_AGC)
+COMPATIBLE_IOCTL(SOUND_MIXER_3DSE)
+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)
+/* And these ioctls need translation */
+HANDLE_IOCTL(TIOCGSERIAL, do_tiocgserial)
+HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
+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(SIOCGPPPSTATS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc)
+HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
+HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
+HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
+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(FBIOGET_FSCREENINFO, fb_ioctl_trans)
+HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
+HANDLE_IOCTL(FBIOPUTCMAP, fb_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(CDROMREADMODE2, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADMODE1, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADRAW, cdrom_ioctl_trans)
+HANDLE_IOCTL(CDROMREADCOOKED, cdrom_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)
+#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+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)
+#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)
+#if 0
+/* One SMB ioctl needs translations. */
+#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32)
+HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
+#endif
+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_GENRTC)
+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)   /* struct rtc_time only has ints */
+COMPATIBLE_IOCTL(RTC_ALM_READ)  /* struct rtc_time only has ints */
+COMPATIBLE_IOCTL(RTC_RD_TIME)   /* struct rtc_time only has ints */
+COMPATIBLE_IOCTL(RTC_SET_TIME)  /* struct rtc_time only has ints */
+HANDLE_IOCTL(RTC_IRQP_READ, w_long)
+COMPATIBLE_IOCTL(RTC_IRQP_SET)
+HANDLE_IOCTL(RTC_EPOCH_READ, w_long)
+COMPATIBLE_IOCTL(RTC_EPOCH_SET)
+#endif
+#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 */
+COMPATIBLE_IOCTL(PA_PERF_ON)
+COMPATIBLE_IOCTL(PA_PERF_OFF)
+COMPATIBLE_IOCTL(PA_PERF_VERSION)
+IOCTL_TABLE_END
+
+unsigned int ioctl32_hash_table[1024];
+
+extern 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] = (u32)(long)trans;
+	else {
+		t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash];
+		while (t->next)
+			t = (struct ioctl_trans *)(long)t->next;
+		trans->next = 0;
+		t->next = (u32)(long)trans;
+	}
+}
+
+static int __init init_sys32_ioctl(void)
+{
+	int i;
+	extern struct ioctl_trans ioctl_translations[], ioctl_translations_end[];
+
+	for (i = 0; &ioctl_translations[i] < &ioctl_translations_end[0]; 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;
+
+panic("register_ioctl32_conversion() is B0RKEN! Called by %p\n", __builtin_return_address(0));
+
+	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 = (u32)(long)sys_ioctl;
+	else
+		additional_ioctls[i].handler = (u32)(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 *)(long)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 *)(long)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 (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+	unsigned long pafnptr[4];
+	extern char __gp;
+	struct ioctl_trans *t;
+	int error = -EBADF;
+
+	filp = fget(fd);
+	if(!filp)
+		goto out2;
+
+	if (!filp->f_op || !filp->f_op->ioctl) {
+		error = sys_ioctl (fd, cmd, arg);
+		goto out;
+	}
+
+	/* intercept private networking ioctl() calls here since it is
+	 * an onerous task to figure out which ones of the HANDLE_IOCTL
+	 * list map to these values.
+	 */
+	if (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 0xf) {
+		error = siocprivate(fd, cmd, arg);
+		goto out;
+	}
+
+	t = (struct ioctl_trans *)(long)ioctl32_hash_table [ioctl32_hash (cmd)];
+
+	while (t && t->cmd != cmd)
+		t = (struct ioctl_trans *)(long)t->next;
+	if (t) {
+		handler = (void *) pafnptr;
+		pafnptr[0] = pafnptr[1] = 0UL;
+		pafnptr[2] = (unsigned long) t->handler;
+		pafnptr[3] = A(&__gp);
+		error = handler(fd, cmd, arg, filp);
+	} else {
+		static int count = 0;
+		if (++count <= 20)
+			printk(KERN_WARNING
+				"sys32_ioctl: Unknown cmd fd(%d) "
+				"cmd(%08x) arg(%08x)\n",
+				(int)fd, (unsigned int)cmd, (unsigned int)arg);
+		error = -EINVAL;
+	}
+out:
+	fput(filp);
+out2:
+	return error;
+}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/iosapic.c linux-2.4.20-pre2/arch/parisc/kernel/iosapic.c
--- linux-2.4.20-pre1/arch/parisc/kernel/iosapic.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/iosapic.c	Mon Aug 12 16:34:14 2002
@@ -169,11 +169,13 @@
 
 #include <asm/byteorder.h>	/* get in-line asm for swab */
 #include <asm/pdc.h>
-#include <asm/pdcpat.h>
 #include <asm/page.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/gsc.h>		/* gsc_read/write functions */
+#ifdef CONFIG_SUPERIO
+#include <asm/superio.h>
+#endif
 
 #include <asm/iosapic.h>
 #include "./iosapic_private.h"
@@ -181,7 +183,6 @@
 #define MODULE_NAME "iosapic"
 
 /* "local" compile flags */
-#undef IOSAPIC_CALLBACK
 #undef PCI_BRIDGE_FUNCS
 #undef DEBUG_IOSAPIC
 #undef DEBUG_IOSAPIC_IRT
@@ -282,28 +283,6 @@
 
 #define	IOSAPIC_EOI(eoi_addr, eoi_data) gsc_writel(eoi_data, eoi_addr)
 
-#if IOSAPIC_CALLBACK
-/*
-** Shouldn't use callback since SAPIC doesn't have an officially assigned
-** H or S version numbers. Slight long term risk the number chosen would
-** collide with something else.
-** But benefit is cleaner lba/sapic interface.
-** Might be worth it but for just use direct calls for now.
-**
-** Entry below is copied from lba driver.
-** Only thing different is hw_type.
-*/
-static struct pa_iodc_driver iosapic_driver_for[] = {
-	{HPHW_OTHER, 0x782, 0, 0x0000A, 0, 0x00,
-	DRIVER_CHECK_HWTYPE + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION,
-	"I/O Sapic", "",(void *) iosapic_callback},     
-	{0,0,0,0,0,0,
-	0,
-	(char *) NULL,(char *) NULL,(void *) NULL}                     
-};
-#endif /* IOSAPIO_CALLBACK */
-
-
 static struct iosapic_info *iosapic_list;
 static spinlock_t iosapic_lock;
 static int iosapic_count;
@@ -350,25 +329,22 @@
 static int __init /* return number of entries as success/fail flag */
 iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
 {
-	struct pdc_pat_io_num pdc_io_num; /* PAT PDC return block */
 	long status;              /* PDC return value status */
-	struct irt_entry *table = NULL;  /* start of interrupt routing tbl */
+	struct irt_entry *table;  /* start of interrupt routing tbl */
 	unsigned long num_entries = 0UL;
 
 	ASSERT(NULL != irt);
-	/* FIXME ASSERT(((&pdc_io_num) & (0x3f)) == 0);  enforce 32-byte alignment */
 
-	/* Try PAT_PDC to get interrupt routing table size */
-	DBG(KERN_DEBUG "calling get_irt_size\n");
-	status = pdc_pat_get_irt_size( &pdc_io_num, cell_num);
-	DBG(KERN_DEBUG "get_irt_size: %ld\n", status);
+	if (is_pdc_pat()) {
 
-	switch(status) {
+		/* Use pat pdc routine to get interrupt routing table size */
+		DBG("calling get_irt_size (cell %ld)\n", cell_num);
+		status = pdc_pat_get_irt_size(&num_entries, cell_num);
+		DBG("get_irt_size: %ld\n", status);
 
-	case PDC_RET_OK:	/* PAT box. Proceed to get the IRT */
+		ASSERT(status == PDC_OK);
 
 		/* save the number of entries in the table */
-		num_entries = pdc_io_num.num;
 		ASSERT(0UL != num_entries);
 
 		/*
@@ -384,30 +360,27 @@
 		}
 
 		/* get PCI INT routing table */
-		status = pdc_pat_get_irt( (void *) table, cell_num);
-		DBG(KERN_DEBUG "pdc_pat_get_irt: %ld\n", status);
-		ASSERT(status == PDC_RET_OK);
-		break;
-
-	case PDC_RET_NE_PROC: /* Not a PAT platform. Try PDC_PCI extensions */
+		status = pdc_pat_get_irt(table, cell_num);
+		DBG("pdc_pat_get_irt: %ld\n", status);
+		ASSERT(status == PDC_OK);
+	} else {
 		/*
-		** C3000/J5000 (and similar) platforms with "legacy" PDC
-		** will return exactly one IRT.
+		** C3000/J5000 (and similar) platforms with Sprockets PDC
+		** will return exactly one IRT for all iosapics.
 		** So if we have one, don't need to get it again.
 		*/
 		if (NULL != irt_cell)
-			break;
+			return 0;
 
-		status = pdc_pci_irt_size( (void *)&pdc_io_num,
-				/* elroy HPA (really a NOP) */ 0);
-		DBG(KERN_WARNING "pdc_pci_irt_size: %ld\n", status);
+		/* Should be using the Elroy's HPA, but it's ignored anyway */
+		status = pdc_pci_irt_size(&num_entries, 0);
+		DBG("pdc_pci_irt_size: %ld\n", status);
 
-		if (PDC_RET_OK != status) {
+		if (PDC_OK != status) {
 			/* Not a "legacy" system with I/O SAPIC either */
 			return 0;
 		}
 
-		num_entries = pdc_io_num.num;
 		ASSERT(0UL != num_entries);
 
 		table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
@@ -416,36 +389,27 @@
 			return 0;
 		}
 
-		status = pdc_pci_irt( (void *) &pdc_io_num,
-				(void *) NULL, /* Elroy HPA - not used */
-				(void *) table);
-
-		ASSERT(PDC_RET_OK == status);
-		break;
-
-	default:
-		printk(KERN_WARNING MODULE_NAME ": PDC_PAT_IO call failed with %ld\n", status);
-		break;
+		/* HPA ignored by this call too. */
+		status = pdc_pci_irt(num_entries, 0, table);
+		ASSERT(PDC_OK == status);
 	}
 
 	/* return interrupt table address */
 	*irt = table;
 
-
 #ifdef DEBUG_IOSAPIC_IRT
-	{
+{
 	struct irt_entry *p = table;
 	int i;
 
-	printk(MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num);
-	printk(MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n",
+	printk(KERN_DEBUG MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num);
+	printk(KERN_DEBUG MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n",
 		table,
 		num_entries,
 		(int) sizeof(struct irt_entry));
 
-	for (i = 0 ; i < num_entries ; i++, p++)
-	{
-		printk(MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n",
+	for (i = 0 ; i < num_entries ; i++, p++) {
+		printk(KERN_DEBUG MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n",
 		p->entry_type, p->entry_length, p->interrupt_type,
 		p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id,
 		p->src_seg_id, p->dest_iosapic_intin,
@@ -453,7 +417,7 @@
 		((u32 *) p)[3]
 		);
 	}
-	}
+}
 #endif /* DEBUG_IOSAPIC_IRT */
 
 	return num_entries;
@@ -464,6 +428,8 @@
 void __init
 iosapic_init(void)
 {
+	unsigned long cell = 0;
+
 	/* init global data */
 	iosapic_lock = SPIN_LOCK_UNLOCKED;
         iosapic_list = (struct iosapic_info *) NULL;
@@ -471,22 +437,24 @@
 
 	DBG("iosapic_init()\n");
 
+#ifdef __LP64__
+	if (is_pdc_pat()) {
+		int status;
+		struct pdc_pat_cell_num cell_info;
+
+		status = pdc_pat_cell_get_number(&cell_info);
+		if (status == PDC_OK) {
+			cell = cell_info.cell_num;
+		}
+	}
+#endif
+
 	/*
 	**  get IRT for this cell.
 	*/
-	irt_num_entry =  iosapic_load_irt(0L, &irt_cell);
+	irt_num_entry =  iosapic_load_irt(cell, &irt_cell);
 	if (0 == irt_num_entry)
 		irt_cell = NULL;	/* old PDC w/o iosapic */
-
-#ifdef IOSAPIC_CALLBACK
-	/*
-	** When new I/O SAPICs are discovered, this callback
-	** will get invoked. Implies lba driver will register
-	** I/O Sapic as a device it "discovered" with faked
-	** IODC data.
-	*/
-	register_driver(iosapic_driver_for);
-#endif /* IOSAPIC_CALLBACK */
 }
 
 
@@ -546,7 +514,7 @@
 		return i;
 	}
 
-	printk(KERN_WARNING MODULE_NAME ": 0x%p : no IRT entry for slot %d, pin %d\n",
+	printk(KERN_WARNING MODULE_NAME ": 0x%lx : no IRT entry for slot %d, pin %d\n",
 			isi->isi_hpa, slot, intr_pin);
 	return NULL;
 }
@@ -571,21 +539,18 @@
 {
 	u8 intr_pin, intr_slot;
 
-	(void) pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);
+	pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);
 
-	DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n", PCI_SLOT(pcidev->devfn), intr_pin);
+	DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n",
+		PCI_SLOT(pcidev->devfn), intr_pin);
 
-	if (0 == intr_pin)
-	{
-		/*
-		** The device does NOT support/use IRQ lines.
-		*/
+	if (0 == intr_pin) {
+		/* The device does NOT support/use IRQ lines.  */
 		return NULL;
 	}
 
 	/* Check if pcidev behind a PPB */
-	if (NULL != pcidev->bus->self)
-	{
+	if (NULL != pcidev->bus->self) {
 		/* Convert pcidev INTR_PIN into something we
 		** can lookup in the IRT.
 		*/
@@ -600,7 +565,7 @@
 		** or by some ambitous soul who wants to watch TV.
 		*/
 		if (pci_bridge_funcs->xlate_intr_line) {
-			intr_pin = (*pci_bridge_funcs->xlate_intr_line)(pcidev);
+			intr_pin = pci_bridge_funcs->xlate_intr_line(pcidev);
 		}
 #else	/* PCI_BRIDGE_FUNCS */
 		struct pci_bus *p = pcidev->bus;
@@ -646,8 +611,8 @@
 	extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
 	int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline;
 
-	DBG("iosapic_interrupt(): irq %d line %d eoi %p\n", irq, vi->vi_irqline,
-				vi->vi_eoi_addr);
+	DBG("iosapic_interrupt(): irq %d line %d eoi %p\n",
+		irq, vi->vi_irqline, vi->vi_eoi_addr);
 
 /* FIXME: Need to mask/unmask? processor IRQ is already masked... */
 	do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs);
@@ -668,12 +633,39 @@
 	struct vector_info *vi;
 	int isi_line;	/* line used by device */
 	int tmp;
+	int return_irq;
+#ifdef CONFIG_SUPERIO
+	int superio_irq = -1;
+#endif
 
 	if (NULL == isi) {
-		printk(KERN_WARNING MODULE_NAME ": 0x%p hpa not registered\n", isi->isi_hpa);
+		printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
+			pcidev->name);
 		return(-1);
 	}
 
+#ifdef CONFIG_SUPERIO
+	if (is_superio_device(pcidev)) {
+		superio_irq = superio_fixup_irq(pcidev);
+		if (superio_irq == -1)
+		    return(-1);
+
+		if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN) {
+
+			/*
+			 * SuperIO USB controller has an irt entry.
+			 * Only let the USB controller hookup the rest
+			 * of the interrupt routing when it comes through.
+			 * Note that interrupts for all three functions
+			 * actually come through the PIC's on function 1!
+			 */
+
+			pcidev->irq = superio_irq;
+			return superio_irq;
+		}
+	}
+#endif /* CONFIG_SUPERIO */
+
 	/* lookup IRT entry for isi/slot/pin set */
 	irte = iosapic_xlate_pin(isi, pcidev);
 	if (NULL == irte) {
@@ -714,22 +706,31 @@
 	vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8);
         ASSERT(vi->vi_txn_data < 256);  /* matches 8 above */
 
-	tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, "iosapic", vi);
+	tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0,
+						vi->vi_name, vi);
 	ASSERT(tmp == 0);
 
-	vi->vi_eoi_addr = ((void *) isi->isi_hpa) + IOSAPIC_REG_EOI;
+	vi->vi_eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI);
 	vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline);
 
 	ASSERT(NULL != isi->isi_region);
-	/*
-	** pcidev->irq still needs to be virtualized.
-	*/
-	pcidev->irq = isi->isi_region->data.irqbase + isi_line;
+	/* pcidev->irq still needs to be virtualized.  */
+
+	return_irq = isi->isi_region->data.irqbase + isi_line;
 
-	DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", PCI_SLOT(pcidev->devfn),
-	PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
+#ifdef CONFIG_SUPERIO
+	if (superio_irq != -1) {
+		superio_inform_irq(return_irq);
+		return_irq = superio_irq;
+	}
+#endif
+	pcidev->irq = return_irq;
+
+	DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n",
+		PCI_SLOT(pcidev->devfn),
+	PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, return_irq);
 
-	return(pcidev->irq);
+	return return_irq;
 }
 
 
@@ -755,7 +756,7 @@
 	struct iosapic_info *isp = vi->vi_ios;
 
 	ASSERT(NULL != isp);
-	ASSERT(NULL != isp->isi_hpa);
+	ASSERT(0 != isp->isi_hpa);
 	DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p  0x%x 0x%x\n",
 		vi->vi_irqline,
 		isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW,
@@ -807,16 +808,13 @@
 	** Extracting id_eid isn't a real clean way of getting it.
 	** But the encoding is the same for both PA and IA64 platforms.
 	*/
-#ifdef __LP64__
-	if (pdc_pat) {
+	if (is_pdc_pat()) {
 		/*
 		** PAT PDC just hands it to us "right".
 		** vi_txn_addr comes from cpu_data[x].txn_addr.
 		*/
 		*dp1 = (u32) (vi->vi_txn_addr);
-	} else
-#endif
-	{
+	} else {
 		/* 
 		** eg if base_addr == 0xfffa0000),
 		**    we want to get 0xa0ff0000.
@@ -886,7 +884,6 @@
 
 	/* data is initialized by fixup_irq */
 	ASSERT(0 < vi->vi_txn_irq);
-	ASSERT(0UL != vi->vi_txn_addr);
 	ASSERT(0UL != vi->vi_txn_data);
 
 	iosapic_set_irt_data(vi, &d0, &d1);
@@ -895,10 +892,10 @@
 
 #ifdef DEBUG_IOSAPIC_IRT
 {
-u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);
-printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);
-while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));
-printk("\n");
+	u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);
+	printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);
+	while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));
+	printk("\n");
 }
 
 printk("iosapic_enable_irq(): sel ");
@@ -943,10 +940,10 @@
 
 
 static struct irq_region_ops iosapic_irq_ops = {
-	iosapic_disable_irq,
-	iosapic_enable_irq,
-	iosapic_mask_irq,
-	iosapic_unmask_irq
+	disable_irq:	iosapic_disable_irq,
+	enable_irq:	iosapic_enable_irq,
+	mask_irq:	iosapic_mask_irq,
+	unmask_irq:	iosapic_unmask_irq
 };
 
 
@@ -967,15 +964,9 @@
 }
 
 
-#ifndef IOSAPIC_CALLBACK
-/*
-** iosapic_register() is the alternative to iosapic_driver_for().
-** (Only one or the other should be implemented.)
-*/
-
 /*
 ** iosapic_register() is called by "drivers" with an integrated I/O SAPIC.
-** Caller must be certain they have an I/O SAPIC and know it's MMIO address.
+** Caller must be certain they have an I/O SAPIC and know its MMIO address.
 **
 **	o allocate iosapic_info and add it to the list
 **	o read iosapic version and squirrel that away
@@ -984,7 +975,7 @@
 **	o allocate isi_region (registers region handlers)
 */
 void *
-iosapic_register(void *hpa)
+iosapic_register(unsigned long hpa)
 {
 	struct iosapic_info *isi = NULL;
 	struct irt_entry *irte = irt_cell;
@@ -1021,7 +1012,7 @@
 
 	memset(isi, 0, sizeof(struct iosapic_info));
 
-	isi->isi_hpa         = (unsigned char *) hpa;
+	isi->isi_hpa         = hpa;
 	isi->isi_version     = iosapic_rd_version(isi);
 	isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
 
@@ -1034,6 +1025,7 @@
 	}
 
 	memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors);
+	sprintf(isi->isi_name, "IO-SAPIC%02d", iosapic_count++);
 
 	/*
 	** Initialize vector array
@@ -1041,17 +1033,16 @@
 	for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
 		vip->vi_irqline = (unsigned char) cnt;
 		vip->vi_ios = isi;
+		sprintf(vip->vi_name, "%s-L%d", isi->isi_name, cnt);
 	}
 
 	isi->isi_region = alloc_irq_region(isi->isi_num_vectors,
-				&iosapic_irq_ops, IRQ_REG_DIS|IRQ_REG_MASK,
-				"I/O Sapic", (void *) isi->isi_vector);
+				&iosapic_irq_ops, isi->isi_name,
+				(void *) isi->isi_vector);
 
 	ASSERT(NULL != isi->isi_region);
 	return ((void *) isi);
 }
-#endif /* !IOSAPIC_CALLBACK */
-
 
 
 #ifdef DEBUG_IOSAPIC
@@ -1092,8 +1083,8 @@
 {
 	ASSERT(NULL != isi);
 	printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi);
-	printk(KERN_DEBUG "\t\tisi_hpa: %p\n", isi->isi_hpa);
-	printk(KERN_DEBUG "\t\tisi_satus:     %x\n", isi->isi_status);
+	printk(KERN_DEBUG "\t\tisi_hpa:       %lx\n", isi->isi_hpa);
+	printk(KERN_DEBUG "\t\tisi_status:     %x\n", isi->isi_status);
 	printk(KERN_DEBUG "\t\tisi_version:   %x\n", isi->isi_version);
 	printk(KERN_DEBUG "\t\tisi_vector:    %p\n", isi->isi_vector);
 }
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/iosapic_private.h linux-2.4.20-pre2/arch/parisc/kernel/iosapic_private.h
--- linux-2.4.20-pre1/arch/parisc/kernel/iosapic_private.h	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/iosapic_private.h	Mon Aug 12 16:34:14 2002
@@ -111,22 +111,25 @@
 	struct irt_entry *vi_irte;      /* IRT entry */
 	u32	*vi_eoi_addr;	/* precalculate EOI reg address */
 	u32	vi_eoi_data;	/* IA64: ?       PA: swapped txn_data */
-	u8	vi_status;	/* status/flags */
-	u8	vi_irqline;	/* INTINn(IRQ) */
 	int	vi_txn_irq;	/* virtual IRQ number for processor */
 	ulong	vi_txn_addr;    /* IA64: id_eid  PA: partial HPA */
 	ulong	vi_txn_data;    /* IA64: vector  PA: EIR bit */
+	u8	vi_status;	/* status/flags */
+	u8	vi_irqline;	/* INTINn(IRQ) */
+	char	vi_name[32];    /* user visible identity */
 };
 
 
 struct iosapic_info {
 	struct iosapic_info  *isi_next;      /* list of I/O SAPIC          */
-	volatile void        *isi_hpa;       /* physical base address      */
+	unsigned long	     isi_hpa;	     /* physical base address */
 	struct irq_region    *isi_region;    /* each I/O SAPIC is one region */
 	struct vector_info   *isi_vector;    /* IRdT (IRQ line) array  */
 	int                  isi_num_vectors; /* size of IRdT array */
 	int                  isi_status;     /* status/flags               */
 	unsigned int         isi_version;    /* DEBUG: data fr version reg */
+	/* round up to next cacheline */
+	char                 isi_name[20]; /* identify region for users */
 };
 
 
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/irq.c linux-2.4.20-pre2/arch/parisc/kernel/irq.c
--- linux-2.4.20-pre1/arch/parisc/kernel/irq.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/irq.c	Mon Aug 12 16:34:14 2002
@@ -1,13 +1,10 @@
-/* $Id: irq.c,v 1.8 2000/02/08 02:01:17 grundler Exp $
- *
+/* 
  * Code to handle x86 style IRQs plus some generic interrupt stuff.
  *
- * This is not in any way SMP-clean.
- *
  * Copyright (C) 1992 Linus Torvalds
  * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
- * Copyright (C) 1999 SuSE GmbH (Author: Philipp Rumpf, prumpf@tux.org)
- * Copyright (C) 2000 Hewlett Packard Corp (Co-Author: Grant Grundler, grundler@cup.hp.com)
+ * Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org)
+ * Copyright (C) 1999-2000 Grant Grundler
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
@@ -23,138 +20,167 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#include <linux/config.h>
 #include <linux/bitops.h>
 #include <asm/bitops.h>
+#include <linux/config.h>
 #include <asm/pdc.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/kernel_stat.h>
 #include <linux/signal.h>
-#include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
 #include <linux/irq.h>
+#include <linux/spinlock.h>
 
 #include <asm/cache.h>
 
 #undef DEBUG_IRQ
+#undef PARISC_IRQ_CR16_COUNTS
 
 extern void timer_interrupt(int, void *, struct pt_regs *);
 extern void ipi_interrupt(int, void *, struct pt_regs *);
 
 #ifdef DEBUG_IRQ
-#define DBG_IRQ(x...)   printk(x)
+#define DBG_IRQ(irq, x)	if ((irq) != TIMER_IRQ) printk x
 #else /* DEBUG_IRQ */
-#define DBG_IRQ(x...)
+#define DBG_IRQ(irq, x)	do { } while (0)
 #endif /* DEBUG_IRQ */
 
-#define EIEM_MASK(irq) (1L<<(MAX_CPU_IRQ-IRQ_OFFSET(irq)))
-#define CLEAR_EIEM_BIT(irq) set_eiem(get_eiem() & ~EIEM_MASK(irq))
-#define SET_EIEM_BIT(irq) set_eiem(get_eiem() | EIEM_MASK(irq))
+#define EIEM_MASK(irq)       (1UL<<(MAX_CPU_IRQ-IRQ_OFFSET(irq)))
+
+/* Bits in EIEM correlate with cpu_irq_action[].
+** Numbered *Big Endian*! (ie bit 0 is MSB)
+*/
+static unsigned long cpu_eiem = 0;
+
+static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED;  /* protect IRQ regions */
+
+#ifdef CONFIG_SMP
+static void cpu_set_eiem(void *info)
+{
+	set_eiem((unsigned long) info);
+}
+#endif
 
-static void disable_cpu_irq(void *unused, int irq)
+static inline void disable_cpu_irq(void *unused, int irq)
 {
-	CLEAR_EIEM_BIT(irq);
+	unsigned long eirr_bit = EIEM_MASK(irq);
+
+	cpu_eiem &= ~eirr_bit;
+	set_eiem(cpu_eiem);
+        smp_call_function(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
 }
 
 static void enable_cpu_irq(void *unused, int irq)
 {
-	unsigned long mask = EIEM_MASK(irq);
+	unsigned long eirr_bit = EIEM_MASK(irq);
+
+	mtctl(eirr_bit, 23);	/* clear EIRR bit before unmasking */
+	cpu_eiem |= eirr_bit;
+        smp_call_function(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
+	set_eiem(cpu_eiem);
+}
+
+/* mask and disable are the same at the CPU level
+** Difference is enable clears pending interrupts
+*/
+#define mask_cpu_irq	disable_cpu_irq
 
-	mtctl(mask, 23);
-	SET_EIEM_BIT(irq);
+static inline void unmask_cpu_irq(void *unused, int irq)
+{
+	unsigned long eirr_bit = EIEM_MASK(irq);
+	cpu_eiem |= eirr_bit;
+	/* NOTE: sending an IPI will cause do_cpu_irq_mask() to
+	** handle *any* unmasked pending interrupts.
+	** ie We don't need to check for pending interrupts here.
+	*/
+        smp_call_function(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
+	set_eiem(cpu_eiem);
 }
 
 static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
-	[IRQ_OFFSET(TIMER_IRQ)] { timer_interrupt, 0, 0, "timer", NULL, NULL },
-	[IRQ_OFFSET(IPI_IRQ)]	{ ipi_interrupt, 0, 0, "IPI", NULL, NULL },
+	[IRQ_OFFSET(TIMER_IRQ)] { handler: timer_interrupt, name: "timer", },
+#ifdef CONFIG_SMP
+	[IRQ_OFFSET(IPI_IRQ)]	{ handler: ipi_interrupt,   name: "IPI", },
+#endif
 };
 
 struct irq_region cpu_irq_region = {
-	{ disable_cpu_irq, enable_cpu_irq, NULL, NULL },
-	{ &cpu_data[0], "PA-PIC", IRQ_REG_MASK|IRQ_REG_DIS, IRQ_FROM_REGION(CPU_IRQ_REGION)},
-	cpu_irq_actions
+	ops:	{ disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq },
+	data:	{ dev: &cpu_data[0],
+		  name: "PA-CPU-00",
+		  irqbase: IRQ_FROM_REGION(CPU_IRQ_REGION), },
+	action:	cpu_irq_actions,
 };
 
 struct irq_region *irq_region[NR_IRQ_REGS] = {
-	[ 0 ] NULL,		/* abuse will data page fault (aka code 15) */
+	[ 0 ]              NULL, /* reserved for EISA, else causes data page fault (aka code 15) */
 	[ CPU_IRQ_REGION ] &cpu_irq_region,
 };
 
 
+/*
+** Generic interfaces that device drivers can use:
+**    mask_irq()	block IRQ
+**    unmask_irq()	re-enable IRQ and trigger if IRQ is pending
+**    disable_irq()	block IRQ
+**    enable_irq()	clear pending and re-enable IRQ
+*/
 
-/* we special-case the real IRQs here, which feels right given the relatively
- * high cost of indirect calls.  If anyone is bored enough to benchmark this
- * and find out whether I am right, feel free to.   prumpf */
-
-static inline void mask_irq(int irq)
+void mask_irq(int irq)
 {
 	struct irq_region *region;
-	
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
-#endif
-	DBG_IRQ("mask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
 
-	if(IRQ_REGION(irq) != CPU_IRQ_REGION) {
-		region = irq_region[IRQ_REGION(irq)];
-		if(region->data.flags & IRQ_REG_MASK)
-			region->ops.mask_irq(region->data.dev, IRQ_OFFSET(irq));
-	} else {
-		CLEAR_EIEM_BIT(irq);
-	}
+	DBG_IRQ(irq, ("mask_irq(%d) %d+%d eiem 0x%lx\n", irq,
+				IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+	irq = irq_cannonicalize(irq);
+	region = irq_region[IRQ_REGION(irq)];
+	if (region->ops.mask_irq)
+		region->ops.mask_irq(region->data.dev, IRQ_OFFSET(irq));
 }
 
-static inline void unmask_irq(int irq)
+void unmask_irq(int irq)
 {
 	struct irq_region *region;
 
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
-#endif
-	DBG_IRQ("unmask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
-
-	if(IRQ_REGION(irq) != CPU_IRQ_REGION) {
-		region = irq_region[IRQ_REGION(irq)];
-		if(region->data.flags & IRQ_REG_MASK)
-			region->ops.unmask_irq(region->data.dev, IRQ_OFFSET(irq));
-	} else {
-		SET_EIEM_BIT(irq);
-	}
+	DBG_IRQ(irq, ("unmask_irq(%d) %d+%d eiem 0x%lx\n", irq,
+				IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+	irq = irq_cannonicalize(irq);
+	region = irq_region[IRQ_REGION(irq)];
+	if (region->ops.unmask_irq)
+		region->ops.unmask_irq(region->data.dev, IRQ_OFFSET(irq));
 }
 
 void disable_irq(int irq)
 {
 	struct irq_region *region;
 
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
-#endif
-	DBG_IRQ("disable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+	DBG_IRQ(irq, ("disable_irq(%d) %d+%d eiem 0x%lx\n", irq,
+				IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+	irq = irq_cannonicalize(irq);
 	region = irq_region[IRQ_REGION(irq)];
-
-	if(region->data.flags & IRQ_REG_DIS)
+	if (region->ops.disable_irq)
 		region->ops.disable_irq(region->data.dev, IRQ_OFFSET(irq));
 	else
 		BUG();
 }
 
-void enable_irq(int irq) 
+void enable_irq(int irq)
 {
 	struct irq_region *region;
 
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
-#endif
-	DBG_IRQ("enable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+	DBG_IRQ(irq, ("enable_irq(%d) %d+%d eiem 0x%lx\n", irq,
+				IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+	irq = irq_cannonicalize(irq);
 	region = irq_region[IRQ_REGION(irq)];
 
-	if(region->data.flags & IRQ_REG_DIS)
+	if (region->ops.enable_irq)
 		region->ops.enable_irq(region->data.dev, IRQ_OFFSET(irq));
 	else
 		BUG();
@@ -164,30 +190,40 @@
 {
 #ifdef CONFIG_PROC_FS
 	char *p = buf;
-	int i, j;
-	int regnr, irq_no;
-	struct irq_region *region;
-	struct irqaction *action, *mainaction;
+	unsigned int regnr = 0;
 
-	p += sprintf(p, "           ");
-	for (j=0; j<smp_num_cpus; j++)
-		p += sprintf(p, "CPU%d       ",j);
+	p += sprintf(p, "     ");
+#ifdef CONFIG_SMP
+	for (; regnr < smp_num_cpus; regnr++)
+#endif
+		p += sprintf(p, "      CPU%d ", regnr);
+
+#ifdef PARISC_IRQ_CR16_COUNTS
+	p += sprintf(p, "[min/avg/max] (CPU cycle counts)");
+#endif
 	*p++ = '\n';
 
+	/* We don't need *irqsave lock variants since this is
+	** only allowed to change while in the base context.
+	*/
+	spin_lock(&irq_lock);
 	for (regnr = 0; regnr < NR_IRQ_REGS; regnr++) {
-	    region = irq_region[regnr];
-	    if (!region || !region->action)
+	    unsigned int i;
+	    struct irq_region *region = irq_region[regnr];
+
+            if (!region || !region->action)
 		continue;
-	    
-	    mainaction = region->action;
 
 	    for (i = 0; i <= MAX_CPU_IRQ; i++) {
-		action = mainaction++;
-		if (!action || !action->name)
-		    continue;
-		
-		irq_no = IRQ_FROM_REGION(regnr) + i;
-		
+		struct irqaction *action = &region->action[i];
+		unsigned int irq_no = IRQ_FROM_REGION(regnr) + i;
+#ifdef CONFIG_SMP
+		unsigned int j;
+#endif
+
+		if (!action->handler)
+			continue;
+
 		p += sprintf(p, "%3d: ", irq_no);
 #ifndef CONFIG_SMP
 		p += sprintf(p, "%10u ", kstat_irqs(irq_no));
@@ -196,30 +232,48 @@
 		    p += sprintf(p, "%10u ",
 			    kstat.irqs[cpu_logical_map(j)][irq_no]);
 #endif
-		p += sprintf(p, " %14s", 
+		p += sprintf(p, " %14s",
 			    region->data.name ? region->data.name : "N/A");
+#ifndef PARISC_IRQ_CR16_COUNTS
 		p += sprintf(p, "  %s", action->name);
 
-		for (action=action->next; action; action = action->next)
-		    p += sprintf(p, ", %s", action->name);
-		*p++ = '\n';
-	    }	    	     
-	}  
+		while ((action = action->next))
+			p += sprintf(p, ", %s", action->name);
+#else
+		for ( ;action; action = action->next) {
+			unsigned int i, avg, min, max;
 
-	p += sprintf(p, "\n");
-#if CONFIG_SMP
-	p += sprintf(p, "LOC: ");
-	for (j = 0; j < smp_num_cpus; j++)
-		p += sprintf(p, "%10u ",
-			apic_timer_irqs[cpu_logical_map(j)]);
-	p += sprintf(p, "\n");
+			min = max = action->cr16_hist[0];
+
+			for (avg = i = 0; i < PARISC_CR16_HIST_SIZE; i++) {
+				int hist = action->cr16_hist[i];
+
+				if (hist) {
+					avg += hist;
+				} else
+					break;
+
+				if (hist > max) max = hist;
+				if (hist < min) min = hist;
+			}
+
+			avg /= i;
+			p += sprintf(p, " %s[%d/%d/%d]", action->name,
+					min,avg,max);
+		}
 #endif
 
+		*p++ = '\n';
+	    }
+	}
+	spin_unlock(&irq_lock);
+
+	p += sprintf(p, "\n");
 	return p - buf;
 
 #else	/* CONFIG_PROC_FS */
 
-	return 0;	
+	return 0;
 
 #endif	/* CONFIG_PROC_FS */
 }
@@ -240,8 +294,8 @@
 	int irq;
 
 	/* never return irq 0 cause that's the interval timer */
-	for(irq=1; irq<=MAX_CPU_IRQ; irq++) {
-		if(cpu_irq_region.action[irq].handler == NULL) {
+	for (irq = 1; irq <= MAX_CPU_IRQ; irq++) {
+		if (cpu_irq_region.action[irq].handler == NULL) {
 			return (IRQ_FROM_REGION(CPU_IRQ_REGION) + irq);
 		}
 	}
@@ -254,9 +308,7 @@
 txn_claim_irq(int irq)
 {
 	if (irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)].handler ==NULL)
-	{
 		return irq;
-	}
 
 	/* unlikely, but be prepared */
 	return -1;
@@ -267,10 +319,10 @@
 {
 	struct cpuinfo_parisc *dev = (struct cpuinfo_parisc *) (irq_region[IRQ_REGION(virt_irq)]->data.dev);
 
-	if (0==dev) {
+	if (!dev) {
 		printk(KERN_ERR "txn_alloc_addr(0x%x): CPU IRQ region? dev %p\n",
 			virt_irq,dev);
-		return(0UL);
+		return 0;
 	}
 	return (dev->txn_addr);
 }
@@ -283,7 +335,7 @@
 ** V-class (EPIC):          6 bits
 ** N/L-class/A500:          8 bits (iosapic)
 ** PCI 2.2 MSI:             16 bits (I think)
-** Existing PCI devices:    32-bits (NCR c720/ATM/GigE/HyperFabric)
+** Existing PCI devices:    32-bits (all Symbios SCSI/ATM/HyperFabric)
 **
 ** On the service provider side:
 ** o PA 1.1 (and PA2.0 narrow mode)     5-bits (width of EIR register)
@@ -308,117 +360,204 @@
 		panic("Sorry -- didn't allocate valid IRQ for this device\n");
 	}
 
-	return(IRQ_OFFSET(virt_irq));
+	return (IRQ_OFFSET(virt_irq));
 }
 
-
-/* FIXME: SMP, flags, bottom halves, rest */
 void do_irq(struct irqaction *action, int irq, struct pt_regs * regs)
 {
 	int cpu = smp_processor_id();
 
 	irq_enter(cpu, irq);
+	++kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
 
-#ifdef DEBUG_IRQ
-	if (irq != TIMER_IRQ)
+	DBG_IRQ(irq, ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)));
+
+	for (; action; action = action->next) {
+#ifdef PARISC_IRQ_CR16_COUNTS
+		unsigned long cr_start = mfctl(16);
 #endif
-	DBG_IRQ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
-	if (action->handler == NULL)
-		printk(KERN_ERR "No handler for interrupt %d !\n", irq);
 
-	for(; action && action->handler; action = action->next) {
+		if (action->handler == NULL) {
+			if (IRQ_REGION(irq) == EISA_IRQ_REGION && irq_region[EISA_IRQ_REGION]) {
+				/* were we called due to autodetecting (E)ISA irqs ? */
+				unsigned int *status;
+				status = &irq_region[EISA_IRQ_REGION]->data.status[IRQ_OFFSET(irq)];
+				if (*status & IRQ_AUTODETECT) {
+					*status &= ~IRQ_WAITING;
+					continue; 
+				}
+			}
+			printk(KERN_ERR "IRQ:  CPU:%d No handler for IRQ %d !\n", cpu, irq);
+			continue;
+		}
+
 		action->handler(irq, action->dev_id, regs);
+
+#ifdef PARISC_IRQ_CR16_COUNTS
+		{
+			unsigned long cr_end = mfctl(16);
+			unsigned long tmp = cr_end - cr_start;
+			/* check for roll over */
+			cr_start = (cr_end < cr_start) ?  -(tmp) : (tmp);
+		}
+		action->cr16_hist[action->cr16_idx++] = (int) cr_start;
+		action->cr16_idx &= PARISC_CR16_HIST_SIZE - 1;
+#endif
 	}
-	
+
 	irq_exit(cpu, irq);
+}
+
+
+/* ONLY called from entry.S:intr_extint() */
+void do_cpu_irq_mask(struct irq_region *region, struct pt_regs *regs)
+{
+	unsigned long eirr_val;
+	unsigned int i=3;	/* limit time in interrupt context */
+
+	/*
+	 * PSW_I or EIEM bits cannot be enabled until after the
+	 * interrupts are processed.
+	 * timer_interrupt() assumes it won't get interrupted when it
+	 * holds the xtime_lock...an unmasked interrupt source could
+	 * interrupt and deadlock by trying to grab xtime_lock too.
+	 * Keeping PSW_I and EIEM disabled avoids this.
+	 */
+	set_eiem(0UL);	/* disable all extr interrupt for now */
+
+	/* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
+	 * 2) We loop here on EIRR contents in order to avoid
+	 *    nested interrupts or having to take another interupt
+	 *    when we could have just handled it right away.
+	 * 3) Limit the number of times we loop to make sure other
+	 *    processing can occur.
+	 */
+	while ((eirr_val = (mfctl(23) & cpu_eiem)) && --i) {
+		unsigned long bit = (1UL<<MAX_CPU_IRQ);
+		unsigned int irq = 0;
+
+		mtctl(eirr_val, 23); /* reset bits we are going to process */
+
+#ifdef DEBUG_IRQ
+		if (eirr_val != (1UL << MAX_CPU_IRQ))
+			printk(KERN_DEBUG "do_cpu_irq_mask  %x\n", eirr_val);
+#endif
+
+		for (; eirr_val && bit; bit>>=1, irq++)
+		{
+			unsigned int irq_num;
+			if (!(bit&eirr_val))
+				continue;
 
-	/* don't need to care about unmasking and stuff */
-	do_softirq();
+			/* clear bit in mask - can exit loop sooner */
+			eirr_val &= ~bit;
+
+			irq_num = region->data.irqbase + irq;
+			do_irq(&region->action[irq], irq_num, regs);
+		}
+	}
+	set_eiem(cpu_eiem);
 }
 
+
+/* Called from second level IRQ regions: eg dino or iosapic. */
 void do_irq_mask(unsigned long mask, struct irq_region *region, struct pt_regs *regs)
 {
 	unsigned long bit;
-	int irq;
-	int cpu = smp_processor_id();
+	unsigned int irq;
 
 #ifdef DEBUG_IRQ
-	if (mask != (1L << MAX_CPU_IRQ))
-	    printk("do_irq_mask %08lx %p %p\n", mask, region, regs);
+	if (mask != (1L<<MAX_CPU_IRQ))
+	    printk(KERN_DEBUG "do_irq_mask %08lx %p %p\n", mask, region, regs);
 #endif
 
-	for(bit=(1L<<MAX_CPU_IRQ), irq = 0; mask && bit; bit>>=1, irq++) {
-		int irq_num;
-		if(!(bit&mask))
+	for (bit = (1L<<MAX_CPU_IRQ), irq = 0; mask && bit; bit>>=1, irq++) {
+		unsigned int irq_num;
+		if (!(bit&mask))
 			continue;
 
+		mask &= ~bit;	/* clear bit in mask - can exit loop sooner */
 		irq_num = region->data.irqbase + irq;
 
-		++kstat.irqs[cpu][IRQ_FROM_REGION(CPU_IRQ_REGION) | irq];
-		if (IRQ_REGION(irq_num) != CPU_IRQ_REGION)
-		    ++kstat.irqs[cpu][irq_num];
-
 		mask_irq(irq_num);
 		do_irq(&region->action[irq], irq_num, regs);
 		unmask_irq(irq_num);
 	}
 }
 
-static inline int alloc_irqregion(void)
+
+static inline int find_free_region(void)
 {
 	int irqreg;
 
-	for(irqreg=1; irqreg<=(NR_IRQ_REGS); irqreg++) {
-		if(irq_region[irqreg] == NULL)
+	for (irqreg=1; irqreg <= (NR_IRQ_REGS); irqreg++) {
+		if (irq_region[irqreg] == NULL)
 			return irqreg;
 	}
 
 	return 0;
 }
 
-struct irq_region *alloc_irq_region(
-	int count, struct irq_region_ops *ops, unsigned long flags,
-	const char *name, void *dev)
+
+/*****
+ * alloc_irq_region - allocate/init a new IRQ region
+ * @count: number of IRQs in this region.
+ * @ops: function table with request/release/mask/unmask/etc.. entries.
+ * @name: name of region owner for /proc/interrupts output.
+ * @dev: private data to associate with the new IRQ region.
+ *
+ * Every IRQ must become a MMIO write to the CPU's EIRR in
+ * order to get CPU service. The IRQ region represents the
+ * number of unique events the region handler can (or must)
+ * identify. For PARISC CPU, that's the width of the EIR Register.
+ * IRQ regions virtualize IRQs (eg EISA or PCI host bus controllers)
+ * for line based devices.
+ */
+struct irq_region *alloc_irq_region( int count, struct irq_region_ops *ops,
+					const char *name, void *dev)
 {
 	struct irq_region *region;
 	int index;
 
-	index = alloc_irqregion();
+	index = find_free_region();
+	if (index == 0) {
+		printk(KERN_ERR "Maximum number of irq regions exceeded. Increase NR_IRQ_REGS!\n");
+		return NULL;
+	}
 
-	if((IRQ_REGION(count-1)))
+	if ((IRQ_REGION(count-1)))
 		return NULL;
-	
+
 	if (count < IRQ_PER_REGION) {
-	    DBG_IRQ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n", 
-			IRQ_PER_REGION, name, count);
+	    DBG_IRQ(0, ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n",
+			IRQ_PER_REGION, name, count));
 	    count = IRQ_PER_REGION;
 	}
 
-	if(flags & IRQ_REG_MASK)
-		if(!(ops->mask_irq && ops->unmask_irq))
-			return NULL;
-			
-	if(flags & IRQ_REG_DIS)
-		if(!(ops->disable_irq && ops->enable_irq))
+	/* if either mask *or* unmask is set, both have to be set. */
+	if((ops->mask_irq || ops->unmask_irq) &&
+		!(ops->mask_irq && ops->unmask_irq))
 			return NULL;
 
-	if((irq_region[index]))
-		return NULL;
+	/* ditto for enable/disable */
+	if( (ops->disable_irq || ops->enable_irq) &&
+		!(ops->disable_irq && ops->enable_irq) )
+			return NULL;
 
-	region = kmalloc(sizeof *region, GFP_ATOMIC);
-	if(!region)
+	region = kmalloc(sizeof(*region), GFP_ATOMIC);
+	if (!region)
 		return NULL;
+	memset(region, 0, sizeof(*region));
 
-	region->action = kmalloc(sizeof *region->action * count, GFP_ATOMIC);
-	if(!region->action) {
+	region->action = kmalloc(count * sizeof(*region->action), GFP_ATOMIC);
+	if (!region->action) {
 		kfree(region);
 		return NULL;
 	}
-	memset(region->action, 0, sizeof *region->action * count);
+	memset(region->action, 0, count * sizeof(*region->action));
 
 	region->ops = *ops;
 	region->data.irqbase = IRQ_FROM_REGION(index);
-	region->data.flags = flags;
 	region->data.name = name;
 	region->data.dev = dev;
 
@@ -426,14 +565,12 @@
 
 	return irq_region[index];
 }
-	
 
-	
 /* FIXME: SMP, flags, bottom halves, rest */
 
-int request_irq(unsigned int irq, 
+int request_irq(unsigned int irq,
 		void (*handler)(int, void *, struct pt_regs *),
-		unsigned long irqflags, 
+		unsigned long irqflags,
 		const char * devname,
 		void *dev_id)
 {
@@ -442,13 +579,19 @@
 #if 0
 	printk(KERN_INFO "request_irq(%d, %p, 0x%lx, %s, %p)\n",irq, handler, irqflags, devname, dev_id);
 #endif
-	if(!handler) {
+
+	irq = irq_cannonicalize(irq);
+	/* request_irq()/free_irq() may not be called from interrupt context. */
+	if (in_interrupt())
+		BUG();
+
+	if (!handler) {
 		printk(KERN_ERR "request_irq(%d,...): Augh! No handler for irq!\n",
 			irq);
 		return -EINVAL;
 	}
 
-	if ((IRQ_REGION(irq) == 0) || irq_region[IRQ_REGION(irq)] == NULL) {
+	if (irq_region[IRQ_REGION(irq)] == NULL) {
 		/*
 		** Bug catcher for drivers which use "char" or u8 for
 		** the IRQ number. They lose the region number which
@@ -459,19 +602,24 @@
 		return -EINVAL;
 	}
 
-	action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)];
+	spin_lock(&irq_lock);
+	action = &(irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]);
 
-	if(action->handler) {
-		while(action->next)
+	/* First one is preallocated. */
+	if (action->handler) {
+		/* But it's in use...find the tail and allocate a new one */
+		while (action->next)
 			action = action->next;
 
-		action->next = kmalloc(sizeof *action, GFP_ATOMIC);
+		action->next = kmalloc(sizeof(*action), GFP_ATOMIC);
+		memset(action->next, 0, sizeof(*action));
 
 		action = action->next;
-	}			
+	}
 
-	if(!action) {
-		printk(KERN_ERR "request_irq():Augh! No action!\n") ;
+	if (!action) {
+		spin_unlock(&irq_lock);
+		printk(KERN_ERR "request_irq(): Augh! No action!\n") ;
 		return -ENOMEM;
 	}
 
@@ -481,6 +629,7 @@
 	action->name = devname;
 	action->next = NULL;
 	action->dev_id = dev_id;
+	spin_unlock(&irq_lock);
 
 	enable_irq(irq);
 	return 0;
@@ -490,14 +639,22 @@
 {
 	struct irqaction *action, **p;
 
+	/* See comments in request_irq() about interrupt context */
+	irq = irq_cannonicalize(irq);
+	
+	if (in_interrupt()) BUG();
+
+	spin_lock(&irq_lock);
 	action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)];
 
-	if(action->dev_id == dev_id) {
-		if(action->next == NULL)
+	if (action->dev_id == dev_id) {
+		if (action->next == NULL) {
 			action->handler = NULL;
-		else
-			memcpy(action, action->next, sizeof *action);
+		} else {
+			memcpy(action, action->next, sizeof(*action));
+		}
 
+		spin_unlock(&irq_lock);
 		return;
 	}
 
@@ -512,27 +669,175 @@
 		*p = action->next;
 		kfree(action);
 
+		spin_unlock(&irq_lock);
 		return;
 	}
 
+	spin_unlock(&irq_lock);
 	printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
 }
 
-unsigned long probe_irq_on (void)
+
+/*
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
+ */
+
+static DECLARE_MUTEX(probe_sem);
+
+/**
+ *	probe_irq_on	- begin an interrupt autodetect
+ *
+ *	Commence probing for an interrupt. The interrupts are scanned
+ *	and a mask of potential interrupt lines is returned.
+ *
+ */
+
+/* TODO: spin_lock_irq(desc->lock -> irq_lock) */
+
+unsigned long probe_irq_on(void)
 {
-	return 0;
+	unsigned int i;
+	unsigned long val;
+	unsigned long delay;
+	struct irq_region *region;
+
+	/* support for irq autoprobing is limited to EISA (irq region 0) */
+	region = irq_region[EISA_IRQ_REGION];
+	if (!EISA_bus || !region)
+		return 0;
+
+	down(&probe_sem);
+
+	/*
+	 * enable any unassigned irqs
+	 * (we must startup again here because if a longstanding irq
+	 * happened in the previous stage, it may have masked itself)
+	 */
+	for (i = EISA_MAX_IRQS-1; i > 0; i--) {
+		struct irqaction *action;
+		
+		spin_lock_irq(&irq_lock);
+		action = region->action + i;
+		if (!action->handler) {
+			region->data.status[i] |= IRQ_AUTODETECT | IRQ_WAITING;
+			region->ops.enable_irq(region->data.dev,i);
+		}
+		spin_unlock_irq(&irq_lock);
+	}
+
+	/*
+	 * Wait for spurious interrupts to trigger
+	 */
+	for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+		/* about 100ms delay */ synchronize_irq();
+
+	/*
+	 * Now filter out any obviously spurious interrupts
+	 */
+	val = 0;
+	for (i = 0; i < EISA_MAX_IRQS; i++) {
+		unsigned int status;
+
+		spin_lock_irq(&irq_lock);
+		status = region->data.status[i];
+
+		if (status & IRQ_AUTODETECT) {
+			/* It triggered already - consider it spurious. */
+			if (!(status & IRQ_WAITING)) {
+				region->data.status[i] = status & ~IRQ_AUTODETECT;
+				region->ops.disable_irq(region->data.dev,i);
+			} else
+				if (i < BITS_PER_LONG)
+					val |= (1 << i);
+		}
+		spin_unlock_irq(&irq_lock);
+	}
+
+	return val;
 }
 
-int probe_irq_off (unsigned long irqs)
+/*
+ * Return the one interrupt that triggered (this can
+ * handle any interrupt source).
+ */
+
+/**
+ *	probe_irq_off	- end an interrupt autodetect
+ *	@val: mask of potential interrupts (unused)
+ *
+ *	Scans the unused interrupt lines and returns the line which
+ *	appears to have triggered the interrupt. If no interrupt was
+ *	found then zero is returned. If more than one interrupt is
+ *	found then minus the first candidate is returned to indicate
+ *	their is doubt.
+ *
+ *	The interrupt probe logic state is returned to its previous
+ *	value.
+ *
+ *	BUGS: When used in a module (which arguably shouldnt happen)
+ *	nothing prevents two IRQ probe callers from overlapping. The
+ *	results of this are non-optimal.
+ */
+ 
+int probe_irq_off(unsigned long val)
 {
-	return 0;
+        struct irq_region *region;
+	int i, irq_found, nr_irqs;
+
+        /* support for irq autoprobing is limited to EISA (irq region 0) */
+        region = irq_region[EISA_IRQ_REGION];
+        if (!EISA_bus || !region)
+		return 0;
+
+	nr_irqs = 0;
+	irq_found = 0;
+	for (i = 0; i < EISA_MAX_IRQS; i++) {
+		unsigned int status;
+		
+		spin_lock_irq(&irq_lock);
+		status = region->data.status[i];
+
+                if (status & IRQ_AUTODETECT) {
+			if (!(status & IRQ_WAITING)) {
+				if (!nr_irqs)
+					irq_found = i;
+				nr_irqs++;
+			}
+			region->ops.disable_irq(region->data.dev,i);
+			region->data.status[i] = status & ~IRQ_AUTODETECT;
+		}
+		spin_unlock_irq(&irq_lock);
+	}
+	up(&probe_sem);
+
+	if (nr_irqs > 1)
+		irq_found = -irq_found;
+	return irq_found;
 }
 
 
 void __init init_IRQ(void)
 {
+	local_irq_disable();	/* PARANOID - should already be disabled */
+	mtctl(-1L, 23);		/* EIRR : clear all pending external intr */
+#ifdef CONFIG_SMP
+	if (!cpu_eiem)
+		cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
+#else
+	cpu_eiem = EIEM_MASK(TIMER_IRQ);
+#endif
+        set_eiem(cpu_eiem);	/* EIEM : enable all external intr */
+
 }
 
-void init_irq_proc(void)
+#ifdef CONFIG_PROC_FS
+/* called from kernel/sysctl.c:sysctl_init() */
+void __init init_irq_proc(void)
 {
 }
+#endif
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/irq_smp.c linux-2.4.20-pre2/arch/parisc/kernel/irq_smp.c
--- linux-2.4.20-pre1/arch/parisc/kernel/irq_smp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/irq_smp.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,232 @@
+/*
+ *  linux/arch/parisc/kernel/irq_smp.c
+ *  (90% stolen from alpha port, 9% from ia64, rest is mine -ggg)
+ *  
+ *  Copyright (C) 2001 Hewlett-Packard Co
+ *  Copyright (C) 2001 Grant Grundler <grundler@puffin.external.hp.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+
+int global_irq_holder = NO_PROC_ID;	/* Who has global_irq_lock. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; /* protects IRQ's. */
+
+
+/* Global IRQ locking depth. */
+static void *previous_irqholder = NULL;
+
+#define MAXCOUNT 100000000
+
+
+static void
+show(char * str, void *where)
+{
+	int cpu = smp_processor_id();
+
+	printk("\n%s, CPU %d: %p\n", str, cpu, where);
+	printk("irq:  %d [%d %d]\n",
+		irqs_running(),
+		local_irq_count(0),
+		local_irq_count(1));
+
+	printk("bh:   %d [%d %d]\n",
+		spin_is_locked(&global_bh_lock) ? 1 : 0,
+		local_bh_count(0),
+		local_bh_count(1));
+}
+
+static inline void
+wait_on_irq(int cpu, void *where)
+{
+	int count = MAXCOUNT;
+
+	for (;;) {
+
+		/*
+		 * Wait until all interrupts are gone. Wait
+		 * for bottom half handlers unless we're
+		 * already executing in one..
+		 */
+		if (!irqs_running()) {
+			if (local_bh_count(cpu)
+			    || !spin_is_locked(&global_bh_lock))
+				break;
+		}
+
+		/* Duh, we have to loop. Release the lock to avoid deadlocks */
+		spin_unlock(&global_irq_lock);
+
+		for (;;) {
+			if (!--count) {
+				show("wait_on_irq", where);
+				count = MAXCOUNT;
+			}
+			__sti();
+			udelay(1); /* make sure to run pending irqs */
+			__cli();
+
+			if (irqs_running())
+				continue;
+			if (spin_is_locked(&global_irq_lock))
+				continue;
+			if (!local_bh_count(cpu)
+			    && spin_is_locked(&global_bh_lock))
+				continue;
+			if (spin_trylock(&global_irq_lock))
+				break;
+		}
+	}
+}
+
+static inline void
+get_irqlock(int cpu, void* where)
+{
+	if (!spin_trylock(&global_irq_lock)) {
+		/* Do we already hold the lock?  */
+		if (cpu == global_irq_holder)
+			return;
+		/* Uhhuh.. Somebody else got it.  Wait.  */
+		spin_lock(&global_irq_lock);
+	}
+
+	/*
+	 * Ok, we got the lock bit.
+	 * But that's actually just the easy part.. Now
+	 * we need to make sure that nobody else is running
+	 * in an interrupt context. 
+	 */
+	wait_on_irq(cpu, where);
+
+	/*
+	 * Finally.
+	 */
+#if DEBUG_SPINLOCK
+	global_irq_lock.task = current;
+	global_irq_lock.previous = where;
+#endif
+	global_irq_holder = cpu;
+	previous_irqholder = where;
+}
+
+
+/*
+** A global "cli()" while in an interrupt context
+** turns into just a local cli(). Interrupts
+** should use spinlocks for the (very unlikely)
+** case that they ever want to protect against
+** each other.
+** 
+** If we already have local interrupts disabled,
+** this will not turn a local disable into a
+** global one (problems with spinlocks: this makes
+** save_flags+cli+sti usable inside a spinlock).
+*/
+void
+__global_cli(void)
+{
+	unsigned int flags;
+	__save_flags(flags);
+	if (flags & PSW_I) {
+		int cpu = smp_processor_id();
+		__cli(); 
+		if (!local_irq_count(cpu)) {
+			void *where = __builtin_return_address(0);
+			get_irqlock(cpu, where);
+		}
+	}
+}
+
+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;
+	int cpu = smp_processor_id();
+
+	__save_flags(flags);
+	local_enabled = (flags & PSW_I) != 0;
+	/* default to local */
+	retval = 2 + local_enabled;
+
+	/* Check for global flags if we're not in an interrupt.  */
+	if (!local_irq_count(cpu)) {
+		if (local_enabled)
+			retval = 1;
+		if (global_irq_holder == cpu)
+			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(KERN_ERR "global_restore_flags: %08lx (%p)\n",
+			flags, __builtin_return_address(0));
+	}
+}
+
+/*
+ * From its use, I infer that synchronize_irq() stalls a thread until
+ * the effects of a command to an external device are known to have
+ * taken hold.  Typically, the command is to stop sending interrupts.
+ * The strategy here is wait until there is at most one processor
+ * (this one) in an irq.  The memory barrier serializes the write to
+ * the device and the subsequent accesses of global_irq_count.
+ * --jmartin
+ */
+#define DEBUG_SYNCHRONIZE_IRQ 0
+
+void
+synchronize_irq(void)
+{
+	/* Jay's version.  */
+	if (irqs_running()) {
+		cli();
+		sti();
+	}
+}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/keyboard.c linux-2.4.20-pre2/arch/parisc/kernel/keyboard.c
--- linux-2.4.20-pre1/arch/parisc/kernel/keyboard.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/keyboard.c	Mon Aug 12 16:34:14 2002
@@ -1,4 +1,12 @@
 /*
+ *  WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *  ---------------------------------------------------------------
+ *  This source file will be removed as soon as we have converted
+ *  hp_psaux.c and hp_keyb.c to the input layer !
+ *  
+ */
+
+/*
  *  linux/arch/parisc/kernel/keyboard.c
  *
  *  Alex deVries <adevries@thepuffingroup.com>
@@ -7,8 +15,10 @@
  *  Copyright 2000 Philipp Rumpf
  */
 
+#include <linux/errno.h>
 #include <linux/keyboard.h>
 #include <asm/keyboard.h>
+#include <linux/module.h>
 
 static int def_setkeycode(unsigned int x, unsigned int y)
 {
@@ -43,20 +53,29 @@
 
 static char def_sysrq_xlate[NR_KEYS];
 
-static struct kbd_ops def_kbd_ops = {
-	setkeycode:	def_setkeycode,
-	getkeycode:	def_getkeycode,
-	translate:	def_translate,
-	unexpected_up:	def_unexpected_up,
-	leds:		def_leds,
-	init_hw:	def_init_hw,
-
-	sysrq_key:	0xff,
+#define DEFAULT_KEYB_OPS \
+	setkeycode:	def_setkeycode,	\
+	getkeycode:	def_getkeycode, \
+	translate:	def_translate, \
+	unexpected_up:	def_unexpected_up, \
+	leds:		def_leds, \
+	init_hw:	def_init_hw, \
+	sysrq_key:	0xff, \
 	sysrq_xlate:	def_sysrq_xlate,
+
+static struct kbd_ops def_kbd_ops = {
+	DEFAULT_KEYB_OPS
 };
 
 struct kbd_ops *kbd_ops = &def_kbd_ops;
 
+void unregister_kbd_ops(void)
+{
+	struct kbd_ops new_kbd_ops = { DEFAULT_KEYB_OPS };
+	register_kbd_ops(&new_kbd_ops);
+}
+EXPORT_SYMBOL(unregister_kbd_ops);
+
 void register_kbd_ops(struct kbd_ops *ops)
 {
 	if(ops->setkeycode)
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/lba_pci.c linux-2.4.20-pre2/arch/parisc/kernel/lba_pci.c
--- linux-2.4.20-pre1/arch/parisc/kernel/lba_pci.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/lba_pci.c	Mon Aug 12 16:34:14 2002
@@ -34,6 +34,7 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>		/* for __init and __devinit */
+/* #define PCI_DEBUG	enable ASSERT */
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
@@ -42,15 +43,13 @@
 #include <asm/byteorder.h>
 #include <asm/irq.h>		/* for struct irq_region support */
 #include <asm/pdc.h>
-#include <asm/pdcpat.h>
 #include <asm/page.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 
-#include <asm/hardware.h>	/* for register_driver() stuff */
+#include <asm/hardware.h>	/* for register_parisc_driver() stuff */
 #include <asm/iosapic.h>	/* for iosapic_register() */
-#include <asm/gsc.h>		/* gsc_read/write stuff */
-
+#include <asm/io.h>		/* read/write stuff */
 
 #ifndef TRUE
 #define TRUE (1 == 1)
@@ -62,6 +61,9 @@
 #undef DEBUG_LBA_CFG	/* debug Config Space Access (ie PCI Bus walk) */
 #undef DEBUG_LBA_PAT	/* debug PCI Resource Mgt code - PDC PAT only */
 
+#undef FBB_SUPPORT	/* Fast Back-Back xfers - NOT READY YET */
+
+
 #ifdef DEBUG_LBA
 #define DBG(x...)	printk(x)
 #else
@@ -102,22 +104,6 @@
 
 #define MODULE_NAME "lba"
 
-static int lba_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-
-static struct pa_iodc_driver lba_drivers_for[]= {
-
-   {HPHW_BRIDGE, 0x782, 0x0, 0xa, 0,0,
-		DRIVER_CHECK_HVERSION + 
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "tbd", (void *) lba_driver_callback},
-
-   {0,0,0,0,0,0,
-   0,
-   (char *) NULL, (char *) NULL, (void *) NULL}
-};
-
-
 #define LBA_FUNC_ID	0x0000	/* function id */
 #define LBA_FCLASS	0x0008	/* function class, bist, header, rev... */
 #define LBA_CAPABLE	0x0030	/* capabilities register */
@@ -137,6 +123,9 @@
 #define LBA_MOD_ID	0x0100	/* Module ID. PDC_PAT_CELL reports 4 */
 
 #define LBA_STAT_CTL	0x0108	/* Status & Control */
+#define   LBA_BUS_RESET		0x01	/*  Deassert PCI Bus Reset Signal */
+#define   CLEAR_ERRLOG		0x10	/*  "Clear Error Log" cmd */
+#define   CLEAR_ERRLOG_ENABLE	0x20	/*  "Clear Error Log" Enable */
 #define   HF_ENABLE	0x40	/*    enable HF mode (default is -1 mode) */
 
 #define LBA_LMMIO_BASE	0x0200	/* < 4GB I/O address range */
@@ -162,15 +151,18 @@
 
 #define LBA_DMA_CTL	0x0278	/* firmware sets this */
 
-/* RESET: ignore DMA stuff until we can measure performance */
-#define LBA_IBASE	0x0300	/* DMA support */
+#define LBA_IBASE	0x0300	/* SBA DMA support */
 #define LBA_IMASK	0x0308
+
+/* FIXME: ignore DMA Hint stuff until we can measure performance */
 #define LBA_HINT_CFG	0x0310
 #define LBA_HINT_BASE	0x0380	/* 14 registers at every 8 bytes. */
 
 /* ERROR regs are needed for config cycle kluges */
 #define LBA_ERROR_CONFIG 0x0680
+#define     LBA_SMART_MODE 0x20
 #define LBA_ERROR_STATUS 0x0688
+#define LBA_ROPE_CTL     0x06A0
 
 #define LBA_IOSAPIC_BASE	0x800 /* Offset of IRQ logic */
 
@@ -232,19 +224,20 @@
  * BE WARNED: register writes are posted.
  *  (ie follow writes which must reach HW with a read)
  */
-#define READ_U8(addr)  gsc_readb(addr)
-#define READ_U16(addr) gsc_readw((u16 *) (addr))
-#define READ_U32(addr) gsc_readl((u32 *) (addr))
-#define WRITE_U8(value, addr) gsc_writeb(value, addr)
-#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr))
-#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
-
-#define READ_REG8(addr)  gsc_readb(addr)
-#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr)))
-#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr)))
-#define WRITE_REG8(value, addr) gsc_writeb(value, addr)
-#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr))
-#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr))
+#define READ_U8(addr)  __raw_readb(addr)
+#define READ_U16(addr) __raw_readw(addr)
+#define READ_U32(addr) __raw_readl(addr)
+#define WRITE_U8(value, addr)  __raw_writeb(value, addr)
+#define WRITE_U16(value, addr) __raw_writew(value, addr)
+#define WRITE_U32(value, addr) __raw_writel(value, addr)
+
+#define READ_REG8(addr)  readb(addr)
+#define READ_REG16(addr) readw(addr)
+#define READ_REG32(addr) readl(addr)
+#define READ_REG64(addr) readq(addr)
+#define WRITE_REG8(value, addr)  writeb(value, addr)
+#define WRITE_REG16(value, addr) writew(value, addr)
+#define WRITE_REG32(value, addr) writel(value, addr)
 
 
 #define LBA_CFG_TOK(bus,dfn) ((u32) ((bus)<<16 | (dfn)<<8))
@@ -253,25 +246,12 @@
 #define LBA_CFG_FUNC(tok) ((u8) ((tok)>>8 ) & 0x7)
 
 
-#ifdef DEBUG_LBA
-/* Extract LBA (Rope) number from HPA */
-#define LBA_NUM(x)    ((((uintptr_t) x) >> 13) & 0xf)
-#endif /* DEBUG_LBA */
-
-#ifdef __LP64__
-/* PDC_PAT */
-static  unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
-#endif
-
 /*
-** One time initialization to let the world know the LBA was found.
-** This is the only routine which is NOT static.
-** Must be called exactly once before pci_init().
+** Extract LBA (Rope) number from HPA
+** REVISIT: 16 ropes for Stretch/Ike?
 */
-void __init lba_init(void)
-{
-	register_driver(lba_drivers_for);
-}
+#define ROPES_PER_SBA	8
+#define LBA_NUM(x)    ((((unsigned long) x) >> 13) & (ROPES_PER_SBA-1))
 
 
 static void
@@ -282,9 +262,9 @@
 	if (NULL == r)
 		return;
 
-	printk("(%p)", r->parent);
+	printk(KERN_DEBUG "(%p)", r->parent);
 	for (i = d; i ; --i) printk(" ");
-	printk("%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags);
+	printk(KERN_DEBUG "%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags);
 	lba_dump_res(r->child, d+2);
 	lba_dump_res(r->sibling, d);
 }
@@ -369,7 +349,7 @@
      * Set the smart mode bit so that master aborts don't cause		\
      * LBA to go into PCI fatal mode (required).			\
      */									\
-    WRITE_REG32(error_config | 0x20, d->hba.base_addr + LBA_ERROR_CONFIG);	\
+    WRITE_REG32(error_config | LBA_SMART_MODE, d->hba.base_addr + LBA_ERROR_CONFIG);	\
 }
 
 
@@ -414,9 +394,9 @@
  *
  *		Actually, there is still a race in which
  *		we could be clearing a fatal error.  We will
- *		live with this during our real mode bus walk
+ *		live with this during our initial bus walk
  *		until rev 4.0 (no driver activity during
- *		real mode bus walk).  The real mode bus walk
+ *		initial bus walk).  The initial bus walk
  *		has race conditions concerning the use of
  *		smart mode as well.
  */
@@ -430,7 +410,7 @@
      * Set clear enable (CE) bit. Unset by HW when new			\
      * errors are logged -- LBA HW ERS section 14.3.3).		\
      */									\
-    WRITE_REG32(status_control | 0x20, base + LBA_STAT_CTL);	\
+    WRITE_REG32(status_control | CLEAR_ERRLOG_ENABLE, base + LBA_STAT_CTL); \
     error_status = READ_REG32(base + LBA_ERROR_STATUS);		\
     if ((error_status & 0x1f) != 0) {					\
 	/*								\
@@ -442,7 +422,7 @@
 	     * Clear error status (if fatal bit not set) by setting	\
 	     * clear error log bit (CL).				\
 	     */								\
-	    WRITE_REG32(status_control | 0x10, base + LBA_STAT_CTL);	\
+	    WRITE_REG32(status_control | CLEAR_ERRLOG, base + LBA_STAT_CTL); \
 	}								\
     }									\
 }
@@ -483,7 +463,7 @@
 
 
 static unsigned int
-lba_rd_cfg( struct lba_device *d, u32 tok, u8 reg, u32 size)
+lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size)
 {
 	u32 data = ~0;
 	int error = 0;
@@ -525,7 +505,6 @@
 }
 
 
-
 #define LBA_CFG_RD(size, mask) \
 static int lba_cfg_read##size (struct pci_dev *dev, int pos, u##size *data) \
 { \
@@ -533,17 +512,18 @@
 	u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \
 	u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \
  \
-	if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \
+/* FIXME: B2K/C3600 workaround is always use old method... */ \
+	/* if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) */ { \
 		/* original - Generate config cycle on broken elroy \
 		  with risk we will miss PCI bus errors. */ \
 		*data = (u##size) lba_rd_cfg(d, tok, pos, sizeof(u##size)); \
-		DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, *data); \
+		DBG_CFG("%s(%s+%2x) -> 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, *data); \
 		return(*data == (u##size) -1); \
 	} \
  \
 	if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) \
 	{ \
-		DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> -1 (b)\n", __FUNCTION__, dev->slot_name, pos, *data); \
+		DBG_CFG("%s(%s+%2x) -> -1 (b)\n", __FUNCTION__, dev->slot_name, pos); \
 		/* either don't want to look or know device isn't present. */ \
 		*data = (u##size) -1; \
 		return(0); \
@@ -555,7 +535,7 @@
 	*/ \
 	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \
 	*data = READ_REG##size(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask));\
-	DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, *data);\
+	DBG_CFG("%s(%s+%2x) -> 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, *data);\
 	return(*data == (u##size) -1); \
 }
 
@@ -618,19 +598,19 @@
  	ASSERT((tok & 0xff) == 0); \
 	ASSERT(pos < 0x100); \
  \
-	if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \
+	if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) { \
 		/* Original Workaround */ \
 		lba_wr_cfg(d, tok, pos, (u32) data, sizeof(u##size)); \
-		DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, data); \
+		DBG_CFG("%s(%s+%2x) = 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, data); \
 		return 0; \
 	} \
  \
 	if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) { \
-		DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (b)\n", __FUNCTION__, dev->slot_name, pos, data); \
+		DBG_CFG("%s(%s+%2x) = 0x%x (b)\n", __FUNCTION__, dev->slot_name, pos, data); \
 		return 1; /* New Workaround */ \
 	} \
  \
-	DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, data); \
+	DBG_CFG("%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, data); \
 	/* Basic Algorithm */ \
 	LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \
 	WRITE_REG##size(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask)); \
@@ -644,9 +624,12 @@
 LBA_CFG_WR(32, 0) 
 
 static struct pci_ops lba_cfg_ops = {
-        lba_cfg_read8, lba_cfg_read16, lba_cfg_read32,
-	lba_cfg_write8, lba_cfg_write16, lba_cfg_write32
-
+	read_byte:	lba_cfg_read8,
+	read_word:	lba_cfg_read16,
+	read_dword:	lba_cfg_read32,
+	write_byte:	lba_cfg_write8,
+	write_word:	lba_cfg_write16,
+	write_dword:	lba_cfg_write32
 };
 
 
@@ -654,7 +637,7 @@
 static void
 lba_bios_init(void)
 {
-	DBG(KERN_DEBUG MODULE_NAME ": lba_bios_init\n");
+	DBG(MODULE_NAME ": lba_bios_init\n");
 }
 
 
@@ -712,15 +695,15 @@
 lba_fixup_bus(struct pci_bus *bus)
 {
 	struct list_head *ln;
-        struct pci_dev *dev;
+#ifdef FBB_SUPPORT
 	u16 fbb_enable = PCI_STATUS_FAST_BACK;
 	u16 status;
-	struct lba_device *ldev = LBA_DEV(bus->sysdata);
-#ifdef __LP64__
-	int i;
 #endif
+	struct lba_device *ldev = LBA_DEV(bus->sysdata);
+	int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num);
+
 	DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n",
-				bus, bus->secondary, bus->sysdata);
+		bus, bus->secondary, bus->sysdata);
 
 	/*
 	** Properly Setup MMIO resources for this bus.
@@ -731,63 +714,119 @@
 
 		DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
 			ldev->hba.io_space.name,
-			ldev->hba.io_space.start,
-			ldev->hba.io_space.end,
+			ldev->hba.io_space.start, ldev->hba.io_space.end,
 			(int) ldev->hba.io_space.flags);
 		DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n",
-			ldev->hba.mem_space.name,
-			ldev->hba.mem_space.start,
-			ldev->hba.mem_space.end,
-			(int) ldev->hba.mem_space.flags);
+			ldev->hba.lmmio_space.name,
+			ldev->hba.lmmio_space.start, ldev->hba.lmmio_space.end,
+			(int) ldev->hba.lmmio_space.flags);
 
 		err = request_resource(&ioport_resource, &(ldev->hba.io_space));
 		if (err < 0) {
 			BUG();
 			lba_dump_res(&ioport_resource, 2);
 		}
-		err = request_resource(&iomem_resource, &(ldev->hba.mem_space));
+		err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
 		if (err < 0) {
 			BUG();
 			lba_dump_res(&iomem_resource, 2);
 		}
 
 		bus->resource[0] = &(ldev->hba.io_space);
-		bus->resource[1] = &(ldev->hba.mem_space);
+		bus->resource[1] = &(ldev->hba.lmmio_space);
+	} else {
+		/* KLUGE ALERT!
+		** PCI-PCI Bridge resource munging.
+		** This hack should go away in the near future.
+		** It's based on the Alpha port.
+		*/
+		int i;
+		u16 cmd;
+
+		for (i = 0; i < 4; i++) {
+			bus->resource[i] =
+				&bus->self->resource[PCI_BRIDGE_RESOURCES+i];
+			bus->resource[i]->name = bus->name;
+		}
+#if 0
+		bus->resource[0]->flags |= pci_bridge_check_io(bus->self);
+#else
+		bus->resource[0]->flags |= IORESOURCE_IO;
+#endif
+		bus->resource[1]->flags |= IORESOURCE_MEM;
+		bus->resource[2]->flags = 0;	/* Don't support prefetchable */
+		bus->resource[3]->flags = 0;	/* not used */
+
+		/* 
+		** If the PPB is enabled (ie already configured) then
+		** just read those values.
+		*/
+		(void) lba_cfg_read16(bus->self, PCI_COMMAND, &cmd);
+		if (cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) {
+			pci_read_bridge_bases(bus);
+		} else {
+			/* Not configured.
+			** For now, propogate HBA limits to the bus;
+			**	PCI will adjust them later.
+			*/
+			bus->resource[0]->end = ldev->hba.io_space.end;
+			bus->resource[1]->end = ldev->hba.lmmio_space.end;
+		}
+
+		/* Turn off downstream PF memory address range by default */
+		bus->resource[2]->start = 1024*1024;
+		bus->resource[2]->end = bus->resource[2]->start - 1;
 	}
 
-	list_for_each(ln, &bus->devices) {
 
-		dev = pci_dev_b(ln);
+	list_for_each(ln, &bus->devices) {
+		int i;
+		struct pci_dev *dev = pci_dev_b(ln);
 
-#ifdef __LP64__
-		/*
-		** 0-5 are the "standard PCI regions"
-		** (see comments near PCI_NUM_RESOURCES in include/linux/pci.h)
-		*/
-		for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
-			struct resource *res = &(dev->resource[i]);
+		DBG("lba_fixup_bus() %s\n", dev->name);
 
-			if (res->flags & IORESOURCE_MEM) {
-				/* "Globalize" PCI address */
-				res->start |= ldev->lmmio_base;
-				res->end   |= ldev->lmmio_base;
+		/* Virtualize Device/Bridge Resources. */
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *res = &dev->resource[i];
+
+			/* If resource not allocated - skip it */
+			if (!res->start)
+				continue;
+
+			if (res->flags & IORESOURCE_IO) {
+				DBG("lba_fixup_bus() I/O Ports [%lx/%lx] -> ",
+					res->start, res->end);
+				res->start |= lba_portbase;
+				res->end   |= lba_portbase;
+				DBG("[%lx/%lx]\n", res->start, res->end);
+			} else if (res->flags & IORESOURCE_MEM) {
+				/*
+				** Convert PCI (IO_VIEW) addresses to
+				** processor (PA_VIEW) addresses
+				 */
+				DBG("lba_fixup_bus() MMIO [%lx/%lx] -> ",
+					res->start, res->end);
+				res->start = PCI_HOST_ADDR(HBA_DATA(ldev), res->start);
+				res->end   = PCI_HOST_ADDR(HBA_DATA(ldev), res->end);
+				DBG("[%lx/%lx]\n", res->start, res->end);
 			}
 		}
-#endif
 
+#ifdef FBB_SUPPORT
 		/*
 		** If one device does not support FBB transfers,
 		** No one on the bus can be allowed to use them.
 		*/
 		(void) lba_cfg_read16(dev, PCI_STATUS, &status);
 		fbb_enable &= status;
+#endif
 
 #ifdef __LP64__
-		if (pdc_pat) {
+		if (is_pdc_pat()) {
 			/* Claim resources for PDC's devices */
 			lba_claim_dev_resources(dev);
 		}
-#endif	/* __LP64__ */
+#endif
 
                 /*
 		** P2PB's have no IRQs. ignore them.
@@ -796,12 +835,12 @@
 			continue;
 
 		/* Adjust INTERRUPT_LINE for this dev */
-		iosapic_fixup_irq(LBA_DEV(bus->sysdata)->iosapic_obj, dev);
+		iosapic_fixup_irq(ldev->iosapic_obj, dev);
 	}
 
-#if 0
+#ifdef FBB_SUPPORT
 /* FIXME/REVISIT - finish figuring out to set FBB on both
-** pbus_set_ranges() clobbers PCI_BRIDGE_CONTROL.
+** pci_setup_bridge() clobbers PCI_BRIDGE_CONTROL.
 ** Can't fixup here anyway....garr...
 */
 	if (fbb_enable) {
@@ -828,8 +867,8 @@
 
 
 struct pci_bios_ops lba_bios_ops = {
-	lba_bios_init,
-	lba_fixup_bus  /* void lba_fixup_bus(struct pci_bus *bus) */
+	init:		lba_bios_init,
+	fixup_bus:	lba_fixup_bus,
 };
 
 
@@ -853,8 +892,6 @@
 static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \
 { \
 	u##size t; \
-	ASSERT(bus != NULL); \
-	DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, bus, addr); \
 	t = READ_REG##size(LBA_ASTRO_PORT_BASE + addr); \
 	DBG_PORT(" 0x%x\n", t); \
 	return (t); \
@@ -895,8 +932,8 @@
 #define LBA_PORT_OUT(size, mask) \
 static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \
 { \
-	ASSERT(bus != NULL); \
-	DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
+	ASSERT(d != NULL); \
+	DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \
 	WRITE_REG##size(val, LBA_ASTRO_PORT_BASE + addr); \
 	if (LBA_DEV(d)->hw_rev < 3) \
 		lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \
@@ -908,13 +945,16 @@
 
 
 static struct pci_port_ops lba_astro_port_ops = {
-	lba_astro_in8, lba_astro_in16, lba_astro_in32,
-	lba_astro_out8, lba_astro_out16, lba_astro_out32
+	inb:	lba_astro_in8,
+	inw:	lba_astro_in16,
+	inl:	lba_astro_in32,
+	outb:	lba_astro_out8,
+	outw:	lba_astro_out16,
+	outl:	lba_astro_out32
 };
 
 
 #ifdef __LP64__
-
 #define PIOP_TO_GMMIO(lba, addr) \
 	((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3))
 
@@ -936,7 +976,7 @@
 { \
 	u##size t; \
 	ASSERT(bus != NULL); \
-	DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \
+	DBG_PORT("%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \
 	t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \
 	DBG_PORT(" 0x%x\n", t); \
 	return (t); \
@@ -953,7 +993,7 @@
 { \
 	void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \
 	ASSERT(bus != NULL); \
-	DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
+	DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
 	WRITE_REG##size(val, where); \
 	/* flush the I/O down to the elroy at least */ \
 	lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \
@@ -965,8 +1005,12 @@
 
 
 static struct pci_port_ops lba_pat_port_ops = {
-	lba_pat_in8, lba_pat_in16, lba_pat_in32,
-	lba_pat_out8, lba_pat_out16, lba_pat_out32
+	inb:	lba_pat_in8,
+	inw:	lba_pat_in16,
+	inl:	lba_pat_in32,
+	outb:	lba_pat_out8,
+	outw:	lba_pat_out16,
+	outl:	lba_pat_out32
 };
 
 
@@ -978,30 +1022,27 @@
 ** We don't have a struct pci_bus assigned to us yet.
 */
 static void
-lba_pat_resources( struct hp_device *d, struct lba_device *lba_dev)
+lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 {
+	unsigned long bytecnt;
 	pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;	/* PA_VIEW */
-#ifdef DONT_NEED_THIS_FOR_ASTRO
 	pdc_pat_cell_mod_maddr_block_t io_pdc_cell;	/* IO_VIEW */
 	long io_count;
-#endif
 	long status;	/* PDC return status */
 	long pa_count;
 	int i;
 
 	/* return cell module (IO view) */
-	status = pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index,
+	status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
 				PA_VIEW, & pa_pdc_cell);
 	pa_count = pa_pdc_cell.mod[1];
 
-#ifdef DONT_NEED_THIS_FOR_ASTRO
-	status |= pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index,
-				IO_VIEW, & io_pdc_cell);
+	status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
+				IO_VIEW, &io_pdc_cell);
 	io_count = io_pdc_cell.mod[1];
-#endif
 
 	/* We've already done this once for device discovery...*/
-	if (status != PDC_RET_OK) {
+	if (status != PDC_OK) {
 		panic("pdc_pat_cell_module() call failed for LBA!\n");
 	}
 
@@ -1017,10 +1058,11 @@
 			unsigned long type;
 			unsigned long start;
 			unsigned long end;	/* aka finish */
-		} *p;
+		} *p, *io;
 		struct resource *r;
 
 		p = (void *) &(pa_pdc_cell.mod[2+i*3]);
+		io = (void *) &(io_pdc_cell.mod[2+i*3]);
 
 		/* Convert the PAT range data to PCI "struct resource" */
 		switch(p->type & 0xff) {
@@ -1030,9 +1072,9 @@
 			break;
 		case PAT_LMMIO:
 			/* used to fix up pre-initialized MEM BARs */
-			lba_dev->lmmio_base = p->start;
+			lba_dev->hba.lmmio_space_offset = p->start - io->start;
 
-			r = &(lba_dev->hba.mem_space);
+			r = &(lba_dev->hba.lmmio_space);
 			r->name   = "LBA LMMIO";
 			r->start  = p->start;
 			r->end    = p->end;
@@ -1060,8 +1102,8 @@
 
 			r = &(lba_dev->hba.io_space);
 			r->name   = "LBA I/O Port";
-			r->start = lba_dev->hba.hba_num << 16;
-			r->end   = r->start + 0xffffUL;
+			r->start  = HBA_PORT_BASE(lba_dev->hba.hba_num);
+			r->end    = r->start + HBA_PORT_SPACE_SIZE - 1;
 			r->flags  = IORESOURCE_IO;
 			r->parent = r->sibling = r->child = NULL;
 			break;
@@ -1077,17 +1119,22 @@
 
 
 static void
-lba_legacy_resources( struct hp_device *d, struct lba_device *lba_dev)
+lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
 {
-	int lba_num;
 	struct resource *r;
+	unsigned long rsize;
+	int lba_num;
+
 #ifdef __LP64__
 	/*
-	** Used to sign extend instead BAR values are only 32-bit.
-	** 64-bit BARs have the upper 32-bit's zero'd by firmware.
-	** "Sprockets" PDC initializes for 32-bit OS.
+	** Sign extend all BAR values on "legacy" platforms.
+	** "Sprockets" PDC (Forte/Allegro) initializes everything
+	** for "legacy" 32-bit OS (HPUX 10.20).
+	** Upper 32-bits of 64-bit BAR will be zero too.
 	*/
-	lba_dev->lmmio_base = 0xffffffff00000000UL;
+	lba_dev->hba.lmmio_space_offset = 0xffffffff00000000UL;
+#else
+	lba_dev->hba.lmmio_space_offset = 0UL;
 #endif
 
 	/*
@@ -1097,7 +1144,7 @@
 	** PCI bus walk *should* end up with the same result.
 	** FIXME: But we don't have sanity checks in PCI or LBA.
 	*/
-	lba_num = READ_REG32(d->hpa + LBA_FW_SCRATCH);
+	lba_num = READ_REG32(pa_dev->hpa + LBA_FW_SCRATCH);
 	r = &(lba_dev->hba.bus_num);
 	r->name = "LBA PCI Busses";
 	r->start = lba_num & 0xff;
@@ -1106,19 +1153,67 @@
 	/* Set up local PCI Bus resources - we don't really need
 	** them for Legacy boxes but it's nice to see in /proc.
 	*/
-	r = &(lba_dev->hba.mem_space);
+	r = &(lba_dev->hba.lmmio_space);
 	r->name  = "LBA PCI LMMIO";
 	r->flags = IORESOURCE_MEM;
-	r->start = READ_REG32(d->hpa + LBA_LMMIO_BASE);
-	r->end   = r->start + ~ (READ_REG32(d->hpa + LBA_LMMIO_MASK));
+	/* Ignore "Range Enable" bit in the BASE register */
+	r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev),
+		((long) READ_REG32(pa_dev->hpa + LBA_LMMIO_BASE)) & ~1UL);
+	rsize =  ~READ_REG32(pa_dev->hpa + LBA_LMMIO_MASK) + 1;
+
+	/*
+	** Each rope only gets part of the distributed range.
+	** Adjust "window" for this rope
+	*/
+	rsize /= ROPES_PER_SBA;
+	r->start += rsize * LBA_NUM(pa_dev->hpa);
+	r->end = r->start + rsize - 1 ;
+
+	/*
+	** XXX FIXME - ignore LBA_ELMMIO_BASE for now
+	** "Directed" ranges are used when the "distributed range" isn't
+	** sufficient for all devices below a given LBA.  Typically devices
+	** like graphics cards or X25 may need a directed range when the
+	** bus has multiple slots (ie multiple devices) or the device
+	** needs more than the typical 4 or 8MB a distributed range offers.
+	**
+	** The main reason for ignoring it now frigging complications.
+	** Directed ranges may overlap (and have precedence) over
+	** distributed ranges. Ie a distributed range assigned to a unused
+	** rope may be used by a directed range on a different rope.
+	** Support for graphics devices may require fixing this
+	** since they may be assigned a directed range which overlaps
+	** an existing (but unused portion of) distributed range.
+	*/
+	r = &(lba_dev->hba.elmmio_space);
+	r->name  = "extra LBA PCI LMMIO";
+	r->flags = IORESOURCE_MEM;
+	r->start = READ_REG32(pa_dev->hpa + LBA_ELMMIO_BASE);
+	r->end   = 0;
+
+	/* check Range Enable bit */
+	if (r->start & 1) {
+		/* First baby step to getting Direct Ranges listed in /proc.
+		** AFAIK, only Sprockets PDC will setup a directed Range.
+		*/
+
+		r->start &= ~1;
+		r->end    = r->start;
+		r->end   += ~READ_REG32(pa_dev->hpa + LBA_ELMMIO_MASK);
+		printk(KERN_DEBUG "WARNING: Ignoring enabled ELMMIO BASE 0x%0lx  SIZE 0x%lx\n",
+			r->start,
+			r->end + 1);
+
+	}
 
 	r = &(lba_dev->hba.io_space);
 	r->name  = "LBA PCI I/O Ports";
 	r->flags = IORESOURCE_IO;
-	r->start = READ_REG32(d->hpa + LBA_IOS_BASE);
-	r->end   = r->start + (READ_REG32(d->hpa + LBA_IOS_MASK) ^ 0xffff);
+	r->start = READ_REG32(pa_dev->hpa + LBA_IOS_BASE) & ~1L;
+	r->end   = r->start + (READ_REG32(pa_dev->hpa + LBA_IOS_MASK) ^ (HBA_PORT_SPACE_SIZE - 1));
 
-	lba_num = lba_dev->hba.hba_num << 16;
+	/* Virtualize the I/O Port space ranges */
+	lba_num = HBA_PORT_BASE(lba_dev->hba.hba_num);
 	r->start |= lba_num;
 	r->end   |= lba_num;
 }
@@ -1136,29 +1231,92 @@
 **
 **************************************************************************/
 
-static void
+static int __init
 lba_hw_init(struct lba_device *d)
 {
 	u32 stat;
+	u32 bus_reset;	/* PDC_PAT_BUG */
+
+#if 0
+	printk(KERN_DEBUG "LBA %lx  STAT_CTL %Lx  ERROR_CFG %Lx  STATUS %Lx DMA_CTL %Lx\n",
+		d->hba.base_addr,
+		READ_REG64(d->hba.base_addr + LBA_STAT_CTL),
+		READ_REG64(d->hba.base_addr + LBA_ERROR_CONFIG),
+		READ_REG64(d->hba.base_addr + LBA_ERROR_STATUS),
+		READ_REG64(d->hba.base_addr + LBA_DMA_CTL) );
+	printk(KERN_DEBUG "	ARB mask %Lx  pri %Lx  mode %Lx  mtlt %Lx\n",
+		READ_REG64(d->hba.base_addr + LBA_ARB_MASK),
+		READ_REG64(d->hba.base_addr + LBA_ARB_PRI),
+		READ_REG64(d->hba.base_addr + LBA_ARB_MODE),
+		READ_REG64(d->hba.base_addr + LBA_ARB_MTLT) );
+	printk(KERN_DEBUG "	HINT cfg 0x%Lx\n",
+		READ_REG64(d->hba.base_addr + LBA_HINT_CFG));
+	printk(KERN_DEBUG "	HINT reg ");
+	{ int i;
+	for (i=LBA_HINT_BASE; i< (14*8 + LBA_HINT_BASE); i+=8)
+		printk(" %Lx", READ_REG64(d->hba.base_addr + i));
+	}
+	printk("\n");
+#endif	/* DEBUG_LBA_PAT */
+
+#ifdef __LP64__
+#warning FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support
+#endif
+
+	/* PDC_PAT_BUG: exhibited in rev 40.48  on L2000 */
+	bus_reset = READ_REG32(d->hba.base_addr + LBA_STAT_CTL + 4) & 1;
+	if (bus_reset) {
+		printk(KERN_DEBUG "NOTICE: PCI bus reset still asserted! (clearing)\n");
+	}
+
+	stat = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG);
+	if (stat & LBA_SMART_MODE) {
+		printk(KERN_DEBUG "NOTICE: LBA in SMART mode! (cleared)\n");
+		stat &= ~LBA_SMART_MODE;
+		WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG);
+	}
 
 	/* Set HF mode as the default (vs. -1 mode). */
         stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);
 	WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
 
 	/*
+	** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal
+	** if it's not already set. If we just cleared the PCI Bus Reset
+	** signal, wait a bit for the PCI devices to recover and setup.
+	*/
+	if (bus_reset)
+		mdelay(pci_post_reset_delay);
+
+	if (0 == READ_REG32(d->hba.base_addr + LBA_ARB_MASK)) {
+		/*
+		** PDC_PAT_BUG: PDC rev 40.48 on L2000.
+		** B2000/C3600/J6000 also have this problem?
+		** 
+		** Elroys with hot pluggable slots don't get configured
+		** correctly if the slot is empty.  ARB_MASK is set to 0
+		** and we can't master transactions on the bus if it's
+		** not at least one. 0x3 enables elroy and first slot.
+		*/
+		printk(KERN_DEBUG "NOTICE: Enabling PCI Arbitration\n");
+		WRITE_REG32(0x3, d->hba.base_addr + LBA_ARB_MASK);
+	}
+
+	/*
 	** FIXME: Hint registers are programmed with default hint
 	** values by firmware. Hints should be sane even if we
 	** can't reprogram them the way drivers want.
 	*/
+	return 0;
 }
 
 
 
-static void
+static void __init
 lba_common_init(struct lba_device *lba_dev)
 {
 	pci_bios = &lba_bios_ops;
-	pcibios_register_hba((struct pci_hba_data *)lba_dev);
+	pcibios_register_hba(HBA_DATA(lba_dev));
 	lba_dev->lba_lock = SPIN_LOCK_UNLOCKED;	
 
 	/*
@@ -1176,32 +1334,31 @@
 ** If so, initialize the chip and tell other partners in crime they
 ** have work to do.
 */
-static __init int
-lba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+static int __init
+lba_driver_callback(struct parisc_device *dev)
 {
 	struct lba_device *lba_dev;
 	struct pci_bus *lba_bus;
 	u32 func_class;
 	void *tmp_obj;
-
-	/* from drivers/pci/setup-bus.c */
-	extern void __init pbus_set_ranges(struct pci_bus *, struct pbus_set_ranges_data *);
+	char *version;
 
 	/* Read HW Rev First */
-	func_class = READ_REG32(d->hpa + LBA_FCLASS);
+	func_class = READ_REG32(dev->hpa + LBA_FCLASS);
 	func_class &= 0xf;
 
 	switch (func_class) {
-	case 0:	dri->version = "TR1.0"; break;
-	case 1:	dri->version = "TR2.0"; break;
-	case 2:	dri->version = "TR2.1"; break;
-	case 3:	dri->version = "TR2.2"; break;
-	case 4:	dri->version = "TR3.0"; break;
-	case 5:	dri->version = "TR4.0"; break;
-	default: dri->version = "TR4+";
+	case 0:	version = "TR1.0"; break;
+	case 1:	version = "TR2.0"; break;
+	case 2:	version = "TR2.1"; break;
+	case 3:	version = "TR2.2"; break;
+	case 4:	version = "TR3.0"; break;
+	case 5:	version = "TR4.0"; break;
+	default: version = "TR4+";
 	}
 
-	printk("%s version %s (0x%x) found at 0x%p\n", dri->name, dri->version, func_class & 0xf, d->hpa);
+	printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
+		MODULE_NAME, version, func_class & 0xf, dev->hpa);
 
 	/* Just in case we find some prototypes... */
 	if (func_class < 2) {
@@ -1212,22 +1369,16 @@
 	/*
 	** Tell I/O SAPIC driver we have a IRQ handler/region.
 	*/
-	tmp_obj = iosapic_register(d->hpa+LBA_IOSAPIC_BASE);
-	if (NULL == tmp_obj) {
-		/* iosapic may have failed. But more likely the
-		** slot isn't occupied and thus has no IRT entries.
-		** iosapic_register looks for this iosapic in the IRT
-		** before bothering to allocating data structures
-		** we don't need.
-		*/
-		DBG(KERN_WARNING MODULE_NAME ": iosapic_register says not used\n");
-		return (1);
-	}
+	tmp_obj = iosapic_register(dev->hpa + LBA_IOSAPIC_BASE);
 
+	/* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't
+	**	have an IRT entry will get NULL back from iosapic code.
+	*/
+	
 	lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL);
 	if (NULL == lba_dev)
 	{
-		printk("lba_init_chip - couldn't alloc lba_device\n");
+		printk(KERN_ERR "lba_init_chip - couldn't alloc lba_device\n");
 		return(1);
 	}
 
@@ -1242,48 +1393,45 @@
 	*/
 	lba_dev->hw_rev = func_class;
 
-	lba_dev->hba.base_addr = d->hpa;  /* faster access */
+	lba_dev->hba.base_addr = dev->hpa;  /* faster access */
+	lba_dev->hba.dev = dev;
 	lba_dev->iosapic_obj = tmp_obj;  /* save interrupt handle */
+	lba_dev->hba.iommu = sba_get_iommu(dev);  /* get iommu data */
 
 	/* ------------ Second : initialize common stuff ---------- */
 	lba_common_init(lba_dev);
-	lba_hw_init(lba_dev);
+
+	if (lba_hw_init(lba_dev))
+		return(1);
 
 	/* ---------- Third : setup I/O Port and MMIO resources  --------- */
-#ifdef __LP64__
 
-	if (pdc_pat) {
+#ifdef __LP64__
+	if (is_pdc_pat()) {
 		/* PDC PAT firmware uses PIOP region of GMMIO space. */
 		pci_port = &lba_pat_port_ops;
 
 		/* Go ask PDC PAT what resources this LBA has */
-		lba_pat_resources(d, lba_dev);
-
-	} else {
+		lba_pat_resources(dev, lba_dev);
+	} else
 #endif
+	{
 		/* Sprockets PDC uses NPIOP region */
 		pci_port = &lba_astro_port_ops;
 
 		/* Poke the chip a bit for /proc output */
-		lba_legacy_resources(d, lba_dev);
-#ifdef __LP64__
+		lba_legacy_resources(dev, lba_dev);
 	}
-#endif
 
 	/* 
 	** Tell PCI support another PCI bus was found.
 	** Walks PCI bus for us too.
 	*/
 	lba_bus = lba_dev->hba.hba_bus =
-		pci_scan_bus( lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev);
+		pci_scan_bus(lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev);
 
 #ifdef __LP64__
-	if (pdc_pat) {
-
-		/* determine window sizes needed by PCI-PCI bridges */
-		DBG_PAT("LBA pcibios_size_bridge()\n");
-		pcibios_size_bridge(lba_bus, NULL);
-
+	if (is_pdc_pat()) {
 		/* assign resources to un-initialized devices */
 		DBG_PAT("LBA pcibios_assign_unassigned_resources()\n");
 		pcibios_assign_unassigned_resources(lba_bus);
@@ -1292,14 +1440,10 @@
 		DBG_PAT("\nLBA PIOP resource tree\n");
 		lba_dump_res(&lba_dev->hba.io_space, 2);
 		DBG_PAT("\nLBA LMMIO resource tree\n");
-		lba_dump_res(&lba_dev->hba.mem_space, 2);
+		lba_dump_res(&lba_dev->hba.lmmio_space, 2);
 #endif
-
-		/* program *all* PCI-PCI bridge range registers */
-		DBG_PAT("LBA pbus_set_ranges()\n");
-		pbus_set_ranges(lba_bus, NULL);
 	}
-#endif /* __LP64__ */
+#endif
 
 	/*
 	** Once PCI register ops has walked the bus, access to config
@@ -1314,33 +1458,43 @@
 	return 0;
 }
 
+static struct parisc_device_id lba_tbl[] = {
+	{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x782, 0xa },
+	{ 0, }
+};
+
+static struct parisc_driver lba_driver = {
+	name:		MODULE_NAME,
+	id_table:	lba_tbl,
+	probe:		lba_driver_callback
+};
+
+/*
+** One time initialization to let the world know the LBA was found.
+** Must be called exactly once before pci_init().
+*/
+void __init lba_init(void)
+{
+	register_parisc_driver(&lba_driver);
+}
 
 /*
 ** Initialize the IBASE/IMASK registers for LBA (Elroy).
-** Only called from sba_iommu.c initialization sequence.
+** Only called from sba_iommu.c in order to route ranges (MMIO vs DMA).
+** sba_iommu is responsible for locking (none needed at init time).
 */
-void lba_init_iregs(void *sba_hpa, u32 ibase, u32 imask)
+void
+lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
 {
-	extern struct pci_hba_data *hba_list;	/* arch/parisc/kernel/pci.c */
-	struct pci_hba_data *lba;
+	unsigned long base_addr = lba->hpa;
 
 	imask <<= 2;	/* adjust for hints - 2 more bits */
 
 	ASSERT((ibase & 0x003fffff) == 0);
 	ASSERT((imask & 0x003fffff) == 0);
 	
-	/* FIXME: sba_hpa is intended to search some table to
-	**      determine which LBA's belong to the caller's SBA.
-	** IS_ASTRO: just assume only one SBA for now.
-	*/
-	ASSERT(NULL != hba_list);
-	DBG(KERN_DEBUG "%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);
-
-	for (lba = hba_list; NULL != lba; lba = lba->next) {
-		DBG(KERN_DEBUG "%s() base_addr %p\n", __FUNCTION__, lba->base_addr);
-		WRITE_REG32( imask, lba->base_addr + LBA_IMASK);
-		WRITE_REG32( ibase, lba->base_addr + LBA_IBASE);
-	}
-	DBG(KERN_DEBUG "%s() done\n", __FUNCTION__);
+	DBG("%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);
+	WRITE_REG32( imask, base_addr + LBA_IMASK);
+	WRITE_REG32( ibase, base_addr + LBA_IBASE);
 }
 
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/led.c linux-2.4.20-pre2/arch/parisc/kernel/led.c
--- linux-2.4.20-pre1/arch/parisc/kernel/led.c	Wed Dec  6 11:46:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/led.c	Mon Aug 12 16:34:14 2002
@@ -3,34 +3,64 @@
  *
  *      (c) Copyright 2000 Red Hat Software
  *      (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
+ *      (c) Copyright 2001-2002 Helge Deller <deller@gmx.de>
+ *      (c) Copyright 2001 Randolph Chung <tausq@debian.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.
  *
+ * TODO:
+ *	- speed-up calculations with inlined assembler
+ *	- interface to write to second row of LCD from /proc
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
+#include <linux/stddef.h>	/* for offsetof() */
 #include <linux/init.h>
-#include <linux/kernel_stat.h>
 #include <linux/types.h>
-#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/bitops.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/reboot.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
 #include <asm/io.h>
 #include <asm/gsc.h>
 #include <asm/processor.h>
 #include <asm/hardware.h>
 #include <asm/param.h>		/* HZ */
 #include <asm/led.h>
+#include <asm/pdc.h>
+#include <asm/uaccess.h>
 
+/* The control of the LEDs and LCDs on PARISC-machines have to be done 
+   completely in software. The necessary calculations are done in a tasklet
+   which is scheduled at every timer interrupt and since the calculations 
+   may consume relatively much CPU-time some of the calculations can be 
+   turned off with the following variables (controlled via procfs) */
+
+static int led_type = -1;
+static int led_heartbeat = 1;
+static int led_diskio = 1;
+static int led_lanrxtx = 1;
+static char lcd_text[32];
 
-/* define to disable all LED functions */
-#undef  DISABLE_LEDS
+#if 0
+#define DPRINTK(x)	printk x
+#else
+#define DPRINTK(x)
+#endif
 
 
-#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF)
+#define CALC_ADD(val, comp, add) \
+ (val<=(comp/8) ? add/16 : val<=(comp/4) ? add/8 : val<=(comp/2) ? add/4 : add)
 
 
 struct lcd_block {
@@ -40,8 +70,10 @@
 };
 
 /* Structure returned by PDC_RETURN_CHASSIS_INFO */
+/* NOTE: we use unsigned long:16 two times, since the following member 
+   lcd_cmd_reg_addr needs to be 64bit aligned on 64bit PA2.0-machines */
 struct pdc_chassis_lcd_info_ret_block {
-	unsigned long model:16;		/* DISPLAY_MODEL_XXXX (see below)  */
+	unsigned long model:16;		/* DISPLAY_MODEL_XXXX */
 	unsigned long lcd_width:16;	/* width of the LCD in chars (DISPLAY_MODEL_LCD only) */
 	char *lcd_cmd_reg_addr;		/* ptr to LCD cmd-register & data ptr for LED */
 	char *lcd_data_reg_addr;	/* ptr to LCD data-register (LCD only) */
@@ -56,33 +88,23 @@
 	char _pad;
 };
 
-/* values for pdc_chassis_lcd_info_ret_block.model: */
-#define DISPLAY_MODEL_LCD  0	/* KittyHawk LED or LCD */
-#define DISPLAY_MODEL_NONE 1	/* no LED or LCD */
-#define DISPLAY_MODEL_LASI 2	/* LASI style 8 bit LED */
-#define DISPLAY_MODEL_OLD_ASP 0x7F /* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */
-
 
 /* LCD_CMD and LCD_DATA for KittyHawk machines */
-#ifdef __LP64__
-#define KITTYHAWK_LCD_CMD 0xfffffffff0190000L
-#else
-#define KITTYHAWK_LCD_CMD 0xf0190000
-#endif
-#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD + 1)
+#define KITTYHAWK_LCD_CMD  (0xfffffffff0190000UL) /* 64bit-ready */
+#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1)
 
-
-/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's */
+/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's 
+ * HP seems to have used Sharp/Hitachi HD44780 LCDs most of the time. */
 static struct pdc_chassis_lcd_info_ret_block
 lcd_info __attribute__((aligned(8))) =
 {
-      model:DISPLAY_MODEL_LCD,
-      lcd_width:16,
-      lcd_cmd_reg_addr:(char *) KITTYHAWK_LCD_CMD,
+      model:		DISPLAY_MODEL_LCD,
+      lcd_width:	16,
+      lcd_cmd_reg_addr:	(char *) KITTYHAWK_LCD_CMD,
       lcd_data_reg_addr:(char *) KITTYHAWK_LCD_DATA,
-      min_cmd_delay:40,
-      reset_cmd1:0x80,
-      reset_cmd2:0xc0,
+      min_cmd_delay:	40,
+      reset_cmd1:	0x80,
+      reset_cmd2:	0xc0,
 };
 
 
@@ -92,7 +114,143 @@
 #define LED_DATA_REG	lcd_info.lcd_cmd_reg_addr	/* LASI & ASP only */
 
 
+/* ptr to LCD/LED-specific function */
+static void (*led_func_ptr) (unsigned char);
+
+#define LED_HASLCD 1
+#define LED_NOLCD  0
+#ifdef CONFIG_PROC_FS
+static int led_proc_read(char *page, char **start, off_t off, int count, 
+	int *eof, void *data)
+{
+	char *out = page;
+	int len;
+
+	switch ((long)data)
+	{
+	case LED_NOLCD:
+		out += sprintf(out, "Heartbeat: %d\n", led_heartbeat);
+		out += sprintf(out, "Disk IO: %d\n", led_diskio);
+		out += sprintf(out, "LAN Rx/Tx: %d\n", led_lanrxtx);
+		break;
+	case LED_HASLCD:
+		out += sprintf(out, "%s\n", lcd_text);
+		break;
+	default:
+		*eof = 1;
+		return 0;
+	}
+
+	len = out - page - off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else {
+		len = count;
+	}
+	*start = page + off;
+	return len;
+}
+
+static int led_proc_write(struct file *file, const char *buf, 
+	unsigned long count, void *data)
+{
+	char *cur, lbuf[count];
+	int d;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	memset(lbuf, 0, count);
+
+	copy_from_user(lbuf, buf, count);
+	cur = lbuf;
+
+	/* skip initial spaces */
+	while (*cur && isspace(*cur))
+	{
+		cur++;
+	}
+
+	switch ((long)data)
+	{
+	case LED_NOLCD:
+		d = *cur++ - '0';
+		if (d != 0 && d != 1) goto parse_error;
+		led_heartbeat = d;
+
+		if (*cur++ != ' ') goto parse_error;
+
+		d = *cur++ - '0';
+		if (d != 0 && d != 1) goto parse_error;
+		led_diskio = d;
+
+		if (*cur++ != ' ') goto parse_error;
+
+		d = *cur++ - '0';
+		if (d != 0 && d != 1) goto parse_error;
+		led_lanrxtx = d;
+
+		break;
+	case LED_HASLCD:
+		if (*cur == 0) 
+		{
+			/* reset to default */
+			lcd_print("Linux " UTS_RELEASE);
+		}
+		else
+		{
+			/* chop off trailing \n.. if the user gives multiple
+			 * \n then it's all their fault.. */
+			if (*cur && cur[strlen(cur)-1] == '\n')
+				cur[strlen(cur)-1] = 0;
+			lcd_print(cur);
+		}
+		break;
+	default:
+		return 0;
+	}
+	
+	return count;
+
+parse_error:
+	if ((long)data == LED_NOLCD)
+		printk(KERN_CRIT "Parse error: expect \"n n n\" (n == 0 or 1) for heartbeat,\ndisk io and lan tx/rx indicators\n");
+	return -EINVAL;
+}
+
+static int __init led_create_procfs(void)
+{
+	struct proc_dir_entry *proc_pdc_root = NULL;
+	struct proc_dir_entry *ent;
+
+	if (led_type == -1) return -1;
+
+	proc_pdc_root = proc_mkdir("pdc", 0);
+	if (!proc_pdc_root) return -1;
+	proc_pdc_root->owner = THIS_MODULE;
+	ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
+	if (!ent) return -1;
+	ent->nlink = 1;
+	ent->data = (void *)LED_NOLCD; /* LED */
+	ent->read_proc = led_proc_read;
+	ent->write_proc = led_proc_write;
+	ent->owner = THIS_MODULE;
+
+	if (led_type == LED_HASLCD)
+	{
+		ent = create_proc_entry("lcd", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
+		if (!ent) return -1;
+		ent->nlink = 1;
+		ent->data = (void *)LED_HASLCD; /* LCD */
+		ent->read_proc = led_proc_read;
+		ent->write_proc = led_proc_write;
+		ent->owner = THIS_MODULE;
+	}
 
+	return 0;
+}
+#endif
 
 /*
    ** 
@@ -132,24 +290,20 @@
    ** 
    ** led_LCD_driver()
    ** 
-   ** The logic of the LCD driver is, that we write at every interrupt
+   ** The logic of the LCD driver is, that we write at every scheduled call
    ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers.
-   ** That way we don't need to let this interrupt routine busywait
-   ** the "min_cmd_delay", since idlewaiting in an interrupt-routine is
-   ** allways a BAD IDEA !
+   ** That way we don't need to let this tasklet busywait for min_cmd_delay
+   ** milliseconds.
    **
    ** TODO: check the value of "min_cmd_delay" against the value of HZ.
    **   
  */
-
 static void led_LCD_driver(unsigned char leds)
 {
 	static int last_index;	/* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */
 	static int last_was_cmd;/* 0: CMD was written last, 1: DATA was last */
 	struct lcd_block *block_ptr;
 	int value;
-	
- 	// leds = ~leds;	/* needed ? */ 
 
 	switch (last_index) {
 	    case 0:	block_ptr = &lcd_info.heartbeat;
@@ -165,7 +319,6 @@
 			value = leds & LED_LAN_TX;
 			break;
 	    default:	/* should never happen: */
-			BUG();
 			return;
 	}
 
@@ -178,179 +331,293 @@
 	}    
 	
 	/* now update the vars for the next interrupt iteration */ 
-	if (++last_was_cmd == 2) {
+	if (++last_was_cmd == 2) { /* switch between cmd & data */
 	    last_was_cmd = 0;
-	    if (++last_index == 4)
-		last_index = 0;
+	    if (++last_index == 4) 
+		last_index = 0;	 /* switch back to heartbeat index */
 	}
 }
 
 
+/*
+   ** 
+   ** led_get_net_stats()
+   ** 
+   ** calculate the TX- & RX-troughput on the network interfaces in
+   ** the system for usage in the LED code
+   **
+   ** (analog to dev_get_info() from net/core/dev.c)
+   **   
+ */
+static unsigned long led_net_rx_counter, led_net_tx_counter;
+
+static void led_get_net_stats(int addvalue)
+{
+	static unsigned long rx_total_last, tx_total_last;
+	unsigned long rx_total, tx_total;
+	struct net_device *dev;
+	struct net_device_stats *stats;
+
+	rx_total = tx_total = 0;
+	
+	/* we are running as a tasklet, so locking dev_base 
+	 * for reading should be OK */
+	read_lock(&dev_base_lock);
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	    if (dev->get_stats) { 
+	        stats = dev->get_stats(dev);
+		rx_total += stats->rx_packets;
+		tx_total += stats->tx_packets;
+	    }
+	}
+	read_unlock(&dev_base_lock);
 
-static char currentleds;	/* stores current value of the LEDs */
+	rx_total -= rx_total_last;
+	tx_total -= tx_total_last;
+	
+	if (rx_total)
+	    led_net_rx_counter += CALC_ADD(rx_total, tx_total, addvalue);
+
+	if (tx_total)
+	    led_net_tx_counter += CALC_ADD(tx_total, rx_total, addvalue);
+        
+	rx_total_last += rx_total;
+        tx_total_last += tx_total;
+}
 
-static void (*led_func_ptr) (unsigned char); /* ptr to LCD/LED-specific function */
 
 /*
-   ** led_interrupt_func()
    ** 
-   ** is called at every timer interrupt from time.c,
+   ** led_get_diskio_stats()
+   ** 
+   ** calculate the disk-io througput in the system
+   ** (analog to linux/fs/proc/proc_misc.c)
+   **   
+ */
+static unsigned long led_diskio_counter;
+
+static void led_get_diskio_stats(int addvalue)
+{	
+	static unsigned int diskio_total_last, diskio_max;
+	int major, disk, total;
+	
+	total = 0;
+	for (major = 0; major < DK_MAX_MAJOR; major++) {
+	    for (disk = 0; disk < DK_MAX_DISK; disk++)
+		total += kstat.dk_drive[major][disk];
+	}
+	total -= diskio_total_last;
+	
+	if (total) {
+	    if (total >= diskio_max) {
+		led_diskio_counter += addvalue;
+	        diskio_max = total; /* new maximum value found */ 
+	    } else
+		led_diskio_counter += CALC_ADD(total, diskio_max, addvalue);
+	}
+	
+	diskio_total_last += total; 
+}
+
+
+
+/*
+   ** led_tasklet_func()
+   ** 
+   ** is scheduled at every timer interrupt from time.c and
    ** updates the chassis LCD/LED 
+
+    TODO:
+    - display load average (older machines like 715/64 have 4 "free" LED's for that)
+    - optimizations
  */
 
-#define HEARTBEAT_LEN	(HZ/16)
+static unsigned char currentleds;	/* stores current value of the LEDs */
+
+#define HEARTBEAT_LEN (HZ*6/100)
+#define HEARTBEAT_2ND_RANGE_START (HZ*22/100)
+#define HEARTBEAT_2ND_RANGE_END   (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
 
-void led_interrupt_func(void)
+static void led_tasklet_func(unsigned long unused)
 {
-#ifndef DISABLE_LEDS
-	static int count;
-	static int lastleds = -1;
-	static int nr;
+	static unsigned int count, count_HZ;
+	static unsigned char lastleds;
 
-	/* exit, if not initialized */
+	/* exit if not initialized */
 	if (!led_func_ptr)
 	    return;
-	
-	/* increment the local counter */
-	if (count == (HZ-1))
-	    count = 0;
-	else
-	    count++;
 
-	/* calculate the Heartbeat */
-	if ((count % (HZ/2)) < HEARTBEAT_LEN) 
-	    currentleds |= LED_HEARTBEAT;
-	else
-	    currentleds &= ~LED_HEARTBEAT;
+	/* increment the local counters */
+	++count;
+	if (++count_HZ == HZ)
+	    count_HZ = 0;
+
+	if (led_heartbeat)
+	{
+		/* flash heartbeat-LED like a real heart (2 x short then a long delay) */
+		if (count_HZ<HEARTBEAT_LEN || 
+		    (count_HZ>=HEARTBEAT_2ND_RANGE_START && count_HZ<HEARTBEAT_2ND_RANGE_END)) 
+		    currentleds |= LED_HEARTBEAT;
+		else
+		    currentleds &= ~LED_HEARTBEAT;
+	}
+
+	/* gather network and diskio statistics and flash LEDs respectively */
+
+	if (led_lanrxtx)
+	{
+		if ((count & 31) == 0)
+			led_get_net_stats(30);
+
+		if (led_net_rx_counter) {
+			led_net_rx_counter--;
+			currentleds |= LED_LAN_RCV;
+		}
+		else    
+			currentleds &= ~LED_LAN_RCV;
+
+		if (led_net_tx_counter) {
+			led_net_tx_counter--;
+			currentleds |= LED_LAN_TX;
+		}
+		else    
+			currentleds &= ~LED_LAN_TX;
+	}
 
-	/* roll LEDs 0..2 */
-	if (count == 0) {
-	    if (nr++ >= 2) 
-		nr = 0;
-	    currentleds &= ~7;
-	    currentleds |= (1 << nr);
+	if (led_diskio)
+	{
+		/* avoid to calculate diskio-stats at same irq as netio-stats ! */
+		if ((count & 31) == 15) 
+			led_get_diskio_stats(30);
+
+		if (led_diskio_counter) {
+			led_diskio_counter--;
+			currentleds |= LED_DISK_IO;
+		}
+		else    
+			currentleds &= ~LED_DISK_IO;
 	}
 
-	/* now update the LEDs */
+	/* update the LCD/LEDs */
 	if (currentleds != lastleds) {
 	    led_func_ptr(currentleds);
 	    lastleds = currentleds;
 	}
-#endif
 }
 
+/* main led tasklet struct (scheduled from time.c) */
+DECLARE_TASKLET_DISABLED(led_tasklet, led_tasklet_func, 0);
+
+
+/*
+   ** led_halt()
+   ** 
+   ** called by the reboot notifier chain at shutdown and stops all
+   ** LED/LCD activities.
+   ** 
+ */
+
+static int led_halt(struct notifier_block *, unsigned long, void *);
+
+static struct notifier_block led_notifier = {
+	notifier_call: led_halt,
+};
+
+static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) 
+{
+	char *txt;
+	
+	switch (event) {
+	case SYS_RESTART:	txt = "SYSTEM RESTART";
+				break;
+	case SYS_HALT:		txt = "SYSTEM HALT";
+				break;
+	case SYS_POWER_OFF:	txt = "SYSTEM POWER OFF";
+				break;
+	default:		return NOTIFY_DONE;
+	}
+	
+	/* completely stop the LED/LCD tasklet */
+	tasklet_disable(&led_tasklet);
+
+	if (lcd_info.model == DISPLAY_MODEL_LCD)
+		lcd_print(txt);
+	else
+		if (led_func_ptr)
+			led_func_ptr(0xff); /* turn all LEDs ON */
+	
+	unregister_reboot_notifier(&led_notifier);
+	return NOTIFY_OK;
+}
 
 /*
    ** register_led_driver()
    ** 
-   ** All information in lcd_info needs to be set up prior
-   ** calling this function. 
+   ** registers an external LED or LCD for usage by this driver.
+   ** currently only LCD-, LASI- and ASP-style LCD/LED's are supported.
+   ** 
  */
 
-static void __init register_led_driver(void)
+int __init register_led_driver(int model, char *cmd_reg, char *data_reg)
 {
-#ifndef DISABLE_LEDS
+	static int initialized;
+	
+	if (initialized || !data_reg)
+	    return 1;
+	
+	lcd_info.model = model;		/* store the values */
+	LCD_CMD_REG = (cmd_reg == LED_CMD_REG_NONE) ? NULL : cmd_reg;
+
 	switch (lcd_info.model) {
 	case DISPLAY_MODEL_LCD:
-		printk(KERN_INFO "LCD display at (%p,%p)\n",
-		  LCD_CMD_REG , LCD_DATA_REG);
+		LCD_DATA_REG = data_reg;
+		printk(KERN_INFO "LCD display at %p,%p registered\n", 
+			LCD_CMD_REG , LCD_DATA_REG);
 		led_func_ptr = led_LCD_driver;
+		lcd_print( "Linux " UTS_RELEASE );
+		led_type = LED_HASLCD;
 		break;
 
 	case DISPLAY_MODEL_LASI:
-		printk(KERN_INFO "LED display at %p\n",
-		       LED_DATA_REG);
+		LED_DATA_REG = data_reg;
 		led_func_ptr = led_LASI_driver;
+		printk(KERN_INFO "LED display at %p registered\n", LED_DATA_REG);
+		led_type = LED_NOLCD;
 		break;
 
 	case DISPLAY_MODEL_OLD_ASP:
-		printk(KERN_INFO "LED (ASP-style) display at %p\n",
-		       LED_DATA_REG);
+		LED_DATA_REG = data_reg;
 		led_func_ptr = led_ASP_driver;
+		printk(KERN_INFO "LED (ASP-style) display at %p registered\n", 
+		    LED_DATA_REG);
+		led_type = LED_NOLCD;
 		break;
 
 	default:
 		printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n",
 		       __FUNCTION__, lcd_info.model);
-		return;
+		return 1;
 	}
-#endif
-}
-
-/*
- * XXX - could this move to lasi.c ??
- */
-
-/*
-   ** lasi_led_init()
-   ** 
-   ** lasi_led_init() is called from lasi.c with the base hpa  
-   ** of the lasi controller chip. 
-   ** Since Mirage and Electra machines use a different LED
-   ** address register, we need to check for these machines 
-   ** explicitly.
- */
-
-#ifdef CONFIG_GSC_LASI
-void __init lasi_led_init(unsigned long lasi_hpa)
-{
-	if (lcd_info.model != DISPLAY_MODEL_NONE ||
-	    lasi_hpa == 0)
-		return;
-
-	printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION);
-
-	/* Mirage and Electra machines need special offsets */
-	switch (CPU_HVERSION) {
-	case 0x60A:		/* Mirage Jr (715/64) */
-	case 0x60B:		/* Mirage 100 */
-	case 0x60C:		/* Mirage 100+ */
-	case 0x60D:		/* Electra 100 */
-	case 0x60E:		/* Electra 120 */
-		LED_DATA_REG = (char *) (lasi_hpa - 0x00020000);
-		break;
-	default:
-		LED_DATA_REG = (char *) (lasi_hpa + 0x0000C000);
-		break;
-	}			/* switch() */
-
-	lcd_info.model = DISPLAY_MODEL_LASI;
-	register_led_driver();
-}
-#endif
-
-
-/*
-   ** asp_led_init()
-   ** 
-   ** asp_led_init() is called from asp.c with the ptr 
-   ** to the LED display.
- */
-
-#ifdef CONFIG_GSC_LASI
-void __init asp_led_init(unsigned long led_ptr)
-{
-	if (lcd_info.model != DISPLAY_MODEL_NONE ||
-	    led_ptr == 0)
-		return;
-
-	lcd_info.model = DISPLAY_MODEL_OLD_ASP;
-	LED_DATA_REG = (char *) led_ptr;
+	
+	/* mark the LCD/LED driver now as initialized and 
+	 * register to the reboot notifier chain */
+	initialized++;
+	register_reboot_notifier(&led_notifier);
 
-	register_led_driver();
+	/* start the led tasklet for the first time */
+	tasklet_enable(&led_tasklet);
+	
+	return 0;
 }
 
-#endif
-
-
-
 /*
    ** register_led_regions()
    ** 
-   ** Simple function, which registers the LCD/LED regions for /procfs.
+   ** register_led_regions() registers the LCD/LED regions for /procfs.
    ** At bootup - where the initialisation of the LCD/LED normally happens - 
    ** not all internal structures of request_region() are properly set up,
-   ** so that we delay the registration until busdevice.c is executed.
+   ** so that we delay the led-registration until after busdevices_init() 
+   ** has been executed.
    **
  */
 
@@ -358,17 +625,57 @@
 {
 	switch (lcd_info.model) {
 	case DISPLAY_MODEL_LCD:
-		request_region((unsigned long)LCD_CMD_REG,  1, "lcd_cmd");
-		request_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
+		request_mem_region((unsigned long)LCD_CMD_REG,  1, "lcd_cmd");
+		request_mem_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
 		break;
 	case DISPLAY_MODEL_LASI:
 	case DISPLAY_MODEL_OLD_ASP:
-		request_region((unsigned long)LED_DATA_REG, 1, "led_data");
+		request_mem_region((unsigned long)LED_DATA_REG, 1, "led_data");
 		break;
 	}
 }
 
 
+/*
+   ** 
+   ** lcd_print()
+   ** 
+   ** Displays the given string on the LCD-Display of newer machines.
+   ** lcd_print() disables the timer-based led tasklet during its 
+   ** execution and enables it afterwards again.
+   **
+ */
+int lcd_print( char *str )
+{
+	int i;
+
+	if (!led_func_ptr || lcd_info.model != DISPLAY_MODEL_LCD)
+	    return 0;
+	
+	/* temporarily disable the led tasklet */
+	tasklet_disable(&led_tasklet);
+
+	/* copy display string to buffer for procfs */
+	strncpy(lcd_text, str, sizeof(lcd_text)-1);
+	
+	/* Set LCD Cursor to 1st character */
+	gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG);
+	udelay(lcd_info.min_cmd_delay);
+
+	/* Print the string */
+	for (i=0; i < lcd_info.lcd_width; i++) {
+	    if (str && *str)
+		gsc_writeb(*str++, LCD_DATA_REG);
+	    else
+		gsc_writeb(' ', LCD_DATA_REG);
+	    udelay(lcd_info.min_cmd_delay);
+	}
+	
+	/* re-enable the led tasklet */
+	tasklet_enable(&led_tasklet);
+
+	return lcd_info.lcd_width;
+}
 
 /*
    ** led_init()
@@ -384,10 +691,8 @@
 
 int __init led_init(void)
 {
-#ifndef DISABLE_LEDS
-	long pdc_result[32];
-
-	printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION);
+	struct pdc_chassis_info chassis_info;
+	int ret;
 
 	/* Work around the buggy PDC of KittyHawk-machines */
 	switch (CPU_HVERSION) {
@@ -396,56 +701,74 @@
 	case 0x582:		/* KittyHawk DC3 100 (K400) */
 	case 0x583:		/* KittyHawk DC3 120 (K410) */
 	case 0x58B:		/* KittyHawk DC2 100 (K200) */
-		printk("%s: KittyHawk-Machine found !!\n", __FUNCTION__);
+		printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, "
+				"LED detection skipped.\n", __FILE__, CPU_HVERSION);
 		goto found;	/* use the preinitialized values of lcd_info */
-
-	default:
-		break;
 	}
 
-	/* initialize pdc_result, so we can check the return values of pdc_chassis_info() */
-	pdc_result[0] = pdc_result[1] = 0;
-
-	if (pdc_chassis_info(&pdc_result, &lcd_info, sizeof(lcd_info)) == PDC_OK) {
-		printk("%s: chassis info: model %d, ret0=%d, ret1=%d\n",
-		 __FUNCTION__, lcd_info.model, pdc_result[0], pdc_result[1]);
+	/* initialize the struct, so that we can check for valid return values */
+	lcd_info.model = DISPLAY_MODEL_NONE;
+	chassis_info.actcnt = chassis_info.maxcnt = 0;
 
+	if ((ret = pdc_chassis_info(&chassis_info, &lcd_info, sizeof(lcd_info))) == PDC_OK) {
+		DPRINTK((KERN_INFO "%s: chassis info: model=%d (%s), "
+			 "lcd_width=%d, cmd_delay=%u,\n"
+			 "%s: sizecnt=%d, actcnt=%ld, maxcnt=%ld\n",
+		         __FILE__, lcd_info.model,
+			 (lcd_info.model==DISPLAY_MODEL_LCD) ? "LCD" :
+			  (lcd_info.model==DISPLAY_MODEL_LASI) ? "LED" : "unknown",
+			 lcd_info.lcd_width, lcd_info.min_cmd_delay,
+			 __FILE__, sizeof(lcd_info), 
+			 chassis_info.actcnt, chassis_info.maxcnt));
+		DPRINTK((KERN_INFO "%s: cmd=%p, data=%p, reset1=%x, reset2=%x, act_enable=%d\n",
+			__FILE__, lcd_info.lcd_cmd_reg_addr, 
+			lcd_info.lcd_data_reg_addr, lcd_info.reset_cmd1,  
+			lcd_info.reset_cmd2, lcd_info.act_enable ));
+	
 		/* check the results. Some machines have a buggy PDC */
-		if (pdc_result[0] <= 0 || pdc_result[0] != pdc_result[1])
+		if (chassis_info.actcnt <= 0 || chassis_info.actcnt != chassis_info.maxcnt)
 			goto not_found;
 
 		switch (lcd_info.model) {
-		case DISPLAY_MODEL_LCD:	/* LCD display */
-			if (pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block)
-			    && pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) - 1)
-				 goto not_found;
-			printk("%s: min_cmd_delay = %d uS\n",
-		             __FUNCTION__, lcd_info.min_cmd_delay);
+		case DISPLAY_MODEL_LCD:		/* LCD display */
+			if (chassis_info.actcnt < 
+				offsetof(struct pdc_chassis_lcd_info_ret_block, _pad)-1)
+				goto not_found;
+			if (!lcd_info.act_enable) {
+				DPRINTK((KERN_INFO "PDC prohibited usage of the LCD.\n"));
+				goto not_found;
+			}
 			break;
 
 		case DISPLAY_MODEL_NONE:	/* no LED or LCD available */
+			printk(KERN_INFO "PDC reported no LCD or LED.\n");
 			goto not_found;
 
 		case DISPLAY_MODEL_LASI:	/* Lasi style 8 bit LED display */
-			if (pdc_result[0] != 8 && pdc_result[0] != 32)
+			if (chassis_info.actcnt != 8 && chassis_info.actcnt != 32)
 				goto not_found;
 			break;
 
 		default:
-			printk(KERN_WARNING "Unknown LCD/LED model %d\n",
+			printk(KERN_WARNING "PDC reported unknown LCD/LED model %d\n",
 			       lcd_info.model);
 			goto not_found;
-		}		/* switch() */
+		} /* switch() */
 
 found:
 		/* register the LCD/LED driver */
-		register_led_driver();
+		register_led_driver(lcd_info.model, LCD_CMD_REG, LCD_DATA_REG);
 		return 0;
 
-	}			/* if() */
+	} else { /* if() */
+		DPRINTK((KERN_INFO "pdc_chassis_info call failed with retval = %d\n", ret));
+	}
 
 not_found:
 	lcd_info.model = DISPLAY_MODEL_NONE;
 	return 1;
-#endif
 }
+
+#ifdef CONFIG_PROC_FS
+module_init(led_create_procfs)
+#endif
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/pa7300lc.c linux-2.4.20-pre2/arch/parisc/kernel/pa7300lc.c
--- linux-2.4.20-pre1/arch/parisc/kernel/pa7300lc.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/pa7300lc.c	Mon Aug 12 16:34:14 2002
@@ -4,11 +4,12 @@
  *
  *   Copyright (C) 2000 Philipp Rumpf */
 
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
 #include <asm/gsc.h>
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
-#include <linux/smp.h>
-#include <linux/kernel.h>
 
 /* CPU register indices */
 
@@ -19,12 +20,6 @@
 #define DIOERR		0xf0ec
 #define HIDMAMEM	0xf0f4
 
-/* read CPU Diagnose register index */
-static u32 diag_read(int index)
-{
-	return 0;
-}
-
 /* this returns the HPA of the CPU it was called on */
 static u32 cpu_hpa(void)
 {
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/pacache.S linux-2.4.20-pre2/arch/parisc/kernel/pacache.S
--- linux-2.4.20-pre1/arch/parisc/kernel/pacache.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/pacache.S	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,908 @@
+/*
+ *  Parisc tlb and cache flushing support
+ *  Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * NOTE: fdc,fic, and pdc instructions that use base register modification
+ *       should only use index and base registers that are not shadowed,
+ *       so that the fast path emulation in the non access miss handler
+ *       can be used.
+ */
+
+#ifdef __LP64__
+#define ADDIB   addib,*
+#define CMPB    cmpb,*
+#define ANDCM   andcm,*
+
+	.level 2.0w
+#else
+#define ADDIB   addib,
+#define CMPB    cmpb,
+#define ANDCM   andcm
+
+	.level 2.0
+#endif
+
+#include <asm/assembly.h>
+#include <asm/psw.h>
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+
+	.text
+	.align 128
+
+	.export flush_tlb_all_local,code
+
+flush_tlb_all_local:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	/*
+	 * The pitlbe and pdtlbe instructions should only be used to
+	 * flush the entire tlb. Also, there needs to be no intervening
+	 * tlb operations, e.g. tlb misses, so the operation needs
+	 * to happen in real mode with all interruptions disabled.
+	 */
+
+	/*
+	 * Once again, we do the rfi dance ... some day we need examine
+	 * all of our uses of this type of code and see what can be
+	 * consolidated.
+	 */
+
+	rsm     PSW_SM_I,%r19      /* relied upon translation! */
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	
+	rsm     PSW_SM_Q,%r0       /* Turn off Q bit to load iia queue */
+	ldil    L%REAL_MODE_PSW, %r1
+	ldo     R%REAL_MODE_PSW(%r1), %r1
+	mtctl	%r1, %cr22
+	mtctl	%r0, %cr17
+	mtctl	%r0, %cr17
+	ldil    L%PA(1f),%r1
+	ldo     R%PA(1f)(%r1),%r1
+	mtctl	%r1, %cr18
+	ldo	4(%r1), %r1
+	mtctl	%r1, %cr18
+	rfi
+	nop
+
+1:      ldil            L%PA(cache_info),%r1
+	ldo             R%PA(cache_info)(%r1),%r1
+
+	/* Flush Instruction Tlb */
+
+	LDREG           ITLB_SID_BASE(%r1),%r20
+	LDREG           ITLB_SID_STRIDE(%r1),%r21
+	LDREG           ITLB_SID_COUNT(%r1),%r22
+	LDREG           ITLB_OFF_BASE(%r1),%arg0
+	LDREG           ITLB_OFF_STRIDE(%r1),%arg1
+	LDREG           ITLB_OFF_COUNT(%r1),%arg2
+	LDREG           ITLB_LOOP(%r1),%arg3
+
+	ADDIB=          -1,%arg3,fitoneloop     /* Preadjust and test */
+	movb,<,n        %arg3,%r31,fitdone      /* If loop < 0, skip */
+	copy            %arg0,%r28              /* Init base addr */
+
+fitmanyloop:                                    /* Loop if LOOP >= 2 */
+	mtsp            %r20,%sr1
+	add             %r21,%r20,%r20          /* increment space */
+	copy            %arg2,%r29              /* Init middle loop count */
+
+fitmanymiddle:                                  /* Loop if LOOP >= 2 */
+	ADDIB>          -1,%r31,fitmanymiddle   /* Adjusted inner loop decr */
+	pitlbe          0(%sr1,%r28)
+	pitlbe,m        %arg1(%sr1,%r28)        /* Last pitlbe and addr adjust */
+	ADDIB>          -1,%r29,fitmanymiddle   /* Middle loop decr */
+	copy            %arg3,%r31              /* Re-init inner loop count */
+
+	movb,tr         %arg0,%r28,fitmanyloop  /* Re-init base addr */
+	ADDIB<=,n       -1,%r22,fitdone         /* Outer loop count decr */
+
+fitoneloop:                                     /* Loop if LOOP = 1 */
+	mtsp            %r20,%sr1
+	copy            %arg0,%r28              /* init base addr */
+	copy            %arg2,%r29              /* init middle loop count */
+
+fitonemiddle:                                   /* Loop if LOOP = 1 */
+	ADDIB>          -1,%r29,fitonemiddle    /* Middle loop count decr */
+	pitlbe,m        %arg1(%sr1,%r28)        /* pitlbe for one loop */
+
+	ADDIB>          -1,%r22,fitoneloop      /* Outer loop count decr */
+	add             %r21,%r20,%r20          /* increment space */
+
+fitdone:
+
+	/* Flush Data Tlb */
+
+	LDREG           DTLB_SID_BASE(%r1),%r20
+	LDREG           DTLB_SID_STRIDE(%r1),%r21
+	LDREG           DTLB_SID_COUNT(%r1),%r22
+	LDREG           DTLB_OFF_BASE(%r1),%arg0
+	LDREG           DTLB_OFF_STRIDE(%r1),%arg1
+	LDREG           DTLB_OFF_COUNT(%r1),%arg2
+	LDREG           DTLB_LOOP(%r1),%arg3
+
+	ADDIB=          -1,%arg3,fdtoneloop     /* Preadjust and test */
+	movb,<,n        %arg3,%r31,fdtdone      /* If loop < 0, skip */
+	copy            %arg0,%r28              /* Init base addr */
+
+fdtmanyloop:                                    /* Loop if LOOP >= 2 */
+	mtsp            %r20,%sr1
+	add             %r21,%r20,%r20          /* increment space */
+	copy            %arg2,%r29              /* Init middle loop count */
+
+fdtmanymiddle:                                  /* Loop if LOOP >= 2 */
+	ADDIB>          -1,%r31,fdtmanymiddle   /* Adjusted inner loop decr */
+	pdtlbe          0(%sr1,%r28)
+	pdtlbe,m        %arg1(%sr1,%r28)        /* Last pdtlbe and addr adjust */
+	ADDIB>          -1,%r29,fdtmanymiddle   /* Middle loop decr */
+	copy            %arg3,%r31              /* Re-init inner loop count */
+
+	movb,tr         %arg0,%r28,fdtmanyloop  /* Re-init base addr */
+	ADDIB<=,n       -1,%r22,fdtdone         /* Outer loop count decr */
+
+fdtoneloop:                                     /* Loop if LOOP = 1 */
+	mtsp            %r20,%sr1
+	copy            %arg0,%r28              /* init base addr */
+	copy            %arg2,%r29              /* init middle loop count */
+
+fdtonemiddle:                                   /* Loop if LOOP = 1 */
+	ADDIB>          -1,%r29,fdtonemiddle    /* Middle loop count decr */
+	pdtlbe,m        %arg1(%sr1,%r28)        /* pdtlbe for one loop */
+
+	ADDIB>          -1,%r22,fdtoneloop      /* Outer loop count decr */
+	add             %r21,%r20,%r20          /* increment space */
+
+fdtdone:
+
+	/* Switch back to virtual mode */
+
+	rsm     PSW_SM_Q,%r0       /* clear Q bit to load iia queue */
+	ldil	L%KERNEL_PSW, %r1
+	ldo	R%KERNEL_PSW(%r1), %r1
+	or      %r1,%r19,%r1    /* Set I bit if set on entry */
+	mtctl	%r1, %cr22
+	mtctl	%r0, %cr17
+	mtctl	%r0, %cr17
+	ldil    L%(2f), %r1
+	ldo     R%(2f)(%r1), %r1
+	mtctl	%r1, %cr18
+	ldo	4(%r1), %r1
+	mtctl	%r1, %cr18
+	rfi
+	nop
+
+2:      bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_instruction_cache_local,code
+	.import cache_info,data
+
+flush_instruction_cache_local:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	mtsp            %r0,%sr1
+	ldil            L%cache_info,%r1
+	ldo             R%cache_info(%r1),%r1
+
+	/* Flush Instruction Cache */
+
+	LDREG           ICACHE_BASE(%r1),%arg0
+	LDREG           ICACHE_STRIDE(%r1),%arg1
+	LDREG           ICACHE_COUNT(%r1),%arg2
+	LDREG           ICACHE_LOOP(%r1),%arg3
+	ADDIB=          -1,%arg3,fioneloop      /* Preadjust and test */
+	movb,<,n        %arg3,%r31,fisync       /* If loop < 0, do sync */
+
+fimanyloop:                                     /* Loop if LOOP >= 2 */
+	ADDIB>          -1,%r31,fimanyloop      /* Adjusted inner loop decr */
+	fice            0(%sr1,%arg0)
+	fice,m          %arg1(%sr1,%arg0)       /* Last fice and addr adjust */
+	movb,tr         %arg3,%r31,fimanyloop   /* Re-init inner loop count */
+	ADDIB<=,n       -1,%arg2,fisync         /* Outer loop decr */
+
+fioneloop:                                      /* Loop if LOOP = 1 */
+	ADDIB>          -1,%arg2,fioneloop      /* Outer loop count decr */
+	fice,m          %arg1(%sr1,%arg0)       /* Fice for one loop */
+
+fisync:
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_data_cache_local,code
+	.import cache_info,data
+
+flush_data_cache_local:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	mtsp            %r0,%sr1
+	ldil            L%cache_info,%r1
+	ldo             R%cache_info(%r1),%r1
+
+	/* Flush Data Cache */
+
+	LDREG           DCACHE_BASE(%r1),%arg0
+	LDREG           DCACHE_STRIDE(%r1),%arg1
+	LDREG           DCACHE_COUNT(%r1),%arg2
+	LDREG           DCACHE_LOOP(%r1),%arg3
+	rsm             PSW_SM_I,%r22
+	ADDIB=          -1,%arg3,fdoneloop      /* Preadjust and test */
+	movb,<,n        %arg3,%r31,fdsync       /* If loop < 0, do sync */
+
+fdmanyloop:                                     /* Loop if LOOP >= 2 */
+	ADDIB>          -1,%r31,fdmanyloop      /* Adjusted inner loop decr */
+	fdce            0(%sr1,%arg0)
+	fdce,m          %arg1(%sr1,%arg0)       /* Last fdce and addr adjust */
+	movb,tr         %arg3,%r31,fdmanyloop   /* Re-init inner loop count */
+	ADDIB<=,n       -1,%arg2,fdsync         /* Outer loop decr */
+
+fdoneloop:                                      /* Loop if LOOP = 1 */
+	ADDIB>          -1,%arg2,fdoneloop      /* Outer loop count decr */
+	fdce,m          %arg1(%sr1,%arg0)       /* Fdce for one loop */
+
+fdsync:
+	syncdma
+	sync
+	mtsm    %r22
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export copy_user_page_asm,code
+
+copy_user_page_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldi 64,%r1
+
+	/*
+	 * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
+	 * bundles (very restricted rules for bundling). It probably
+	 * does OK on PCXU and better, but we could do better with
+	 * ldd/std instructions. Note that until (if) we start saving
+	 * the full 64 bit register values on interrupt, we can't
+	 * use ldd/std on a 32 bit kernel.
+	 */
+
+
+1:
+	ldw 0(%r25),%r19
+	ldw 4(%r25),%r20
+	ldw 8(%r25),%r21
+	ldw 12(%r25),%r22
+	stw %r19,0(%r26)
+	stw %r20,4(%r26)
+	stw %r21,8(%r26)
+	stw %r22,12(%r26)
+	ldw 16(%r25),%r19
+	ldw 20(%r25),%r20
+	ldw 24(%r25),%r21
+	ldw 28(%r25),%r22
+	stw %r19,16(%r26)
+	stw %r20,20(%r26)
+	stw %r21,24(%r26)
+	stw %r22,28(%r26)
+	ldw 32(%r25),%r19
+	ldw 36(%r25),%r20
+	ldw 40(%r25),%r21
+	ldw 44(%r25),%r22
+	stw %r19,32(%r26)
+	stw %r20,36(%r26)
+	stw %r21,40(%r26)
+	stw %r22,44(%r26)
+	ldw 48(%r25),%r19
+	ldw 52(%r25),%r20
+	ldw 56(%r25),%r21
+	ldw 60(%r25),%r22
+	stw %r19,48(%r26)
+	stw %r20,52(%r26)
+	stw %r21,56(%r26)
+	stw %r22,60(%r26)
+	ldo 64(%r26),%r26
+	ADDIB>  -1,%r1,1b
+	ldo 64(%r25),%r25
+
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+#if (TMPALIAS_MAP_START >= 0x80000000UL)
+Warning TMPALIAS_MAP_START changed. If > 2 Gb, code in pacache.S is bogus
+#endif
+
+/*
+ * NOTE: Code in clear_user_page has a hard coded dependency on the
+ *       maximum alias boundary being 4 Mb. We've been assured by the
+ *       parisc chip designers that there will not ever be a parisc
+ *       chip with a larger alias boundary (Never say never :-) ).
+ *
+ *       Subtle: the dtlb miss handlers support the temp alias region by
+ *       "knowing" that if a dtlb miss happens within the temp alias
+ *       region it must have occurred while in clear_user_page. Since
+ *       this routine makes use of processor local translations, we
+ *       don't want to insert them into the kernel page table. Instead,
+ *       we load up some general registers (they need to be registers
+ *       which aren't shadowed) with the physical page numbers (preshifted
+ *       for tlb insertion) needed to insert the translations. When we
+ *       miss on the translation, the dtlb miss handler inserts the
+ *       translation into the tlb using these values:
+ *
+ *          %r26 physical page (shifted for tlb insert) of "to" translation
+ *          %r23 physical page (shifted for tlb insert) of "from" translation
+ */
+
+#if 0
+
+	/*
+	 * We can't do this since copy_user_page is used to bring in
+	 * file data that might have instructions. Since the data would
+	 * then need to be flushed out so the i-fetch can see it, it
+	 * makes more sense to just copy through the kernel translation
+	 * and flush it.
+	 *
+	 * I'm still keeping this around because it may be possible to
+	 * use it if more information is passed into copy_user_page().
+	 * Have to do some measurements to see if it is worthwhile to
+	 * lobby for such a change.
+	 */
+
+	.export copy_user_page_asm,code
+
+copy_user_page_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%(__PAGE_OFFSET),%r1
+	sub     %r26,%r1,%r26
+	sub     %r25,%r1,%r23  /* move physical addr into non shadowed reg */
+
+	ldil    L%(TMPALIAS_MAP_START),%r28
+#ifdef __LP64__
+	extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
+	extrd,u %r23,56,32,%r23 /* convert phys addr to tlb insert format */
+	depd    %r24,63,22,%r28 /* Form aliased virtual address 'to' */
+	depdi   0,63,12,%r28    /* Clear any offset bits */
+	copy    %r28,%r29
+	depdi   1,41,1,%r29     /* Form aliased virtual address 'from' */
+#else
+	extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
+	extrw,u %r23,24,25,%r23 /* convert phys addr to tlb insert format */
+	depw    %r24,31,22,%r28 /* Form aliased virtual address 'to' */
+	depwi   0,31,12,%r28    /* Clear any offset bits */
+	copy    %r28,%r29
+	depwi   1,9,1,%r29      /* Form aliased virtual address 'from' */
+#endif
+
+	/* Purge any old translations */
+
+	pdtlb   0(%r28)
+	pdtlb   0(%r29)
+
+	ldi 64,%r1
+
+	/*
+	 * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
+	 * bundles (very restricted rules for bundling). It probably
+	 * does OK on PCXU and better, but we could do better with
+	 * ldd/std instructions. Note that until (if) we start saving
+	 * the full 64 bit register values on interrupt, we can't
+	 * use ldd/std on a 32 bit kernel.
+	 */
+
+
+1:
+	ldw 0(%r29),%r19
+	ldw 4(%r29),%r20
+	ldw 8(%r29),%r21
+	ldw 12(%r29),%r22
+	stw %r19,0(%r28)
+	stw %r20,4(%r28)
+	stw %r21,8(%r28)
+	stw %r22,12(%r28)
+	ldw 16(%r29),%r19
+	ldw 20(%r29),%r20
+	ldw 24(%r29),%r21
+	ldw 28(%r29),%r22
+	stw %r19,16(%r28)
+	stw %r20,20(%r28)
+	stw %r21,24(%r28)
+	stw %r22,28(%r28)
+	ldw 32(%r29),%r19
+	ldw 36(%r29),%r20
+	ldw 40(%r29),%r21
+	ldw 44(%r29),%r22
+	stw %r19,32(%r28)
+	stw %r20,36(%r28)
+	stw %r21,40(%r28)
+	stw %r22,44(%r28)
+	ldw 48(%r29),%r19
+	ldw 52(%r29),%r20
+	ldw 56(%r29),%r21
+	ldw 60(%r29),%r22
+	stw %r19,48(%r28)
+	stw %r20,52(%r28)
+	stw %r21,56(%r28)
+	stw %r22,60(%r28)
+	ldo 64(%r28),%r28
+	ADDIB>  -1,%r1,1b
+	ldo 64(%r29),%r29
+
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+#endif
+
+	.export clear_user_page_asm,code
+
+clear_user_page_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	tophys_r1 %r26
+
+	ldil    L%(TMPALIAS_MAP_START),%r28
+#ifdef __LP64__
+	extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
+	depd    %r25,63,22,%r28 /* Form aliased virtual address 'to' */
+	depdi   0,63,12,%r28    /* Clear any offset bits */
+#else
+	extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
+	depw    %r25,31,22,%r28 /* Form aliased virtual address 'to' */
+	depwi   0,31,12,%r28    /* Clear any offset bits */
+#endif
+
+	/* Purge any old translation */
+
+	pdtlb   0(%r28)
+
+	ldi 64,%r1
+
+1:
+	stw %r0,0(%r28)
+	stw %r0,4(%r28)
+	stw %r0,8(%r28)
+	stw %r0,12(%r28)
+	stw %r0,16(%r28)
+	stw %r0,20(%r28)
+	stw %r0,24(%r28)
+	stw %r0,28(%r28)
+	stw %r0,32(%r28)
+	stw %r0,36(%r28)
+	stw %r0,40(%r28)
+	stw %r0,44(%r28)
+	stw %r0,48(%r28)
+	stw %r0,52(%r28)
+	stw %r0,56(%r28)
+	stw %r0,60(%r28)
+	ADDIB>  -1,%r1,1b
+	ldo 64(%r28),%r28
+
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_kernel_dcache_page
+
+flush_kernel_dcache_page:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+
+#ifdef __LP64__
+	depdi,z 1,63-PAGE_SHIFT,1,%r25
+#else
+	depwi,z 1,31-PAGE_SHIFT,1,%r25
+#endif
+	add     %r26,%r25,%r25
+	sub     %r25,%r23,%r25
+
+
+1:      fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	fdc,m   %r23(%r26)
+	CMPB<<  %r26,%r25,1b
+	fdc,m   %r23(%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export purge_kernel_dcache_page
+
+purge_kernel_dcache_page:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+
+#ifdef __LP64__
+	depdi,z 1,63-PAGE_SHIFT,1,%r25
+#else
+	depwi,z 1,31-PAGE_SHIFT,1,%r25
+#endif
+	add      %r26,%r25,%r25
+	sub      %r25,%r23,%r25
+
+1:      pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	pdc,m   %r23(%r26)
+	CMPB<<  %r26,%r25,1b
+	pdc,m   %r23(%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+#if 0
+	/* Currently not used, but it still is a possible alternate
+	 * solution.
+	 */
+
+	.export flush_alias_page
+
+flush_alias_page:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	tophys_r1 %r26
+
+	ldil    L%(TMPALIAS_MAP_START),%r28
+#ifdef __LP64__
+	extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
+	depd    %r25,63,22,%r28 /* Form aliased virtual address 'to' */
+	depdi   0,63,12,%r28    /* Clear any offset bits */
+#else
+	extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
+	depw    %r25,31,22,%r28 /* Form aliased virtual address 'to' */
+	depwi   0,31,12,%r28    /* Clear any offset bits */
+#endif
+
+	/* Purge any old translation */
+
+	pdtlb   0(%r28)
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+
+#ifdef __LP64__
+	depdi,z 1,63-PAGE_SHIFT,1,%r29
+#else
+	depwi,z 1,31-PAGE_SHIFT,1,%r29
+#endif
+	add      %r28,%r29,%r29
+	sub      %r29,%r23,%r29
+
+1:      fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	fdc,m   %r23(%r28)
+	CMPB<<  %r28,%r29,1b
+	fdc,m   %r23(%r28)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+#endif
+
+	.export flush_user_dcache_range_asm
+
+flush_user_dcache_range_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+	ldo     -1(%r23),%r21
+	ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+	fdc,m   %r23(%sr3,%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_kernel_dcache_range_asm
+
+flush_kernel_dcache_range_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%dcache_stride,%r1
+	ldw     R%dcache_stride(%r1),%r23
+	ldo     -1(%r23),%r21
+	ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+	fdc,m   %r23(%r26)
+
+	sync
+	syncdma
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_user_icache_range_asm
+
+flush_user_icache_range_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%icache_stride,%r1
+	ldw     R%icache_stride(%r1),%r23
+	ldo     -1(%r23),%r21
+	ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+	fic,m   %r23(%sr3,%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_kernel_icache_page
+
+flush_kernel_icache_page:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%icache_stride,%r1
+	ldw     R%icache_stride(%r1),%r23
+
+#ifdef __LP64__
+	depdi,z 1,63-PAGE_SHIFT,1,%r25
+#else
+	depwi,z 1,31-PAGE_SHIFT,1,%r25
+#endif
+	add     %r26,%r25,%r25
+	sub     %r25,%r23,%r25
+
+
+1:      fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	fic,m   %r23(%r26)
+	CMPB<<  %r26,%r25,1b
+	fic,m   %r23(%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.export flush_kernel_icache_range_asm
+
+flush_kernel_icache_range_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	ldil    L%icache_stride,%r1
+	ldw     R%icache_stride(%r1),%r23
+	ldo     -1(%r23),%r21
+	ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+	fic,m   %r23(%r26)
+
+	sync
+	bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.align 128
+
+	.export disable_sr_hashing_asm,code
+
+disable_sr_hashing_asm:
+	.proc
+	.callinfo NO_CALLS
+	.entry
+
+	/* Switch to real mode */
+
+	ssm     0,%r0           /* relied upon translation! */
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	
+	rsm     (PSW_SM_Q|PSW_SM_I),%r0 /* disable Q&I to load the iia queue */
+	ldil    L%REAL_MODE_PSW, %r1
+	ldo     R%REAL_MODE_PSW(%r1), %r1
+	mtctl	%r1, %cr22
+	mtctl	%r0, %cr17
+	mtctl	%r0, %cr17
+	ldil    L%PA(1f),%r1
+	ldo     R%PA(1f)(%r1),%r1
+	mtctl	%r1, %cr18
+	ldo	4(%r1), %r1
+	mtctl	%r1, %cr18
+	rfi
+	nop
+
+1:      cmpib,=,n SRHASH_PCXST,%r26,srdis_pcxs
+	cmpib,=,n SRHASH_PCXL,%r26,srdis_pcxl
+	cmpib,=,n SRHASH_PA20,%r26,srdis_pa20
+	b,n       srdis_done
+
+srdis_pcxs:
+
+	/* Disable Space Register Hashing for PCXS,PCXT,PCXT' */
+
+	.word           0x141c1a00  /* mfdiag %dr0,%r28 */
+	.word           0x141c1a00  /* must issue twice */
+	depwi           0,18,1,%r28 /* Clear DHE (dcache hash enable) */
+	depwi           0,20,1,%r28 /* Clear IHE (icache hash enable) */
+	.word           0x141c1600  /* mtdiag %r28,%dr0 */
+	.word           0x141c1600  /* must issue twice */
+	b,n             srdis_done
+
+srdis_pcxl:
+
+	/* Disable Space Register Hashing for PCXL */
+
+	.word           0x141c0600  /* mfdiag %dr0,%r28 */
+	depwi           0,28,2,%r28 /* Clear DHASH_EN & IHASH_EN */
+	.word           0x141c0240  /* mtdiag %r28,%dr0 */
+	b,n             srdis_done
+
+srdis_pa20:
+
+	/* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+ */
+
+	.word           0x144008bc  /* mfdiag %dr2,%r28 */
+	depdi           0,54,1,%r28 /* clear DIAG_SPHASH_ENAB (bit 54) */
+	.word           0x145c1840  /* mtdiag %r28,%dr2 */
+
+srdis_done:
+
+	/* Switch back to virtual mode */
+
+	rsm     PSW_SM_Q,%r0           /* clear Q bit to load iia queue */
+	ldil	L%KERNEL_PSW, %r1
+	ldo	R%KERNEL_PSW(%r1), %r1
+	mtctl	%r1, %cr22
+	mtctl	%r0, %cr17
+	mtctl	%r0, %cr17
+	ldil    L%(2f), %r1
+	ldo     R%(2f)(%r1), %r1
+	mtctl	%r1, %cr18
+	ldo	4(%r1), %r1
+	mtctl	%r1, %cr18
+	rfi
+	nop
+
+2:      bv      %r0(%r2)
+	nop
+	.exit
+
+	.procend
+
+	.end
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/parisc_ksyms.c linux-2.4.20-pre2/arch/parisc/kernel/parisc_ksyms.c
--- linux-2.4.20-pre1/arch/parisc/kernel/parisc_ksyms.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/parisc_ksyms.c	Mon Aug 12 16:34:14 2002
@@ -14,17 +14,29 @@
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strstr);
 
+#include <asm/hardware.h>	/* struct parisc_device for asm/pci.h */
 #include <linux/pci.h>
 EXPORT_SYMBOL(hppa_dma_ops);
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+EXPORT_SYMBOL(get_pci_node_path);
+#endif
+
+#ifdef CONFIG_IOMMU_CCIO
+EXPORT_SYMBOL(ccio_get_fake);
+#endif
 
+#include <linux/sched.h>
 #include <asm/irq.h>
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
@@ -32,6 +44,13 @@
 #include <asm/processor.h>
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(boot_cpu_data);
+EXPORT_SYMBOL(map_hpux_gateway_page);
+#ifdef CONFIG_EISA
+EXPORT_SYMBOL(EISA_bus);
+#endif
+
+#include <linux/pm.h>
+EXPORT_SYMBOL(pm_power_off);
 
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(synchronize_irq);
@@ -39,35 +58,100 @@
 #include <asm/smplock.h>
 EXPORT_SYMBOL(kernel_flag);
 
+/* from asm/system.h */
 #include <asm/system.h>
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
 
+#include <linux/smp.h>
+EXPORT_SYMBOL(smp_num_cpus);
+#endif /* CONFIG_SMP */
+
+#include <asm/atomic.h>
+EXPORT_SYMBOL(__xchg8);
+EXPORT_SYMBOL(__xchg32);
+EXPORT_SYMBOL(__cmpxchg_u32);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(__atomic_hash);
+#endif
+#ifdef __LP64__
+EXPORT_SYMBOL(__xchg64);
+EXPORT_SYMBOL(__cmpxchg_u64);
 #endif
 
 #include <asm/uaccess.h>
 EXPORT_SYMBOL(lcopy_to_user);
 EXPORT_SYMBOL(lcopy_from_user);
+EXPORT_SYMBOL(lstrnlen_user);
+EXPORT_SYMBOL(lclear_user);
 
+#ifndef __LP64__
 /* Needed so insmod can set dp value */
-
-extern int data_start;
-
-EXPORT_SYMBOL_NOVERS(data_start);
+extern int $global$;
+EXPORT_SYMBOL_NOVERS($global$);
+#endif
 
 #include <asm/gsc.h>
-EXPORT_SYMBOL(_gsc_writeb);
-EXPORT_SYMBOL(_gsc_writew);
-EXPORT_SYMBOL(_gsc_writel);
-EXPORT_SYMBOL(_gsc_readb);
-EXPORT_SYMBOL(_gsc_readw);
-EXPORT_SYMBOL(_gsc_readl);
-EXPORT_SYMBOL(busdevice_alloc_irq);
-EXPORT_SYMBOL(register_driver);
-EXPORT_SYMBOL(gsc_alloc_irq);
+EXPORT_SYMBOL(register_parisc_driver);
+EXPORT_SYMBOL(unregister_parisc_driver);
 EXPORT_SYMBOL(pdc_iodc_read);
+#ifdef CONFIG_GSC
+EXPORT_SYMBOL(gsc_alloc_irq);
+#endif
+
+#include <asm/io.h>
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(memcpy_toio);
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memset_io);
+
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(outsl);
+#endif
+
+#include <asm/cache.h>
+EXPORT_SYMBOL(flush_kernel_dcache_range_asm);
+EXPORT_SYMBOL(flush_kernel_dcache_page);
+EXPORT_SYMBOL(flush_all_caches);
+
+#include <asm/unistd.h>
+extern long sys_open(const char *, int, int);
+extern off_t sys_lseek(int, off_t, int);
+extern int sys_read(int, char *, int);
+extern int sys_write(int, const char *, int);
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_write);
+
+#include <asm/semaphore.h>
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down);
+
+#include <linux/in6.h>
+#include <asm/checksum.h>
+EXPORT_SYMBOL(csum_partial_copy);
+
+#include <asm/pdc.h>
+EXPORT_SYMBOL(pdc_add_valid);
+EXPORT_SYMBOL(pdc_lan_station_id);
+EXPORT_SYMBOL(pdc_get_initiator);
 
 extern void $$divI(void);
 extern void $$divU(void);
@@ -99,7 +183,9 @@
 EXPORT_SYMBOL_NOVERS($$remI);
 EXPORT_SYMBOL_NOVERS($$remU);
 EXPORT_SYMBOL_NOVERS($$mulI);
+#ifndef __LP64__
 EXPORT_SYMBOL_NOVERS($$mulU);
+#endif
 EXPORT_SYMBOL_NOVERS($$divU_3);
 EXPORT_SYMBOL_NOVERS($$divU_5);
 EXPORT_SYMBOL_NOVERS($$divU_6);
@@ -120,15 +206,25 @@
 EXPORT_SYMBOL_NOVERS($$divI_15);
 
 extern void __ashrdi3(void);
+extern void __ashldi3(void);
+extern void __lshrdi3(void);
+extern void __muldi3(void);
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
+EXPORT_SYMBOL_NOVERS(__lshrdi3);
+EXPORT_SYMBOL_NOVERS(__muldi3);
 
 #ifdef __LP64__
 extern void __divdi3(void);
 extern void __udivdi3(void);
+extern void __umoddi3(void);
+extern void __moddi3(void);
 
 EXPORT_SYMBOL_NOVERS(__divdi3);
 EXPORT_SYMBOL_NOVERS(__udivdi3);
+EXPORT_SYMBOL_NOVERS(__umoddi3);
+EXPORT_SYMBOL_NOVERS(__moddi3);
 #endif
 
 #ifndef __LP64__
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/pci-dma.c linux-2.4.20-pre2/arch/parisc/kernel/pci-dma.c
--- linux-2.4.20-pre1/arch/parisc/kernel/pci-dma.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/pci-dma.c	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,7 @@
 /*
-** Dynamic DMA mapping support.
+** PARISC 1.1 Dynamic DMA mapping support.
+** This implementation is for PA-RISC platforms that do not support
+** I/O TLBs (aka DMA address translation hardware).
 ** See Documentation/DMA-mapping.txt for interface definitions.
 **
 **      (c) Copyright 1999,2000 Hewlett-Packard Company
@@ -7,15 +9,10 @@
 **	(c) Copyright 2000 Philipp Rumpf <prumpf@tux.org>
 **      (c) Copyright 2000 John Marvin
 **
-** This implementation is for PA-RISC platforms that do not support
-** I/O TLBs (aka DMA address translation hardware).
-**
 ** "leveraged" from 2.3.47: arch/ia64/kernel/pci-dma.c.
 ** (I assume it's from David Mosberger-Tang but there was no Copyright)
 **
 ** AFAIK, all PA7100LC and PA7300LC platforms can use this code.
-** All PA2.0 machines but V-class can alias xxx_alloc_consistent()
-** to use regular cacheable memory.
 **
 ** - ggg
 */
@@ -117,7 +114,7 @@
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
 	do {
-		pte_t * pte = pte_alloc_kernel(pmd, vaddr);
+		pte_t * pte = pte_alloc(NULL, pmd, vaddr);
 		if (!pte)
 			return -ENOMEM;
 		if (map_pte_uncached(pte, orig_vaddr, end - vaddr, paddr_ptr))
@@ -139,7 +136,7 @@
 	do {
 		pmd_t *pmd;
 		
-		pmd = pmd_alloc_kernel(dir, vaddr);
+		pmd = pmd_alloc(NULL, dir, vaddr);
 		if (!pmd)
 			return -ENOMEM;
 		if (map_pmd_uncached(pmd, vaddr, end - vaddr, &paddr))
@@ -510,7 +507,6 @@
 	pa11_dma_sync_sg			/* dma_sync_sg */
 };
 
-struct pci_dma_ops *hppa_dma_ops;
 
 static int pcxl_proc_info(char *buf, char **start, off_t offset, int len)
 {
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/pci.c linux-2.4.20-pre2/arch/parisc/kernel/pci.c
--- linux-2.4.20-pre1/arch/parisc/kernel/pci.c	Wed Dec  6 11:46:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/pci.c	Mon Aug 12 16:34:14 2002
@@ -6,25 +6,32 @@
  *
  * Copyright (C) 1997, 1998 Ralf Baechle
  * Copyright (C) 1999 SuSE GmbH
- * Copyright (C) 1999 Hewlett-Packard Company
- * Copyright (C) 1999, 2000 Grant Grundler
+ * Copyright (C) 1999-2001 Hewlett-Packard Company
+ * Copyright (C) 1999-2001 Grant Grundler
  */
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>		/* for __init and __devinit */
 #include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>	/* for memcpy() */
+#include <linux/slab.h>
 
+#include <asm/io.h>
 #include <asm/system.h>
+#include <asm/cache.h>		/* for L1_CACHE_BYTES */
 
-#ifdef CONFIG_PCI
+#define DEBUG_RESOURCES 0
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBGC(x...)     printk(KERN_DEBUG x)
+#else
+# define DBGC(x...)
+#endif
 
-#undef DEBUG_RESOURCES
 
-#ifdef DEBUG_RESOURCES
-#define DBG_RES(x...)	printk(x)
+#if DEBUG_RESOURCES
+#define DBG_RES(x...)	printk(KERN_DEBUG x)
 #else
 #define DBG_RES(x...)
 #endif
@@ -42,14 +49,13 @@
 struct pci_port_ops *pci_port;
 struct pci_bios_ops *pci_bios;
 
-struct pci_hba_data *hba_list = NULL;
-int hba_count = 0;
+int pci_hba_count = 0;
 
 /*
 ** parisc_pci_hba used by pci_port->in/out() ops to lookup bus data.
 */
 #define PCI_HBA_MAX 32
-static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX];
+struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX];
 
 
 /********************************************************************
@@ -58,24 +64,31 @@
 **
 *********************************************************************/
 
-#define PCI_PORT_HBA(a) ((a)>>16)
-#define PCI_PORT_ADDR(a) ((a) & 0xffffUL)
+/* EISA port numbers and PCI port numbers share the same interface.  Some
+ * machines have both EISA and PCI adapters installed.  Rather than turn
+ * pci_port into an array, we reserve bus 0 for EISA and call the EISA
+ * routines if the access is to a port on bus 0.  We don't want to fix
+ * EISA and ISA drivers which assume port space is <= 0xffff.
+ */
 
-/* KLUGE : inb needs to be defined differently for PCI devices than
-** for other bus interfaces. Doing this at runtime sucks but is the
-** only way one driver binary can support devices on different bus types.
-**
-*/
+#ifdef CONFIG_EISA
+#define EISA_IN(size) if (EISA_bus && (b == 0)) return eisa_in##size(addr)
+#define EISA_OUT(size) if (EISA_bus && (b == 0)) return eisa_out##size(d, addr)
+#else
+#define EISA_IN(size)
+#define EISA_OUT(size)
+#endif
 
 #define PCI_PORT_IN(type, size) \
 u##size in##type (int addr) \
 { \
 	int b = PCI_PORT_HBA(addr); \
 	u##size d = (u##size) -1; \
+	EISA_IN(size); \
 	ASSERT(pci_port); /* make sure services are defined */ \
 	ASSERT(parisc_pci_hba[b]); /* make sure ioaddr are "fixed up" */ \
 	if (parisc_pci_hba[b] == NULL) { \
-		printk(KERN_WARNING "\nPCI Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \
+		printk(KERN_WARNING "\nPCI or EISA Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \
 	} else { \
 		d = pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \
 	} \
@@ -91,6 +104,7 @@
 void out##type (u##size d, int addr) \
 { \
 	int b = PCI_PORT_HBA(addr); \
+	EISA_OUT(size); \
 	ASSERT(pci_port); \
 	pci_port->out##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr), d); \
 }
@@ -106,15 +120,13 @@
  */
 void pcibios_init(void)
 {
-	ASSERT(pci_bios != NULL);
+	if (!pci_bios)
+		return;
 
-	if (pci_bios)
-	{
-		if (pci_bios->init) {
-			(*pci_bios->init)();
-		} else {
-			printk(KERN_WARNING "pci_bios != NULL but init() is!\n");
-		}
+	if (pci_bios->init) {
+		pci_bios->init();
+	} else {
+		printk(KERN_WARNING "pci_bios != NULL but init() is!\n");
 	}
 }
 
@@ -124,17 +136,10 @@
 {
 	ASSERT(pci_bios != NULL);
 
-        /* If this is a bridge, get the current bases */
-	if (bus->self) {
-		pci_read_bridge_bases(bus);
-	}
-
-	if (pci_bios) {
-		if (pci_bios->fixup_bus) {
-			(*pci_bios->fixup_bus)(bus);
-		} else {
-			printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
-		}
+	if (pci_bios->fixup_bus) {
+		pci_bios->fixup_bus(bus);
+	} else {
+		printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
 	}
 }
 
@@ -144,14 +149,6 @@
 	return str;
 }
 
-#endif /* defined(CONFIG_PCI) */
-
-
-
-/* -------------------------------------------------------------------
-** linux-2.4: NEW STUFF 
-** --------------------
-*/
 
 /*
 ** Used in drivers/pci/quirks.c
@@ -201,19 +198,11 @@
 ** ------------------------------------
 ** PAT PDC systems need this routine. PA legacy PDC does not.
 **
-** Used by alpha/arm: 
-** alpha/kernel/pci.c:common_init_pci()
-** (or arm/kernel/pci.c:pcibios_init())
-**    drivers/pci/setup.c:pci_assign_unassigned_resources()
-**        drivers/pci/setup.c:pdev_assign_unassigned_resources()
-**            arch/<foo>/kernel/pci.c:pcibios_update_resource()
-**
-** When BAR's are configured by linux, this routine
-** will update configuration space with the "normalized"
-** address. "root" indicates where the range starts and res
-** is some portion of that range.
+** When BAR's are configured by linux, this routine will update
+** configuration space with the "normalized" address. "root" indicates
+** where the range starts and res is some portion of that range.
 **
-** For all PA-RISC systems except V-class, root->start would be zero.
+** VCLASS: For all PA-RISC systems except V-class, root->start would be zero.
 **
 ** PAT PDC can tell us which MMIO ranges are available or already in use.
 ** I/O port space and such are not memory mapped anyway for PA-Risc.
@@ -234,7 +223,7 @@
 		barnum, res->start, res->end, (int) res->flags);
 
 	if (barnum >= PCI_BRIDGE_RESOURCES) {
-		/* handled in pbus_set_ranges_data() */
+		/* handled in PCI-PCI bridge specific support */
 		return;
 	}
 
@@ -248,8 +237,7 @@
 	if (res->flags & IORESOURCE_IO) {
 		barval = PCI_PORT_ADDR(res->start);
 	} else if (res->flags & IORESOURCE_MEM) {
-		/* This should work for VCLASS too */
-		barval = res->start & 0xffffffffUL;
+		barval = PCI_BUS_ADDR(HBA_DATA(dev->bus->sysdata), res->start);
 	} else {
 		panic("pcibios_update_resource() WTF? flags not IO or MEM");
 	}
@@ -267,7 +255,7 @@
 	    == (PCI_BASE_ADDRESS_SPACE_MEMORY
 		| PCI_BASE_ADDRESS_MEM_TYPE_64)) {
 		pci_write_config_dword(dev, where+4, 0);
-		printk(KERN_WARNING "PCI: dev %s type 64-bit\n", dev->name);
+		DBGC("PCIBIOS: dev %s type 64-bit\n", dev->name);
 	}
 }
 
@@ -290,25 +278,78 @@
 pcibios_set_master(struct pci_dev *dev)
 {
 	u8 lat;
+
+	/* If someone already mucked with this, don't touch it. */
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
 	if (lat >= 16) return;
 
 	/*
 	** HP generally has fewer devices on the bus than other architectures.
+	** upper byte is PCI_LATENCY_TIMER.
 	*/
-	printk("PCIBIOS: Setting latency timer of %s to 128\n", dev->slot_name);
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+        pci_write_config_word(dev, PCI_CACHE_LINE_SIZE,
+				(0x80 << 8) | (L1_CACHE_BYTES / sizeof(u32)));
+}
+
+
+void __init
+pcibios_init_bus(struct pci_bus *bus)
+{
+	struct pci_dev *dev = bus->self;
+
+	/* We deal only with pci controllers and pci-pci bridges. */
+	if (dev && (dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+		return;
+	
+	if (dev) {
+		/* PCI-PCI bridge - set the cache line and default latency
+		   (32) for primary and secondary buses. */
+		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32);
+
+		/* Read bridge control */
+		pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bus->bridge_ctl);
+	}
+
+	/* Set FBB bit for now. Disable ISA IO forwarding. Enable PERR/SERR */
+	bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK | 
+			   PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
 }
 
 
 /*
-** called by drivers/pci/setup-res.c:pbus_set_ranges().
+** KLUGE: Link the child and parent resources - generic PCI didn't
+*/
+static void
+pcibios_link_hba_resources( struct resource *hba_res, struct resource *r)
+{
+	if (!r->parent) {
+		r->parent = hba_res;
+
+		/* reverse link is harder *sigh*  */
+		if (r->parent->child) {
+			if (r->parent->sibling) {
+				struct resource *next = r->parent->sibling;
+				while (next->sibling)
+					 next = next->sibling;
+				next->sibling = r;
+			} else {
+				r->parent->sibling = r;
+			}
+		} else
+			r->parent->child = r;
+	}
+}
+
+/*
+** called by drivers/pci/setup-res.c:pci_setup_bridge().
 */
 void pcibios_fixup_pbus_ranges(
 	struct pci_bus *bus,
 	struct pbus_set_ranges_data *ranges
 	)
 {
+	struct pci_hba_data *hba = HBA_DATA(bus->sysdata);
+
 	/*
 	** I/O space may see busnumbers here. Something
 	** in the form of 0xbbxxxx where bb is the bus num
@@ -319,9 +360,20 @@
 	ranges->io_start = PCI_PORT_ADDR(ranges->io_start);
 	ranges->io_end   = PCI_PORT_ADDR(ranges->io_end);
 
+	/* Convert MMIO addr to PCI addr (undo global virtualization) */
+	ranges->mem_start = PCI_BUS_ADDR(hba, ranges->mem_start);
+	ranges->mem_end   = PCI_BUS_ADDR(hba, ranges->mem_end);
+
 	DBG_RES("pcibios_fixup_pbus_ranges(%02x, [%lx,%lx %lx,%lx])\n", bus->number,
 		ranges->io_start, ranges->io_end,
 		ranges->mem_start, ranges->mem_end);
+
+	/* KLUGE ALERT
+	** if this resource isn't linked to a "parent", then it seems
+	** to be a child of the HBA - lets link it in.
+	*/
+	pcibios_link_hba_resources(&hba->io_space, bus->resource[0]);
+	pcibios_link_hba_resources(&hba->lmmio_space, bus->resource[1]);
 }
 
 #define MAX(val1, val2)   ((val1) > (val2) ? (val1) : (val2))
@@ -360,107 +412,15 @@
 	/*
 	** WARNING : caller is expected to update "end" field.
 	** We can't since it might really represent the *size*.
-	** The difference is "end = start + size" vs "end += size".
+	** The difference is "end = start + size" vs "end += start".
 	*/
 }
 
 
-#define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
-
-void __devinit
-pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
-{
-	struct pbus_set_ranges_data inner;
-	struct pci_dev *dev;
-	struct pci_dev *bridge = bus->self;
-	struct list_head *ln;
-
-	/* set reasonable default "window" for pcibios_align_resource */
-	inner.io_start  = inner.io_end  = 0;
-	inner.mem_start = inner.mem_end = 0;
-
-	/* Collect information about how our direct children are layed out. */
-	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
-		int i;
-		dev = pci_dev_b(ln);
-
-		/* Skip bridges here - we'll catch them below */
-		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
-			continue;
-
-		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-			struct resource res;
-			unsigned long size;
-
-			if (dev->resource[i].flags == 0)
-				continue;
-
-			memcpy(&res, &dev->resource[i], sizeof(res));
-			size = res.end - res.start + 1;
-
-			if (res.flags & IORESOURCE_IO) {
-				res.start = inner.io_end;
-				pcibios_align_resource(dev, &res, size);
-				inner.io_end += res.start + size;
-			} else if (res.flags & IORESOURCE_MEM) {
-				res.start = inner.mem_end;
-				pcibios_align_resource(dev, &res, size);
-				inner.mem_end = res.start + size;
-			}
-
-		DBG_RES("    %s  inner size %lx/%x IO %lx MEM %lx\n",
-			dev->slot_name,
-			size, res.flags, inner.io_end, inner.mem_end);
-		}
-	}
-
-	/* And for all of the subordinate busses. */
-	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
-		pcibios_size_bridge(pci_bus_b(ln), &inner);
-
-	/* turn the ending locations into sizes (subtract start) */
-	inner.io_end -= inner.io_start - 1;
-	inner.mem_end -= inner.mem_start - 1;
-
-	/* Align the sizes up by bridge rules */
-	inner.io_end = ROUND_UP(inner.io_end, 4*1024) - 1;
-	inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024) - 1;
-
-	/* PPB - PCI bridge Device will normaller also have "outer" != NULL. */
-	if (bridge) {
-		/* Adjust the bus' allocation requirements */
-		/* PPB's pci device Bridge resources */
-
-		bus->resource[0] = &bridge->resource[PCI_BRIDGE_RESOURCES];
-		bus->resource[1] = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
-		
-		bus->resource[0]->start = bus->resource[1]->start  = 0;
-		bus->resource[0]->parent= bus->resource[1]->parent = NULL;
-
-		bus->resource[0]->end    = inner.io_end;
-		bus->resource[0]->flags  = IORESOURCE_IO;
-
-		bus->resource[1]->end    = inner.mem_end;
-		bus->resource[1]->flags  = IORESOURCE_MEM;
-	}
-
-	/* adjust parent's resource requirements */
-	if (outer) {
-		outer->io_end = ROUND_UP(outer->io_end, 4*1024);
-		outer->io_end += inner.io_end;
-
-		outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024);
-		outer->mem_end += inner.mem_end;
-	}
-}
-
-#undef ROUND_UP
-
-
 int __devinit
 pcibios_enable_device(struct pci_dev *dev)
 {
-	u16 cmd, old_cmd;
+	u16 cmd;
 	int idx;
 
 	/*
@@ -468,12 +428,13 @@
 	** enable all the same bits. We just make sure they are here.
 	*/
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	old_cmd = cmd;
 
 	/*
 	** See if any resources have been allocated
+	** While "regular" PCI devices only use 0-5, Bridges use a few
+	** beyond that for window registers.
 	*/
-        for (idx=0; idx<6; idx++) {
+        for (idx=0; idx<DEVICE_COUNT_RESOURCE; idx++) {
 		struct resource *r = &dev->resource[idx];
 		if (r->flags & IORESOURCE_IO)
 			cmd |= PCI_COMMAND_IO;
@@ -482,7 +443,7 @@
 	}
 
 	/*
-	** System error and Parity Error reporting are enabled by default.
+	** Enable System error and Parity Error reporting by default.
 	** Devices that do NOT want those behaviors should clear them
 	** (eg PCI graphics, possibly networking).
 	** Interfaces like SCSI certainly should not. We want the
@@ -491,30 +452,48 @@
 	*/
 	cmd |= (PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
 
-	if (cmd != old_cmd) {
-		printk("PCIBIOS: Enabling device %s (%04x -> %04x)\n",
-			dev->slot_name, old_cmd, cmd);
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
-	}
+	/* If bridge/bus controller has FBB enabled, child must too. */
+	if (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_FAST_BACK)
+		cmd |= PCI_COMMAND_FAST_BACK;
 
+	DBGC("PCIBIOS: Enabling device %s cmd 0x%04x\n", dev->slot_name, cmd);
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
 	return 0;
 }
 
-
-void __devinit
-pcibios_assign_unassigned_resources(struct pci_bus *bus)
+void __init
+pcibios_setup_host_bridge(struct pci_bus *bus)
 {
-	struct list_head *ln;
+	ASSERT(pci_bios != NULL);
 
-        for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next)
+#if 0
+	if (pci_bios)
 	{
-		pdev_assign_unassigned_resources(pci_dev_b(ln));
+		if (pci_bios->setup_host_bridge) {
+			(*pci_bios->setup_host_bridge)(bus);
+		}
 	}
+#endif
+}
 
-        /* And for all of the sub-busses.  */
-	for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
-		pcibios_assign_unassigned_resources(pci_bus_b(ln));
 
+/*
+** Mostly copied from drivers/pci/setup-bus.c:pci_assign_unassigned_resources()
+*/
+void __devinit
+pcibios_assign_unassigned_resources(struct pci_bus *bus)
+{
+	/* from drivers/pci/setup-bus.c */
+	extern void pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges);
+
+	struct pbus_set_ranges_data ranges;
+
+	ranges.io_end = ranges.io_start
+				= bus->resource[0]->start + PCIBIOS_MIN_IO;
+	ranges.mem_end = ranges.mem_start
+				= bus->resource[1]->start + PCIBIOS_MIN_MEM;
+	ranges.found_vga = 0;
+	pbus_assign_resources(bus, &ranges);
 }
 
 /*
@@ -522,14 +501,9 @@
 */
 void pcibios_register_hba(struct pci_hba_data *hba)
 {
-	hba->next = hba_list;
-	hba_list = hba;
-
-	ASSERT(hba_count < PCI_HBA_MAX);
+	ASSERT(pci_hba_count < PCI_HBA_MAX);
 
-	/*
-	** pci_port->in/out() uses parisc_pci_hba to lookup parameter.
-	*/
-	parisc_pci_hba[hba_count] = hba;
-	hba->hba_num = hba_count++;
+	/* pci_port->in/out() uses parisc_pci_hba to lookup parameter. */
+	parisc_pci_hba[pci_hba_count] = hba;
+	hba->hba_num = pci_hba_count++;
 }
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/pdc.c linux-2.4.20-pre2/arch/parisc/kernel/pdc.c
--- linux-2.4.20-pre1/arch/parisc/kernel/pdc.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/pdc.c	Wed Dec 31 16:00:00 1969
@@ -1,217 +0,0 @@
-/* arch/parisc/kernel/pdc.c  - safe pdc access routines
- *
- * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
- * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
- *
- * only these routines should be used out of the real kernel (i.e. everything
- * using virtual addresses) for obvious reasons */
-
-/*	I think it would be in everyone's best interest to follow this
- *	guidelines when writing PDC wrappers:
- *
- *	 - the name of the pdc wrapper should match one of the macros
- *	   used for the first two arguments
- *	 - don't use caps for random parts of the name
- *	 - use ASSERT_ALIGN to ensure the aligment of the arguments is
- *	   correct
- *	 - use __pa() to convert virtual (kernel) pointers to physical
- *	   ones.
- *	 - the name of the struct used for pdc return values should equal
- *	   one of the macros used for the first two arguments to the
- *	   corresponding PDC call
- *	 - keep the order of arguments
- *	 - don't be smart (setting trailing NUL bytes for strings, return
- *	   something useful even if the call failed) unless you are sure
- *	   it's not going to affect functionality or performance
- *
- *	Example:
- *	int pdc_cache_info(struct pdc_cache_info *cache_info )
- *	{
- *		ASSERT_ALIGN(cache_info, 8);
- *	
- *		return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
- *	}
- *					prumpf	991016	
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/page.h>
-#include <asm/pdc.h>
-#include <asm/real.h>
-#include <asm/system.h>
-
-
-#define ASSERT_ALIGN(ptr, align)					\
-	do { if(((unsigned long)(ptr)) & (align-1)) {			\
-		printk("PDC: %s:%d  %s() called with "	\
-			"unaligned argument from %p", __FILE__, __LINE__, \
-			__FUNCTION__, __builtin_return_address(0));	\
-									\
-		return -1;						\
-	} } while(0)
-	
-/* verify address can be accessed without an HPMC */
-int pdc_add_valid(void *address)
-{
-	ASSERT_ALIGN(address, 4);
-
-	return mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, (unsigned long)address);
-}
-
-#if 0
-int pdc_chassis_warn(struct pdc_chassis_warn *address)
-{
-	ASSERT_ALIGN(address, 4);
-
-	return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(address), 0);
-}
-#endif
-
-int pdc_chassis_disp(unsigned long disp)
-{
-	return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp);
-}
-
-int pdc_chassis_info(void *pdc_result, void *chassis_info, unsigned long len)
-{
-	ASSERT_ALIGN(pdc_result, 4);
-	ASSERT_ALIGN(chassis_info, 4);
-	return mem_pdc_call(PDC_CHASSIS,PDC_RETURN_CHASSIS_INFO, 
-	        __pa(pdc_result), __pa(chassis_info), len);
-}
-
-int pdc_hpa_processor(void *address)
-{
-	/* We're using 0 for the last parameter just to make sure.
-	   It's actually HVERSION dependant.  And remember, life is
-	   hard without a backspace. */
-	ASSERT_ALIGN(address, 4);
-
-	return mem_pdc_call(PDC_HPA, PDC_HPA_PROCESSOR, __pa(address),0);
-}
-
-#if 0
-int pdc_hpa_modules(void *address)
-{
-	return mem_pdc_call(PDC_HPA, PDC_HPA_MODULES, address);
-}
-#endif
-
-int pdc_iodc_read(void *address, void * hpa, unsigned int index,
-	void * iodc_data, unsigned int iodc_data_size)
-{
-	ASSERT_ALIGN(address, 4);
-	ASSERT_ALIGN(iodc_data, 8);
-	return mem_pdc_call(PDC_IODC, PDC_IODC_READ, 
-		__pa(address), hpa, index, __pa(iodc_data), iodc_data_size);
-}
-
-
-int pdc_system_map_find_mods(void *pdc_mod_info, 
-	void *mod_path, int index)
-{
-	return mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE,
-		__pa(pdc_mod_info), __pa(mod_path), (long)index);
-}
-
-
-int pdc_model_info(struct pdc_model *model) {
-	ASSERT_ALIGN(model, 8);
-	return mem_pdc_call(PDC_MODEL,PDC_MODEL_INFO,__pa(model),0);
-}
-
-/* get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L) */ 
-int pdc_model_sysmodel(char * name)
-{
-	struct pdc_model_sysmodel sys_model;
-	int retval;
-	
-	ASSERT_ALIGN(&sys_model, 8);
-	ASSERT_ALIGN(name, 4);
-
-	sys_model.mod_len = 0;
-	retval = mem_pdc_call(PDC_MODEL,PDC_MODEL_SYSMODEL,__pa(&sys_model),
-		    OS_ID_HPUX,__pa(name));
-	
-	if (retval == PDC_RET_OK) 
-	    name[sys_model.mod_len] = '\0'; /* add trailing '\0' */
-	else
-	    name[0] = 0;
-	
-	return retval;
-}
-
-/* id: 0 = cpu revision, 1 = boot-rom-version */
-int pdc_model_versions(struct pdc_model_cpuid *cpu_id, int id) {
-	return mem_pdc_call(PDC_MODEL,PDC_MODEL_VERSIONS,__pa(cpu_id),id);
-}
-
-int pdc_model_cpuid(struct pdc_model_cpuid *cpu_id) {
-	cpu_id->cpuid = 0; /* preset zero (call maybe not implemented!) */
-	return mem_pdc_call(PDC_MODEL,6,__pa(cpu_id),0);  /* 6="return CPU ID" */
-}
-
-int pdc_cache_info(struct pdc_cache_info *cache_info) {
-	ASSERT_ALIGN(cache_info, 8);
-
-	return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
-}
-
-#ifndef __LP64__
-int pdc_btlb_info( struct pdc_btlb_info *btlb ) {
-	int status;
-	status = mem_pdc_call(PDC_BLOCK_TLB,PDC_BTLB_INFO,__pa(btlb),0);
-	if (status<0) btlb->max_size = 0;
-	return status;
-}
-
-int pdc_mem_map_hpa(void *r_addr, void *mod_path) {
-	return mem_pdc_call(PDC_MEM_MAP,PDC_MEM_MAP_HPA,
-		__pa(r_addr),__pa(mod_path));
-}
-
-int pdc_lan_station_id(char *lan_addr, void *net_hpa) {
-	struct pdc_lan_station_id id;
-	unsigned char *addr;
-	
-	if (mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ,
-			__pa(&id), net_hpa) < 0)
-		addr = 0;	/* FIXME: else read MAC from NVRAM */
-	    else
-		addr = id.addr;
-	if (addr)
-		memmove( lan_addr, addr, PDC_LAN_STATION_ID_SIZE);
-	    else
-		memset( lan_addr, 0, PDC_LAN_STATION_ID_SIZE);
-	return (addr != 0);
-}
-#endif
-
-
-/* Similar to PDC_PAT stuff in pdcpat.c - but added for Forte/Allegro boxes */
-int pdc_pci_irt_size(void *r_addr, void *hpa)
-{
-	return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE,
-		__pa(r_addr), hpa);
-
-}
-
-int pdc_pci_irt(void *r_addr, void *hpa, void *tbl)
-{
-	return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL,
-		__pa(r_addr), hpa, __pa(tbl));
-}
-
-/* access the TOD clock */
-int pdc_tod_read(struct pdc_tod *tod)
-{
-	ASSERT_ALIGN(tod, 8);
-	return mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(tod), 0);
-}
-
-int pdc_tod_set(unsigned long sec, unsigned long usec)
-{
-	return mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec);
-}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/pdc_cons.c linux-2.4.20-pre2/arch/parisc/kernel/pdc_cons.c
--- linux-2.4.20-pre1/arch/parisc/kernel/pdc_cons.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/parisc/kernel/pdc_cons.c	Mon Aug 12 16:34:14 2002
@@ -1,100 +1,49 @@
+/*
+ *  linux/arch/parisc/kernel/pdc_console.c
+ *
+ *  The PDC console is a simple console, which can be used for debugging 
+ *  boot related problems on HP PA-RISC machines.
+ *
+ *  This code uses the ROM (=PDC) based functions to read and write characters
+ *  from and to PDC's boot path.
+ *  Since all character read from that path must be polled, this code never
+ *  can or will be a fully functional linux console.
+ */
+
+/* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems. 
+ * On production kernels EARLY_BOOTUP_DEBUG should be undefined. */
+#undef EARLY_BOOTUP_DEBUG
+
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/console.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <asm/page.h>
 #include <asm/types.h>
 #include <asm/system.h>
-#include <asm/pdc.h>	/* for iodc_call() proto and friends */
-#include <asm/real.h>
+#include <asm/pdc.h>		/* for iodc_call() proto and friends */
 
-static int __attribute__((aligned(8)))   iodc_retbuf[32];
-static char __attribute__((aligned(64))) iodc_dbuf[4096];
-
-/*
- * pdc_putc:
- * Console character print using IODC.
- *
- * Note that only these special chars are architected for console IODC io:
- * BEL, BS, CR, and LF. Others are passed through.
- * Since the HP console requires CR+LF to perform a 'newline', we translate
- * "\n" to "\r\n".
- */
-
-static int posx;	/* for simple TAB-Simulation... */
-
-/* XXX Should we spinlock posx usage */
-
-void pdc_putc(unsigned char c)
-{
-	unsigned int n;
-	unsigned long flags;
-
-	switch (c) {
-	case '\n':
-		iodc_dbuf[0] = '\r'; 
-		iodc_dbuf[1] = '\n';
-               	n = 2;
-               	posx = 0;
-		break;
-	case '\t':
-		pdc_putc(' ');
-		while (posx & 7) 	/* expand TAB */
-			pdc_putc(' ');
-		return;		/* return since IODC can't handle this */
-	case '\b':
-		posx-=2;		/* BS */
-	default:
-		iodc_dbuf[0] = c;
-		n = 1;
-		posx++;
-		break;
-	}
-	{
-		real32_call(PAGE0->mem_cons.iodc_io,
-			(unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
-			PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
-			__pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
-	}
-}
 
 static void pdc_console_write(struct console *co, const char *s, unsigned count)
 {
 	while(count--)
-		pdc_putc(*s++);
+		pdc_iodc_putc(*s++);
 }
 
-int pdc_console_wait_key(struct console *co)
+void pdc_outc(unsigned char c)
 {
-	int ch = 'X';
-	int status;
-
-	/* Bail if no console input device. */
-	if (!PAGE0->mem_kbd.iodc_io)
-		return 0;
-	
-	/* wait for a keyboard (rs232)-input */
-	do {
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-		status = real32_call(PAGE0->mem_kbd.iodc_io,
-			(unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN,
-			PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers),
-			__pa(iodc_retbuf), 0, __pa(iodc_dbuf), 1, 0);
-		restore_flags(flags);
-		ch = *iodc_dbuf;	/* save the character directly to ch */
-	} while (*iodc_retbuf == 0);	/* wait for a key */
-	return ch;
+	pdc_iodc_outc(c);
 }
 
-int pdc_getc(void)
+
+int pdc_console_poll_key(struct console *co)
 {
-	return pdc_console_wait_key(NULL);
+	return pdc_iodc_getc();
 }
 
 static int pdc_console_setup(struct console *co, char *options)
@@ -102,17 +51,34 @@
 	return 0;
 }
 
+#ifdef CONFIG_PDC_CONSOLE
+static kdev_t pdc_console_device (struct console *c)
+{
+        return MKDEV(PDCCONS_MAJOR, 0);
+}
+#endif
+
+#ifdef CONFIG_PDC_CONSOLE
+#define PDC_CONSOLE_DEVICE pdc_console_device
+#else
+#define PDC_CONSOLE_DEVICE NULL
+#endif
+
 static struct console pdc_cons = {
 	name:		"ttyB",
 	write:		pdc_console_write,
+ 	device:		PDC_CONSOLE_DEVICE,
 	setup:		pdc_console_setup,
-	flags:		CON_PRINTBUFFER|CON_ENABLED,  // |CON_CONSDEV,
+	flags:		CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
 	index:		-1,
 };
 
 static int pdc_console_initialized;
 
-void pdc_console_init(void)
+extern unsigned long con_start;	/* kernel/printk.c */
+extern unsigned long log_end;	/* kernel/printk.c */
+  
+static void pdc_console_init_force(void)
 {
 	if (pdc_console_initialized)
 		return;
@@ -122,23 +88,32 @@
 	if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
 		memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons));
 
-	pdc_console_write(0, "PDC Console Initialized\n", 24);
 	/* register the pdc console */
 	register_console(&pdc_cons);
 }
 
+void pdc_console_init(void)
+{
+#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
+	pdc_console_init_force();
+#endif
+#ifdef EARLY_BOOTUP_DEBUG
+	printk(KERN_INFO "Initialized PDC Console for debugging.\n");
+#endif
+}
+
 
 /* Unregister the pdc console with the printk console layer */
 void pdc_console_die(void)
 {
-	printk("Switching from PDC console\n");
 	if (!pdc_console_initialized)
 		return;
 	--pdc_console_initialized;
-	
-#ifdef CONFIG_VT_CONSOLE
-	schedule_console_callback();
-#endif
+
+	printk(KERN_INFO "Switching from PDC console\n");
+
+	/* Don't repeat what we've already printed */
+	con_start = log_end;
 
 	unregister_console(&pdc_cons);
 }
@@ -155,17 +130,17 @@
 void pdc_console_restart(void)
 {
 	struct console *console;
-	extern int log_size;
 
 	if (pdc_console_initialized)
 		return;
 
-	while ((console = console_drivers) != (struct console *)0)
+	while ((console = console_drivers) != NULL)
 		unregister_console(console_drivers);
 
-	log_size = 0;
-	pdc_console_init();
-	printk("Switched to PDC console\n");
-	return;
+	/* Don't repeat what we've already printed */
+	con_start = log_end;
+	
+	/* force registering the pdc console */
+	pdc_console_init_force();
 }
 
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/perf.c linux-2.4.20-pre2/arch/parisc/kernel/perf.c
--- linux-2.4.20-pre1/arch/parisc/kernel/perf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/perf.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,838 @@
+/*
+ *  Parisc performance counters
+ *  Copyright (C) 2001 Randolph Chung <tausq@debian.org>
+ *
+ *  This code is derived, with permission, from HP/UX sources.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  Edited comment from original sources:
+ *
+ *  This driver programs the PCX-U/PCX-W performance counters
+ *  on the PA-RISC 2.0 chips.  The driver keeps all images now
+ *  internally to the kernel to hopefully eliminate the possiblity
+ *  of a bad image halting the CPU.  Also, there are different
+ *  images for the PCX-W and later chips vs the PCX-U chips.
+ *
+ *  Only 1 process is allowed to access the driver at any time,
+ *  so the only protection that is needed is at open and close.
+ *  A variable "perf_enabled" is used to hold the state of the
+ *  driver.  The spinlock "perf_lock" is used to protect the
+ *  modification of the state during open/close operations so
+ *  multiple processes don't get into the driver simultaneously.
+ *
+ *  This driver accesses the processor directly vs going through
+ *  the PDC INTRIGUE calls.  This is done to eliminate bugs introduced
+ *  in various PDC revisions.  The code is much more maintainable
+ *  and reliable this way vs having to debug on every version of PDC
+ *  on every box. 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+
+#include <asm/gsc.h>
+#include <asm/uaccess.h>
+#include <asm/perf.h>
+#include <asm/processor.h>
+
+#include "perf_images.h"
+
+#define MAX_RDR_WORDS	24
+#define PERF_VERSION	2	/* derived from hpux's PI v2 interface */
+
+/* definition of RDR regs */
+struct rdr_tbl_ent {
+	uint16_t	width;
+	uint8_t		num_words;
+	uint8_t		write_control;
+};
+
+static int perf_processor_interface = UNKNOWN_INTF;
+static int perf_enabled = 0;
+static spinlock_t perf_lock;
+struct parisc_device *cpu_device = NULL;
+
+/* RDRs to write for PCX-W */
+static int perf_rdrs_W[] = 
+	{ 0, 1, 4, 5, 6, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 };
+
+/* RDRs to write for PCX-U */
+static int perf_rdrs_U[] =
+	{ 0, 1, 4, 5, 6, 7, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 };
+
+/* RDR register descriptions for PCX-W */
+static struct rdr_tbl_ent perf_rdr_tbl_W[] = {
+	{ 19,	1,	8 },   /* RDR 0 */
+	{ 16,	1,	16 },  /* RDR 1 */
+	{ 72,	2,	0 },   /* RDR 2 */
+	{ 81,	2,	0 },   /* RDR 3 */
+	{ 328,	6,	0 },   /* RDR 4 */
+	{ 160,	3,	0 },   /* RDR 5 */
+	{ 336,	6,	0 },   /* RDR 6 */
+	{ 164,	3,	0 },   /* RDR 7 */
+	{ 0,	0,	0 },   /* RDR 8 */
+	{ 35,	1,	0 },   /* RDR 9 */
+	{ 6,	1,	0 },   /* RDR 10 */
+	{ 18,	1,	0 },   /* RDR 11 */
+	{ 13,	1,	0 },   /* RDR 12 */
+	{ 8,	1,	0 },   /* RDR 13 */
+	{ 8,	1,	0 },   /* RDR 14 */
+	{ 8,	1,	0 },   /* RDR 15 */
+	{ 1530,	24,	0 },   /* RDR 16 */
+	{ 16,	1,	0 },   /* RDR 17 */
+	{ 4,	1,	0 },   /* RDR 18 */
+	{ 0,	0,	0 },   /* RDR 19 */
+	{ 152,	3,	24 },  /* RDR 20 */
+	{ 152,	3,	24 },  /* RDR 21 */
+	{ 233,	4,	48 },  /* RDR 22 */
+	{ 233,	4,	48 },  /* RDR 23 */
+	{ 71,	2,	0 },   /* RDR 24 */
+	{ 71,	2,	0 },   /* RDR 25 */
+	{ 11,	1,	0 },   /* RDR 26 */
+	{ 18,	1,	0 },   /* RDR 27 */
+	{ 128,	2,	0 },   /* RDR 28 */
+	{ 0,	0,	0 },   /* RDR 29 */
+	{ 16,	1,	0 },   /* RDR 30 */
+	{ 16,	1,	0 },   /* RDR 31 */
+};
+
+/* RDR register descriptions for PCX-U */
+static struct rdr_tbl_ent perf_rdr_tbl_U[] = {
+	{ 19,	1,	8 },              /* RDR 0 */
+	{ 32,	1,	16 },             /* RDR 1 */
+	{ 20,	1,	0 },              /* RDR 2 */
+	{ 0,	0,	0 },              /* RDR 3 */
+	{ 344,	6,	0 },              /* RDR 4 */
+	{ 176,	3,	0 },              /* RDR 5 */
+	{ 336,	6,	0 },              /* RDR 6 */
+	{ 0,	0,	0 },              /* RDR 7 */
+	{ 0,	0,	0 },              /* RDR 8 */
+	{ 0,	0,	0 },              /* RDR 9 */
+	{ 28,	1,	0 },              /* RDR 10 */
+	{ 33,	1,	0 },              /* RDR 11 */
+	{ 0,	0,	0 },              /* RDR 12 */
+	{ 230,	4,	0 },              /* RDR 13 */
+	{ 32,	1,	0 },              /* RDR 14 */
+	{ 128,	2,	0 },              /* RDR 15 */
+	{ 1494,	24,	0 },              /* RDR 16 */
+	{ 18,	1,	0 },              /* RDR 17 */
+	{ 4,	1,	0 },              /* RDR 18 */
+	{ 0,	0,	0 },              /* RDR 19 */
+	{ 158,	3,	24 },             /* RDR 20 */
+	{ 158,	3,	24 },             /* RDR 21 */
+	{ 194,	4,	48 },             /* RDR 22 */
+	{ 194,	4,	48 },             /* RDR 23 */
+	{ 71,	2,	0 },              /* RDR 24 */
+	{ 71,	2,	0 },              /* RDR 25 */
+	{ 28,	1,	0 },              /* RDR 26 */
+	{ 33,	1,	0 },              /* RDR 27 */
+	{ 88,	2,	0 },              /* RDR 28 */
+	{ 32,	1,	0 },              /* RDR 29 */
+	{ 24,	1,	0 },              /* RDR 30 */
+	{ 16,	1,	0 },              /* RDR 31 */
+};
+
+/*
+ * A non-zero write_control in the above tables is a byte offset into
+ * this array.
+ */
+static uint64_t perf_bitmasks[] = {
+	0x0000000000000000,     /* first dbl word must be zero */
+	0xfdffe00000000000,     /* RDR0 bitmask */
+	0x003f000000000000,     /* RDR1 bitmask */
+	0x00ffffffffffffff,     /* RDR20-RDR21 bitmask (152 bits) */
+	0xffffffffffffffff,
+	0xfffffffc00000000,
+	0xffffffffffffffff,     /* RDR22-RDR23 bitmask (233 bits) */
+	0xffffffffffffffff,
+	0xfffffffffffffffc,
+	0xff00000000000000
+};
+
+/*
+ * Write control bitmasks for Pa-8700 processor given
+ * somethings have changed slightly.
+ */
+static uint64_t perf_bitmasks_piranha[] = {
+	0x0000000000000000,     /* first dbl word must be zero */
+	0xfdffe00000000000,     /* RDR0 bitmask */
+	0x003f000000000000,     /* RDR1 bitmask */
+	0x00ffffffffffffff,     /* RDR20-RDR21 bitmask (158 bits) */
+	0xffffffffffffffff,
+	0xfffffffc00000000,
+	0xffffffffffffffff,     /* RDR22-RDR23 bitmask (210 bits) */
+	0xffffffffffffffff,
+	0xffffffffffffffff,
+	0xfffc000000000000
+};
+
+static uint64_t *bitmask_array;   /* array of bitmasks to use */
+
+/******************************************************************************
+ * Function Prototypes
+ *****************************************************************************/
+static int perf_config(uint32_t *image_ptr);
+static int perf_release(struct inode *inode, struct file *file);
+static int perf_open(struct inode *inode, struct file *file);
+static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos);
+static ssize_t perf_write(struct file *file, const char *buf, size_t count, 
+	loff_t *ppos);
+static int perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg);
+static void perf_start_counters(void);
+static int perf_stop_counters(uint32_t *raddr);
+static struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num);
+static int perf_rdr_read_ubuf(uint32_t	rdr_num, uint64_t *buffer);
+static int perf_rdr_clear(uint32_t rdr_num);
+static int perf_write_image(uint64_t *memaddr);
+static void perf_rdr_write(uint32_t rdr_num, uint64_t *buffer);
+
+/* External Assembly Routines */
+extern uint64_t perf_rdr_shift_in_W (uint32_t rdr_num, uint16_t width);
+extern uint64_t perf_rdr_shift_in_U (uint32_t rdr_num, uint16_t width);
+extern void perf_rdr_shift_out_W (uint32_t rdr_num, uint64_t buffer);
+extern void perf_rdr_shift_out_U (uint32_t rdr_num, uint64_t buffer);
+extern void perf_intrigue_enable_perf_counters (void);
+extern void perf_intrigue_disable_perf_counters (void);
+
+/******************************************************************************
+ * Function Definitions
+ *****************************************************************************/
+
+
+/*
+ * configure:
+ *
+ * Configure the cpu with a given data image.  First turn off the counters, 
+ * then download the image, then turn the counters back on.
+ */
+static int perf_config(uint32_t *image_ptr)
+{
+	long error;
+	uint32_t raddr[4];
+
+	/* Stop the counters*/
+	error = perf_stop_counters(raddr);
+	if (error != 0) {
+		printk("perf_config: perf_stop_counters = %ld\n", error);
+		return -EINVAL; 
+	}
+
+printk("Preparing to write image\n");
+	/* Write the image to the chip */
+	error = perf_write_image((uint64_t *)image_ptr);
+	if (error != 0) {
+		printk("perf_config: DOWNLOAD = %ld\n", error);
+		return -EINVAL; 
+	}
+
+printk("Preparing to start counters\n");
+
+	/* Start the counters */
+	perf_start_counters();
+
+	return sizeof(uint32_t);
+}
+
+/*
+ * Open the device and initialize all of it's memory.  The device is only 
+ * opened once, but can be "queried" by multiple processes that know its
+ * file descriptor.
+ */
+static int perf_open(struct inode *inode, struct file *file)
+{
+	spin_lock(&perf_lock);
+	if (perf_enabled) {
+		spin_unlock(&perf_lock);
+		return -EBUSY;
+	}
+	perf_enabled = 1;
+ 	spin_unlock(&perf_lock);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Close the device.
+ */
+static int perf_release(struct inode *inode, struct file *file)
+{
+	spin_lock(&perf_lock);
+	perf_enabled = 0;
+	spin_unlock(&perf_lock);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Read does nothing for this driver
+ */
+static ssize_t perf_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
+{
+	return 0;
+}
+
+/*
+ * write:
+ *
+ * This routine downloads the image to the chip.  It must be
+ * called on the processor that the download should happen
+ * on.
+ */
+static ssize_t perf_write(struct file *file, const char *buf, size_t count, 
+	loff_t *ppos)
+{
+	int err;
+	size_t image_size;
+	uint32_t image_type;
+	uint32_t interface_type;
+	uint32_t test;
+
+	if (perf_processor_interface == ONYX_INTF) 
+		image_size = PCXU_IMAGE_SIZE;
+	else if (perf_processor_interface == CUDA_INTF) 
+		image_size = PCXW_IMAGE_SIZE;
+	else 
+		return -EFAULT;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (count != sizeof(uint32_t))
+		return -EIO;
+
+	if ((err = copy_from_user(&image_type, buf, sizeof(uint32_t))) != 0) 
+		return err;
+
+	/* Get the interface type and test type */
+   	interface_type = (image_type >> 16) & 0xffff;
+	test           = (image_type & 0xffff);
+
+	/* Make sure everything makes sense */
+
+	/* First check the machine type is correct for
+	   the requested image */
+        if (((perf_processor_interface == CUDA_INTF) &&
+		       (interface_type != CUDA_INTF)) ||
+	    ((perf_processor_interface == ONYX_INTF) &&
+	               (interface_type != ONYX_INTF))) 
+		return -EINVAL;
+
+	/* Next check to make sure the requested image
+	   is valid */
+	if (((interface_type == CUDA_INTF) && 
+		       (test >= MAX_CUDA_IMAGES)) ||
+	    ((interface_type == ONYX_INTF) && 
+		       (test >= MAX_ONYX_IMAGES))) 
+		return -EINVAL;
+
+	/* Copy the image into the processor */
+	if (interface_type == CUDA_INTF) 
+		return perf_config(cuda_images[test]);
+	else
+		return perf_config(onyx_images[test]);
+
+	return count;
+}
+
+/*
+ * Patch the images that need to know the IVA addresses.
+ */
+static void perf_patch_images(void)
+{
+#if 0 /* FIXME!! */
+/* 
+ * NOTE:  this routine is VERY specific to the current TLB image.
+ * If the image is changed, this routine might also need to be changed.
+ */
+	extern void $i_itlb_miss_2_0();
+	extern void $i_dtlb_miss_2_0();
+	extern void PA2_0_iva();
+
+	/* 
+	 * We can only use the lower 32-bits, the upper 32-bits should be 0
+	 * anyway given this is in the kernel 
+	 */
+	uint32_t itlb_addr  = (uint32_t)&($i_itlb_miss_2_0);
+	uint32_t dtlb_addr  = (uint32_t)&($i_dtlb_miss_2_0);
+	uint32_t IVAaddress = (uint32_t)&PA2_0_iva;
+
+	if (perf_processor_interface == ONYX_INTF) {
+		/* clear last 2 bytes */
+		onyx_images[TLBMISS][15] &= 0xffffff00;  
+		/* set 2 bytes */
+		onyx_images[TLBMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
+		onyx_images[TLBMISS][16] = (dtlb_addr << 8)&0xffffff00;
+		onyx_images[TLBMISS][17] = itlb_addr;
+
+		/* clear last 2 bytes */
+		onyx_images[TLBHANDMISS][15] &= 0xffffff00;  
+		/* set 2 bytes */
+		onyx_images[TLBHANDMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
+		onyx_images[TLBHANDMISS][16] = (dtlb_addr << 8)&0xffffff00;
+		onyx_images[TLBHANDMISS][17] = itlb_addr;
+
+		/* clear last 2 bytes */
+		onyx_images[BIG_CPI][15] &= 0xffffff00;  
+		/* set 2 bytes */
+		onyx_images[BIG_CPI][15] |= (0x000000ff&((dtlb_addr) >> 24));
+		onyx_images[BIG_CPI][16] = (dtlb_addr << 8)&0xffffff00;
+		onyx_images[BIG_CPI][17] = itlb_addr;
+
+	    onyx_images[PANIC][15] &= 0xffffff00;  /* clear last 2 bytes */
+	 	onyx_images[PANIC][15] |= (0x000000ff&((IVAaddress) >> 24)); /* set 2 bytes */
+		onyx_images[PANIC][16] = (IVAaddress << 8)&0xffffff00;
+
+
+	} else if (perf_processor_interface == CUDA_INTF) {
+		/* Cuda interface */
+		cuda_images[TLBMISS][16] =  
+			(cuda_images[TLBMISS][16]&0xffff0000) |
+			((dtlb_addr >> 8)&0x0000ffff);
+		cuda_images[TLBMISS][17] = 
+			((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
+		cuda_images[TLBMISS][18] = (itlb_addr << 16)&0xffff0000;
+
+		cuda_images[TLBHANDMISS][16] = 
+			(cuda_images[TLBHANDMISS][16]&0xffff0000) |
+			((dtlb_addr >> 8)&0x0000ffff);
+		cuda_images[TLBHANDMISS][17] = 
+			((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
+		cuda_images[TLBHANDMISS][18] = (itlb_addr << 16)&0xffff0000;
+
+		cuda_images[BIG_CPI][16] = 
+			(cuda_images[BIG_CPI][16]&0xffff0000) |
+			((dtlb_addr >> 8)&0x0000ffff);
+		cuda_images[BIG_CPI][17] = 
+			((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
+		cuda_images[BIG_CPI][18] = (itlb_addr << 16)&0xffff0000;
+	} else {
+		/* Unknown type */
+	}
+#endif
+}
+
+
+/*
+ * ioctl routine
+ * All routines effect the processor that they are executed on.  Thus you 
+ * must be running on the processor that you wish to change.
+ */
+
+static int perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	long error_start;
+	uint32_t raddr[4];	
+
+	switch (cmd) {
+
+	    case PA_PERF_ON:
+			/* Start the counters */
+			perf_start_counters();
+			return 0;
+
+	    case PA_PERF_OFF:
+			error_start = perf_stop_counters(raddr);
+			if (error_start != 0) {
+				printk(KERN_ERR "perf_off: perf_stop_counters = %ld\n", error_start);
+				return -EFAULT;	
+			}
+
+			/* copy out the Counters */
+			if (copy_to_user((void *)arg, raddr, 
+					sizeof (raddr)) != 0) {
+				return -EFAULT;
+			}
+			return 0;
+
+	    case PA_PERF_VERSION:
+  	  		/* Return the version # */
+			return put_user(PERF_VERSION, (int *)arg);
+
+	    default:
+  	 		break;
+	}
+	return -ENOTTY;
+}
+
+static struct file_operations perf_fops = {
+	llseek: no_llseek,
+	read: perf_read,
+	write: perf_write,
+	ioctl: perf_ioctl,
+	open: perf_open,
+	release: perf_release
+};
+	
+static struct miscdevice perf_dev = {
+	MISC_DYNAMIC_MINOR,
+	PA_PERF_DEV,
+	&perf_fops
+};
+
+/*
+ * Initialize the module
+ */
+static int __init perf_init(void)
+{
+	/* Determine correct processor interface to use */
+	bitmask_array = perf_bitmasks;
+
+	if (boot_cpu_data.cpu_type == pcxu ||
+	    boot_cpu_data.cpu_type == pcxu_) {
+		perf_processor_interface = ONYX_INTF;
+	} else if (boot_cpu_data.cpu_type == pcxw ||
+		 boot_cpu_data.cpu_type == pcxw_ ||
+		 boot_cpu_data.cpu_type == pcxw2) {
+		perf_processor_interface = CUDA_INTF;
+		if (boot_cpu_data.cpu_type == pcxw2) 
+			bitmask_array = perf_bitmasks_piranha;
+	} else {
+		perf_processor_interface = UNKNOWN_INTF;
+		printk("Performance monitoring counters not supported on this processor\n");
+		return -ENODEV;
+	}
+
+	/* Patch the images to match the system */
+    	perf_patch_images();
+
+	spin_lock_init(&perf_lock);
+	misc_register(&perf_dev);
+
+	/* TODO: this only lets us access the first cpu.. what to do for SMP? */
+	cpu_device = cpu_data[0].dev;
+	printk("Performance monitoring counters enabled for %s\n",
+		cpu_data[0].dev->name);
+
+	return 0;
+}
+
+/*
+ * perf_start_counters(void)
+ *
+ * Start the counters.
+ */
+static void perf_start_counters(void)
+{
+	/* Enable performance monitor counters */
+	perf_intrigue_enable_perf_counters();
+}
+
+/*
+ * perf_stop_counters
+ *
+ * Stop the performance counters and save counts
+ * in a per_processor array.
+ */
+static int perf_stop_counters(uint32_t *raddr)
+{
+	uint64_t userbuf[MAX_RDR_WORDS];
+
+	/* Disable performance counters */
+	perf_intrigue_disable_perf_counters();
+
+	if (perf_processor_interface == ONYX_INTF) {
+		uint64_t tmp64;
+		/*
+		 * Read the counters
+		 */
+		if (!perf_rdr_read_ubuf(16, userbuf))
+			return -13;
+
+		/* Counter0 is bits 1398 thru 1429 */
+		tmp64 =  (userbuf[21] << 22) & 0x00000000ffc00000;
+		tmp64 |= (userbuf[22] >> 42) & 0x00000000003fffff;
+		/* OR sticky0 (bit 1430) to counter0 bit 32 */
+		tmp64 |= (userbuf[22] >> 10) & 0x0000000080000000;
+		raddr[0] = (uint32_t)tmp64;
+
+		/* Counter1 is bits 1431 thru 1462 */
+		tmp64 =  (userbuf[22] >> 9) & 0x00000000ffffffff;
+		/* OR sticky1 (bit 1463) to counter1 bit 32 */
+		tmp64 |= (userbuf[22] << 23) & 0x0000000080000000;
+		raddr[1] = (uint32_t)tmp64;
+
+		/* Counter2 is bits 1464 thru 1495 */
+		tmp64 =  (userbuf[22] << 24) & 0x00000000ff000000;
+		tmp64 |= (userbuf[23] >> 40) & 0x0000000000ffffff;
+		/* OR sticky2 (bit 1496) to counter2 bit 32 */
+		tmp64 |= (userbuf[23] >> 8) & 0x0000000080000000;
+		raddr[2] = (uint32_t)tmp64;
+		
+		/* Counter3 is bits 1497 thru 1528 */
+		tmp64 =  (userbuf[23] >> 7) & 0x00000000ffffffff;
+		/* OR sticky3 (bit 1529) to counter3 bit 32 */
+		tmp64 |= (userbuf[23] << 25) & 0x0000000080000000;
+		raddr[3] = (uint32_t)tmp64;
+
+		/*
+		 * Zero out the counters
+		 */
+
+		/*
+		 * The counters and sticky-bits comprise the last 132 bits
+		 * (1398 - 1529) of RDR16 on a U chip.  We'll zero these
+		 * out the easy way: zero out last 10 bits of dword 21,
+		 * all of dword 22 and 58 bits (plus 6 don't care bits) of
+		 * dword 23.
+		 */
+		userbuf[21] &= 0xfffffffffffffc00;	/* 0 to last 10 bits */
+		userbuf[22] = 0;
+		userbuf[23] = 0;
+
+		/* 
+		 * Write back the zero'ed bytes + the image given
+		 * the read was destructive.
+		 */
+		perf_rdr_write(16, userbuf);
+	} else {
+
+		/*
+		 * Read RDR-15 which contains the counters and sticky bits 
+		 */
+		if (!perf_rdr_read_ubuf(15, userbuf)) {
+			return -13;
+		}
+
+		/* 
+		 * Clear out the counters
+		 */
+		perf_rdr_clear(15);
+
+		/*
+		 * Copy the counters 
+		 */
+		raddr[0] = (uint32_t)((userbuf[0] >> 32) & 0x00000000ffffffffUL);
+		raddr[1] = (uint32_t)(userbuf[0] & 0x00000000ffffffffUL);
+		raddr[2] = (uint32_t)((userbuf[1] >> 32) & 0x00000000ffffffffUL);
+		raddr[3] = (uint32_t)(userbuf[1] & 0x00000000ffffffffUL);
+	}
+ 
+	return 0;
+}
+
+/*
+ * perf_rdr_get_entry
+ *
+ * Retrieve a pointer to the description of what this
+ * RDR contains.
+ */
+static struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num)
+{
+	if (perf_processor_interface == ONYX_INTF) {
+		return &perf_rdr_tbl_U[rdr_num];
+	} else {
+		return &perf_rdr_tbl_W[rdr_num];
+	}
+}
+
+/*
+ * perf_rdr_read_ubuf
+ *
+ * Read the RDR value into the buffer specified.
+ */
+static int perf_rdr_read_ubuf(uint32_t	rdr_num, uint64_t *buffer)
+{
+	uint64_t	data, data_mask = 0;
+	uint32_t	width, xbits, i;
+	struct rdr_tbl_ent *tentry;
+
+	tentry = perf_rdr_get_entry(rdr_num);
+	if ((width = tentry->width) == 0)
+		return 0;
+
+	/* Clear out buffer */
+	i = tentry->num_words;
+	while (i--) {
+		buffer[i] = 0;
+	}	
+
+	/* Check for bits an even number of 64 */
+	if ((xbits = width & 0x03f) != 0) {
+		data_mask = 1;
+		data_mask <<= (64 - xbits);
+		data_mask--;
+	}
+
+	/* Grab all of the data */
+	i = tentry->num_words;
+	while (i--) {
+
+		if (perf_processor_interface == ONYX_INTF) {
+			data = perf_rdr_shift_in_U(rdr_num, width);
+		} else {
+			data = perf_rdr_shift_in_W(rdr_num, width);
+		}
+		if (xbits) {
+			buffer[i] |= (data << (64 - xbits));
+			if (i) {
+				buffer[i-1] |= ((data >> xbits) & data_mask);
+			}
+		} else {
+			buffer[i] = data;
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * perf_rdr_clear
+ *
+ * Zero out the given RDR register
+ */
+static int perf_rdr_clear(uint32_t	rdr_num)
+{
+	struct rdr_tbl_ent *tentry;
+	int32_t		i;
+
+	tentry = perf_rdr_get_entry(rdr_num);
+
+	if (tentry->width == 0) {
+		return -1;
+	}
+
+	i = tentry->num_words;
+	while (i--) {
+		if (perf_processor_interface == ONYX_INTF) {
+			perf_rdr_shift_out_U(rdr_num, 0UL);
+		} else {
+			perf_rdr_shift_out_W(rdr_num, 0UL);
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ * perf_write_image
+ *
+ * Write the given image out to the processor
+ */
+static int perf_write_image(uint64_t *memaddr)
+{
+	uint64_t buffer[MAX_RDR_WORDS];
+	uint64_t *bptr;
+	uint32_t dwords;
+	uint32_t *intrigue_rdr;
+	uint64_t *intrigue_bitmask, tmp64, proc_hpa, *ptr64;
+	struct rdr_tbl_ent *tentry;
+	int i;
+
+	/* Clear out counters */
+	if (perf_processor_interface == ONYX_INTF) {
+
+		perf_rdr_clear(16);
+
+		/* Toggle performance monitor */
+		perf_intrigue_enable_perf_counters();
+		perf_intrigue_disable_perf_counters();
+
+		intrigue_rdr = perf_rdrs_U;
+	} else {
+		perf_rdr_clear(15);
+		intrigue_rdr = perf_rdrs_W;
+	}
+
+	/* Write all RDRs */
+	while (*intrigue_rdr != -1) {
+		tentry = perf_rdr_get_entry(*intrigue_rdr);
+		perf_rdr_read_ubuf(*intrigue_rdr, buffer);
+		bptr   = &buffer[0];
+		dwords = tentry->num_words;
+		if (tentry->write_control) {
+			intrigue_bitmask = &bitmask_array[tentry->write_control >> 3];
+			while (dwords--) {
+				tmp64 = *intrigue_bitmask & *memaddr++;
+				tmp64 |= (~(*intrigue_bitmask++)) & *bptr;
+				*bptr++ = tmp64;
+			}
+		} else {
+			while (dwords--) {
+				*bptr++ = *memaddr++;
+			}
+		}
+
+		perf_rdr_write(*intrigue_rdr, buffer);
+		intrigue_rdr++;
+	}
+
+	/*
+	 * Now copy out the Runway stuff which is not in RDRs
+	 */
+
+	if (cpu_device == NULL)
+	{
+		printk(KERN_ERR "write_image: cpu_device not yet initialized!\n");
+		return -1;
+	}
+
+	proc_hpa = cpu_device->hpa;
+
+	/* Merge intrigue bits into Runway STATUS 0 */
+	ptr64 = (uint64_t *)(proc_hpa + 0x10); /* Runway STATUS 0 */
+	tmp64 = __raw_readq((u64 *)ptr64) & 0xffecffffffffffff;
+	__raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000), (u64 *)ptr64);
+	
+	/* Write RUNWAY DEBUG registers */
+	ptr64 = (uint64_t *)(proc_hpa + 0x40); /* Runway DEBUG 0 */
+	for (i = 0; i < 8; i++) {
+		__raw_writeq(*memaddr++, (u64 *)ptr64);
+		ptr64++;
+	}
+
+	return 0; 
+}
+
+/*
+ * perf_rdr_write
+ *
+ * Write the given RDR register with the contents
+ * of the given buffer.
+ */
+static void perf_rdr_write(uint32_t rdr_num, uint64_t *buffer)
+{
+	struct rdr_tbl_ent *tentry;
+	int32_t		i;
+
+printk("perf_rdr_write\n");
+	tentry = perf_rdr_get_entry(rdr_num);
+	if (tentry->width == 0) { return; }
+
+	i = tentry->num_words;
+	while (i--) {
+		if (perf_processor_interface == ONYX_INTF) {
+			perf_rdr_shift_out_U(rdr_num, buffer[i]);
+		} else {
+			perf_rdr_shift_out_W(rdr_num, buffer[i]);
+		}	
+	}
+printk("perf_rdr_write done\n");
+}
+
+module_init(perf_init);
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/perf_asm.S linux-2.4.20-pre2/arch/parisc/kernel/perf_asm.S
--- linux-2.4.20-pre1/arch/parisc/kernel/perf_asm.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/perf_asm.S	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,1679 @@
+; 
+;   Purpose:
+;	This file has the overall purpose of suppyling low-level
+;   assembly to program the intrigue portion of the cpu.
+; 
+
+#include <linux/config.h>
+#include <asm/assembly.h>
+
+#ifdef __LP64__
+	.level		2.0w
+#endif /* __LP64__ */
+
+#define MTDIAG_1(gr)    .word 0x14201840 + gr*0x10000
+#define MTDIAG_2(gr)    .word 0x14401840 + gr*0x10000
+#define MFDIAG_1(gr)    .word 0x142008A0 + gr
+#define MFDIAG_2(gr)    .word 0x144008A0 + gr
+#define STDIAG(dr)      .word 0x14000AA0 + dr*0x200000
+#define SFDIAG(dr)      .word 0x14000BA0 + dr*0x200000
+#define DR2_SLOW_RET    53
+
+
+;
+; Enable the performance counters
+;
+; The coprocessor only needs to be enabled when
+; starting/stopping the coprocessor with the pmenb/pmdis.
+;
+	.text
+	.align 32
+
+	.export perf_intrigue_enable_perf_counters,code
+perf_intrigue_enable_perf_counters:
+	.proc
+	.callinfo  frame=0,NO_CALLS
+	.entry
+	
+	ldi     0x20,%r25                ; load up perfmon bit
+	mfctl   ccr,%r26                 ; get coprocessor register
+	or      %r25,%r26,%r26             ; set bit
+	mtctl   %r26,ccr                 ; turn on performance coprocessor
+	pmenb                           ; enable performance monitor
+	ssm     0,0                     ; dummy op to ensure completion
+	sync                            ; follow ERS
+	andcm   %r26,%r25,%r26             ; clear bit now 
+	mtctl   %r26,ccr                 ; turn off performance coprocessor
+	nop                             ; NOPs as specified in ERS
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	bve    (%r2)
+	nop
+	.exit
+	.procend
+
+	.export perf_intrigue_disable_perf_counters,code
+perf_intrigue_disable_perf_counters:
+	.proc
+	.callinfo  frame=0,NO_CALLS
+	.entry
+	ldi     0x20,%r25                ; load up perfmon bit
+	mfctl   ccr,%r26                 ; get coprocessor register
+	or      %r25,%r26,%r26             ; set bit
+	mtctl   %r26,ccr                 ; turn on performance coprocessor
+	pmdis                           ; disable performance monitor
+	ssm     0,0                     ; dummy op to ensure completion
+	andcm   %r26,%r25,%r26             ; clear bit now 
+	bve    (%r2)
+	mtctl   %r26,ccr                 ; turn off performance coprocessor
+	.exit
+	.procend
+
+;************************************************************************
+;*																		*
+;* Name: perf_rdr_shift_in_W												*
+;*																		*
+;* Description:															*
+;*	This routine shifts data in from the RDR in arg0 and returns		*
+;*	the result in ret0.  If the RDR is <= 64 bits in length, it			*
+;*	is shifted shifted backup immediately.  This is to compensate		*
+;*	for RDR10 which has bits that preclude PDC stack operations			*
+;*	when they are in the wrong state.									*
+;*																		*
+;* Arguments:															*
+;*	arg0 : rdr to be read												*
+;*	arg1 : bit length of rdr											*
+;*																		*
+;* Returns:																*
+;*	ret0 = next 64 bits of rdr data from staging register				*
+;*																		*
+;* Register usage:														*
+;*	arg0 : rdr to be read												*
+;*	arg1 : bit length of rdr											*
+;*	%r24  - original DR2 value											*
+;*	%r1   - scratch														*
+;*  %r29  - scratch														*
+;*																		*
+;* Returns:																*
+;*	ret0 = RDR data (right justified)									*
+;*																		*
+;************************************************************************
+
+	.export perf_rdr_shift_in_W,code
+perf_rdr_shift_in_W:
+	.proc
+	.callinfo frame=0,NO_CALLS
+	.entry
+;
+; read(shift in) the RDR.
+;
+
+; NOTE: The PCX-W ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, remote diagnose registers.
+;
+
+	depdi,z		1,DR2_SLOW_RET,1,%r29
+	MFDIAG_2	(24)
+	or		    %r24,%r29,%r29
+	MTDIAG_2	(29)			; set DR2_SLOW_RET
+
+	nop
+	nop
+	nop
+	nop	
+
+;
+; Cacheline start (32-byte cacheline)
+;
+	nop
+	nop
+	nop
+	extrd,u		arg1,63,6,%r1    ; setup shift amount based on bits to move 
+
+	mtsar		%r1
+	shladd		arg0,2,%r0,%r1	; %r1 = 4 * RDR number
+	blr  		%r1,%r0		    ; branch to 8-instruction sequence
+	nop
+
+;
+; Cacheline start (32-byte cacheline)
+;
+
+	;
+	; RDR 0 sequence
+	;
+	SFDIAG		(0)		
+	ssm		    0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)					; mtdiag %dr1, %r1 
+	STDIAG		(0)
+	ssm		    0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 1 sequence
+	;
+	sync			
+	ssm		    0,0
+	SFDIAG		(1)
+	ssm		    0,0
+	MFDIAG_1	(28)
+	ssm		    0,0
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	
+	;
+	; RDR 2 read sequence
+	;
+	SFDIAG		(2)		
+	ssm		    0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(2)
+	ssm		    0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 3 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 4 read sequence
+	;
+	sync				
+	ssm			0,0
+	SFDIAG		(4)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	; 
+	; RDR 5 read sequence
+	;
+	sync	
+	ssm			0,0
+	SFDIAG		(5)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 6 read sequence
+	;
+	sync	
+	ssm			0,0
+	SFDIAG		(6)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 7 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 8 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 9 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 10 read sequence
+	;
+	SFDIAG		(10)
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(10)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 11 read sequence
+	;
+	SFDIAG		(11)
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(11)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 12 read sequence
+	;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 13 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(13)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 14 read sequence
+	;
+	SFDIAG		(14)	
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(14)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 15 read sequence
+	;
+	sync				; RDR 15 read sequence
+	ssm			0,0
+	SFDIAG		(15)
+	ssm			0,0
+	MFDIAG_1	(28)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	
+	;
+	; RDR 16 read sequence
+	;
+	sync				; RDR 16 read sequence
+	ssm			0,0
+	SFDIAG		(16)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 17 read sequence
+	;
+	SFDIAG		(17)	
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(17)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 18 read sequence
+	;
+	SFDIAG		(18)	
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(18)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+;
+; RDR 19 read sequence
+;
+	b,n         perf_rdr_shift_in_W_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	;
+	; RDR 20 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(20)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 21 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(21)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 22 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(22)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 23 read sequence
+	;
+	sync		
+	ssm			0,0
+	SFDIAG		(23)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 24 read sequence
+	;
+	sync	
+	ssm			0,0
+	SFDIAG		(24)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 25 read sequence
+	;
+	sync
+	ssm			0,0
+	SFDIAG		(25)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 26 read sequence
+	;
+	SFDIAG		(26)		
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(26)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 27 read sequence
+	;
+	SFDIAG		(27)
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(27)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 28 read sequence
+	;
+	sync				
+	ssm			0,0
+	SFDIAG		(28)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 29 read sequence
+	;
+	sync		
+	ssm			0,0
+	SFDIAG		(29)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_W_leave
+	ssm			0,0
+	nop
+	
+	;
+	; RDR 30 read sequence
+	;
+	SFDIAG		(30)
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(30)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_W_leave
+	
+	;
+	; RDR 31 read sequence
+	;
+	sync		
+	ssm			0,0
+	SFDIAG		(31)
+	ssm			0,0
+	MFDIAG_1	(28)
+	nop
+	ssm			0,0
+	nop
+
+	;
+	; Fallthrough
+	;
+
+perf_rdr_shift_in_W_leave:
+	bve		    (%r2)
+	.exit
+	MTDIAG_2	(24)			; restore DR2
+	.procend
+
+
+;************************************************************************
+;*																		*
+;* Name: perf_rdr_shift_out_W												*
+;*																		*
+;* Description:															*
+;*	This routine moves data to the RDR's.  The double-word that			*
+;*	arg1 points to is loaded and moved into the staging register.		*
+;*	Then the STDIAG instruction for the RDR # in arg0 is called			*
+;*	to move the data to the RDR.										*
+;*																		*
+;* Arguments:															*
+;*	arg0 = rdr number													*
+;*	arg1 = 64-bit value to write										*
+;*	%r24 - DR2 | DR2_SLOW_RET											*
+;*	%r23 - original DR2 value											*
+;*																		*
+;* Returns:																*
+;*	None																*
+;*																		*
+;* Register usage:														*
+;*																		*
+;************************************************************************
+
+	.export perf_rdr_shift_out_W,code
+perf_rdr_shift_out_W:
+	.proc
+	.callinfo frame=0,NO_CALLS
+	.entry
+;
+; NOTE: The PCX-W ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, the remote diagnose registers.
+;
+
+	depdi,z		1,DR2_SLOW_RET,1,%r24
+	MFDIAG_2	(23)
+	or		     %r24,%r23,%r24
+	MTDIAG_2	(24)			; set DR2_SLOW_RET
+
+	MTDIAG_1	(25)			; data to the staging register
+	shladd		arg0,2,%r0,%r1	; %r1 = 4 * RDR number
+	blr		    %r1,%r0		    ; branch to 8-instruction sequence
+	nop
+
+	;
+	; RDR 0 write sequence
+	;
+	sync				; RDR 0 write sequence
+	ssm			0,0
+	STDIAG		(0)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm			0,0
+	nop
+
+	;
+	; RDR 1 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(1)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 2 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(2)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 3 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(3)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 4 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(4)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 5 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(5)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 6 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(6)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 7 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(7)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 8 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(8)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 9 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(9)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 10 write sequence
+	;
+	sync	
+	ssm		0,0
+	STDIAG		(10)
+	STDIAG		(26)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	ssm		0,0
+	nop
+
+	;
+	; RDR 11 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(11)
+	STDIAG		(27)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	ssm		0,0
+	nop
+
+	;
+	; RDR 12 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(12)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 13 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(13)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 14 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(14)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 15 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(15)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 16 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(16)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 17 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(17)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 18 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(18)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 19 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(19)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 20 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(20)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 21 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(21)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 22 write sequence
+	;
+	sync	
+	ssm		0,0
+	STDIAG		(22)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 23 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(23)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 24 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(24)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 25 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(25)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 26 write sequence
+	;
+	sync	
+	ssm		0,0
+	STDIAG		(10)
+	STDIAG		(26)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	ssm		0,0
+	nop
+
+	;
+	; RDR 27 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(11)
+	STDIAG		(27)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	ssm		0,0
+	nop
+
+	;
+	; RDR 28 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(28)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 29 write sequence
+	;
+	sync
+	ssm		0,0
+	STDIAG		(29)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 30 write sequence
+	;
+	sync	
+	ssm		0,0
+	STDIAG		(30)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+	;
+	; RDR 31 write sequence
+	;
+	sync				
+	ssm		0,0
+	STDIAG		(31)
+	ssm		0,0
+	b,n         perf_rdr_shift_out_W_leave
+	nop
+	ssm		0,0
+	nop
+
+perf_rdr_shift_out_W_leave:
+	bve		(%r2)
+	.exit
+	MTDIAG_2	(23)			; restore DR2
+	.procend
+
+
+;**************************** CHRIS ***********************************
+
+;************************************************************************
+;*																		*
+;* Name: rdr_shift_in_U													*
+;*																		*
+;* Description:															*
+;*	This routine shifts data in from the RDR in arg0 and returns		*
+;*	the result in ret0.  If the RDR is <= 64 bits in length, it			*
+;*	is shifted shifted backup immediately.  This is to compensate		*
+;*	for RDR10 which has bits that preclude PDC stack operations			*
+;*	when they are in the wrong state.									*
+;*																		*
+;* Arguments:															*
+;*	arg0 : rdr to be read												*
+;*	arg1 : bit length of rdr											*
+;*																		*
+;* Returns:																*
+;*	ret0 = next 64 bits of rdr data from staging register				*
+;*																		*
+;* Register usage:														*
+;*	arg0 : rdr to be read						                        *
+;*	arg1 : bit length of rdr					                        *
+;*	%r24 - original DR2 value											*
+;*	%r23 - DR2 | DR2_SLOW_RET											*
+;*	%r1  - scratch														*
+;*																		*
+;************************************************************************
+
+	.export perf_rdr_shift_in_U,code
+perf_rdr_shift_in_U:
+	.proc
+	.callinfo frame=0,NO_CALLS
+	.entry
+
+; read(shift in) the RDR.
+;
+; NOTE: The PCX-U ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, remote diagnose registers.
+
+	depdi,z		1,DR2_SLOW_RET,1,%r29
+	MFDIAG_2	(24)
+	or			%r24,%r29,%r29
+	MTDIAG_2	(29)			; set DR2_SLOW_RET
+
+	nop
+	nop
+	nop
+	nop
+
+;
+; Start of next 32-byte cacheline
+;
+	nop
+	nop
+	nop
+	extrd,u		arg1,63,6,%r1
+
+	mtsar		%r1
+	shladd		arg0,2,%r0,%r1	; %r1 = 4 * RDR number
+	blr 		%r1,%r0		; branch to 8-instruction sequence
+	nop
+
+;
+; Start of next 32-byte cacheline
+;
+	SFDIAG		(0)		; RDR 0 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(0)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(1)		; RDR 1 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(1)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	sync				; RDR 2 read sequence
+	ssm			0,0
+	SFDIAG		(4)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 3 read sequence
+	ssm			0,0
+	SFDIAG		(3)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+
+	sync				; RDR 4 read sequence
+	ssm			0,0
+	SFDIAG		(4)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 5 read sequence
+	ssm			0,0
+	SFDIAG		(5)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 6 read sequence
+	ssm			0,0
+	SFDIAG		(6)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 7 read sequence
+	ssm			0,0
+	SFDIAG		(7)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+
+	b,n         perf_rdr_shift_in_U_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	SFDIAG		(9)		; RDR 9 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(9)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+
+	SFDIAG		(10)		; RDR 10 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(10)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(11)		; RDR 11 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(11)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(12)		; RDR 12 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(12)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+
+	SFDIAG		(13)		; RDR 13 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(13)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(14)		; RDR 14 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(14)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(15)		; RDR 15 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(15)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	sync				; RDR 16 read sequence
+	ssm			0,0
+	SFDIAG		(16)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	SFDIAG		(17)		; RDR 17 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(17)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(18)		; RDR 18 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(18)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	b,n         perf_rdr_shift_in_U_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	sync				; RDR 20 read sequence
+	ssm			0,0
+	SFDIAG		(20)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 21 read sequence
+	ssm			0,0
+	SFDIAG		(21)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 22 read sequence
+	ssm			0,0
+	SFDIAG		(22)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 23 read sequence
+	ssm			0,0
+	SFDIAG		(23)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 24 read sequence
+	ssm			0,0
+	SFDIAG		(24)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	sync				; RDR 25 read sequence
+	ssm			0,0
+	SFDIAG		(25)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	SFDIAG		(26)		; RDR 26 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(26)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(27)		; RDR 27 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(27)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	sync				; RDR 28 read sequence
+	ssm			0,0
+	SFDIAG		(28)
+	ssm			0,0
+	MFDIAG_1	(28)
+	b,n         perf_rdr_shift_in_U_leave
+	ssm			0,0
+	nop
+	
+	b,n         perf_rdr_shift_in_U_leave
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	
+	SFDIAG		(30)		; RDR 30 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(30)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	
+	SFDIAG		(31)		; RDR 31 read sequence
+	ssm			0,0
+	MFDIAG_1	(28)
+	shrpd		ret0,%r0,%sar,%r1
+	MTDIAG_1	(1)
+	STDIAG		(31)
+	ssm			0,0
+	b,n         perf_rdr_shift_in_U_leave
+	nop
+
+perf_rdr_shift_in_U_leave:
+	bve		    (%r2)
+	.exit
+	MTDIAG_2	(24)			; restore DR2
+	.procend
+
+;************************************************************************
+;*																		*
+;* Name: rdr_shift_out_U												*
+;*																		*
+;* Description:															*
+;*	This routine moves data to the RDR's.  The double-word that			*
+;*	arg1 points to is loaded and moved into the staging register.		*
+;*	Then the STDIAG instruction for the RDR # in arg0 is called			*
+;*	to move the data to the RDR.										*
+;*																		*
+;* Arguments:															*
+;*	arg0 = rdr target													*
+;*	arg1 = buffer pointer												*
+;*																		*
+;* Returns:																*
+;*	None																*
+;*																		*
+;* Register usage:														*
+;*	arg0 = rdr target													*
+;*	arg1 = buffer pointer												*
+;*	%r24 - DR2 | DR2_SLOW_RET											*
+;*	%r23 - original DR2 value											*
+;*																		*
+;************************************************************************
+
+	.export perf_rdr_shift_out_U,code
+perf_rdr_shift_out_U:
+	.proc
+	.callinfo frame=0,NO_CALLS
+	.entry
+
+;
+; NOTE: The PCX-U ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, the remote diagnose registers.
+;
+
+	depdi,z		1,DR2_SLOW_RET,1,%r24
+	MFDIAG_2	(23)
+	or		%r24,%r23,%r24
+	MTDIAG_2	(24)			; set DR2_SLOW_RET
+
+	MTDIAG_1	(25)			; data to the staging register
+	shladd		 arg0,2,%r0,%r1	; %r1 = 4 * RDR number
+	blr		    %r1,%r0		    ; branch to 8-instruction sequence
+	nop
+
+;
+; 32-byte cachline aligned
+;
+
+	sync				; RDR 0 write sequence
+	ssm			0,0
+	STDIAG		(0)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 1 write sequence
+	ssm			0,0
+	STDIAG		(1)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 2 write sequence
+	ssm			0,0
+	STDIAG		(2)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 3 write sequence
+	ssm			0,0
+	STDIAG		(3)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 4 write sequence
+	ssm			0,0
+	STDIAG		(4)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 5 write sequence
+	ssm			0,0
+	STDIAG		(5)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 6 write sequence
+	ssm			0,0
+	STDIAG		(6)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 7 write sequence
+	ssm			0,0
+	STDIAG		(7)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 8 write sequence
+	ssm			0,0
+	STDIAG		(8)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 9 write sequence
+	ssm			0,0
+	STDIAG		(9)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 10 write sequence
+	ssm			0,0
+	STDIAG		(10)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 11 write sequence
+	ssm			0,0
+	STDIAG		(11)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 12 write sequence
+	ssm			0,0
+	STDIAG		(12)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 13 write sequence
+	ssm			0,0
+	STDIAG		(13)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 14 write sequence
+	ssm			0,0
+	STDIAG		(14)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 15 write sequence
+	ssm			0,0
+	STDIAG		(15)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 16 write sequence
+	ssm			0,0
+	STDIAG		(16)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 17 write sequence
+	ssm			0,0
+	STDIAG		(17)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 18 write sequence
+	ssm			0,0
+	STDIAG		(18)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 19 write sequence
+	ssm			0,0
+	STDIAG		(19)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 20 write sequence
+	ssm			0,0
+	STDIAG		(20)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 21 write sequence
+	ssm			0,0
+	STDIAG		(21)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 22 write sequence
+	ssm			0,0
+	STDIAG		(22)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 23 write sequence
+	ssm			0,0
+	STDIAG		(23)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 24 write sequence
+	ssm			0,0
+	STDIAG		(24)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 25 write sequence
+	ssm			0,0
+	STDIAG		(25)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 26 write sequence
+	ssm			0,0
+	STDIAG		(26)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 27 write sequence
+	ssm			0,0
+	STDIAG		(27)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 28 write sequence
+	ssm			0,0
+	STDIAG		(28)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 29 write sequence
+	ssm			0,0
+	STDIAG		(29)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 30 write sequence
+	ssm			0,0
+	STDIAG		(30)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+	sync				; RDR 31 write sequence
+	ssm			0,0
+	STDIAG		(31)
+	ssm			0,0
+	b,n         perf_rdr_shift_out_U_leave
+	nop
+	ssm			0,0
+	nop
+
+perf_rdr_shift_out_U_leave:
+	bve		(%r2)
+	.exit
+	MTDIAG_2	(23)			; restore DR2
+	.procend
+
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/perf_images.h linux-2.4.20-pre2/arch/parisc/kernel/perf_images.h
--- linux-2.4.20-pre1/arch/parisc/kernel/perf_images.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/perf_images.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,3122 @@
+#ifndef PERF_IMAGES_H
+#define PERF_IMAGES_H
+
+/* Magic numbers taken without modification from HPUX stuff */
+
+/*
+ * Imagine for use with the Onyx cpu interface
+ */
+
+#define PCXU_IMAGE_SIZE 584
+
+static uint32_t onyx_images[][PCXU_IMAGE_SIZE/sizeof(uint32_t)] = {
+/*
+ * CPI:
+ *
+ * Counts the following:
+ *
+ * ctr0 : total cycles
+ * ctr1 : total cycles where nothing retired
+ * ctr2 : total instructions retired, including nullified
+ * ctr3 : total instructions retired, less nullified instructions
+ */
+         {
+         0x4c00c000, 0x00000000, 0x00060000, 0x00000000,
+         0xe0e0e0e0, 0x004e0004, 0x07ffffff, 0xffc01380,
+         0x0101ffff, 0xfffff104, 0xe000c07f, 0xfffffffc,
+         0x01380010, 0x1fffffff, 0xff000000, 0x00000000,
+         0x00000fff, 0xff00000f, 0xffff0000, 0x0fffff00,
+         0x000fffff, 0x00000000, 0x00000000, 0x00ffffff,
+         0xfffff000, 0x0000000f, 0xffffffff, 0xff000000,
+         0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+         0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+         0xfff55fff, 0xffffffff, 0xffffffff, 0xf0000000,
+         0xf0000030, 0x00003c00, 0x067f080c, 0x02019fc0,
+         0x02804067, 0xf0009030, 0x19fc002c, 0x40067f08,
+         0x0c12019f, 0xc0028440, 0x67f00091, 0x3019fc00,
+         0x2fc007ff, 0xf800f001, 0xfffe003c, 0x007fff80,
+         0x0f001fff, 0xe003c007, 0xfff800f0, 0x01fffe00,
+         0x3c007fff, 0x800f001f, 0xffe003c0, 0x07fff800,
+         0xf001fffe, 0x003c007f, 0xff800f00, 0x1fffe003,
+         0xc007fff8, 0x00f001ff, 0xfe003c00, 0x7fff800f,
+         0x001fffe0, 0x03c007ff, 0xf800f001, 0xfffe003c,
+         0x007fff80, 0x0f001fff, 0xe003c007, 0xfff800f0,
+         0x01fffe00, 0x3c007fff, 0x800f001f, 0xffe00000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff},
+
+/* Bus utilization image (bus_util)
+ *
+ * ctr0 : counts address valid cycles
+ * ctr1 : counts data valid cycles
+ * ctr2 : counts overflow from counter 0
+ * ctr3 : counts overflow from counter 1
+ */
+         {
+         0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+         0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffff0000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+         0x0000000c, 0x00003c00, 0x07930000, 0x0041e4c0,
+         0x01002079, 0x3000800c, 0x1e4c0030, 0x00279300,
+         0x010049e4, 0xc0014022, 0x79300090, 0x0c9e4c00,
+         0x34004793, 0x00020051, 0xe4c00180, 0x24793000,
+         0xa00d1e4c, 0x00380067, 0x93000300, 0x59e4c001,
+         0xc0267930, 0x00b00d9e, 0x4c003fff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xfffffc00,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0xffff0000, 0x00000000, 0xf0000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00100000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff },
+
+/*
+ * TLB counts (same as tlbStats image):
+ *
+ * Counts the following:
+ *
+ * ctr0: DTLB misses
+ * ctr1: ITLB misses
+ * ctr2: total cycles in the miss handlers
+ * ctr3: total cycles
+ */
+
+         {
+         0x0c00c000, 0x00000000, 0x00060000, 0x00000000,
+         0xe7e7e0e0, 0x004e0004, 0x07ffffff, 0xffc01380,
+         0x0101ffff, 0xfffff104, 0xe000c06a, 0xafffc85c,
+         0x01380010, 0x1fffffff, 0xff000000, 0x00000000,
+         0x01b9e000, 0x0001b8c0, 0x00000000, 0x0fffff00,
+         0x000fffff, 0x00000000, 0x00000000, 0x00400000,
+         0x00001000, 0x00000004, 0x00000000, 0x01000000,
+         0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+         0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+         0xfff55ff5, 0xffffffff, 0xffffffff, 0xf0000000,
+         0xf0000000, 0x00003c00, 0x01ff0001, 0x08007fc2,
+         0x02c1001f, 0xf0807100, 0x1bfc200c, 0x4806ff00,
+         0x03f001ff, 0xfe003c00, 0x7fff800f, 0x001fffe0,
+         0x03c007ff, 0xf800f001, 0xfffe003c, 0x007fff80,
+         0x0f001fff, 0xe003c007, 0xfff800f0, 0x01fffe00,
+         0x3c007fff, 0x800f001f, 0xffe003c0, 0x07fff800,
+         0xf001fffe, 0x003c007f, 0xff800f00, 0x1fffe003,
+         0xc007fff8, 0x00f001ff, 0xfe003c00, 0x7fff800f,
+         0x001fffe0, 0x03c007ff, 0xf800f001, 0xfffe003c,
+         0x007fff80, 0x0f001fff, 0xe003c007, 0xfff800f0,
+         0x01fffe00, 0x3c007fff, 0x800f001f, 0xffe00000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff },
+
+/* tlbHandMiss
+ *
+ * ctr0: counts TLB misses 
+ * ctr1: counts dmisses inside tlb miss handlers 
+ * ctr2: counts cycles in the tlb miss handlers 
+ * ctr3: counts overflows of ctr2 
+ */
+{
+0x1c00c000,00000000,0x00060000,00000000,
+0xe7e7e0e0,0x004e0004,0x07ffffff,0xffc01380,
+0x0101ffff,0xfffff104,0xe000c06a,0xafffc85c,
+0x01380010,0x1fffffff,0xff000000,00000000,
+0x01b9e000,0x0001b8c0,00000000,0x0fffff00,
+0x000fffff,00000000,00000000,0x00400000,
+0x00001000,0x00000004,00000000,0x01000000,
+0x0000ffff,0xfffffff0,00000000,0x0fffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff55ff5,0xffffffff,0xffffffff,0xf0000000,
+0xf0000000,0x00003c00,0x01fd0000,0x08007f42,
+0x0281001f,0xd080a100,0x19f42008,0x44067d08,
+0x0612019f,0x400084c0,0x67d00060,0x0047f400,
+0x042011fd,0x080b0404,0x7f4202c4,0x0167d080,
+0x311059f4,0x201c4816,0x7d000313,0x059f4001,
+0xfc007fff,0x800f001f,0xffe003c0,0x07fff800,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x6fff0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* branch_taken image (ptkn image)
+ *
+ * ctr0: overflow for ctr1
+ * ctr1: predicted taken branches, actually taken
+ * ctr2: all predicted taken branches (nullfied or not)
+ * ctr3: overflow for ctr2
+ */
+
+        {
+        0xcc01e000, 0x00000000, 0x00060000, 0x00000000,
+        0xa08080a0, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffff0000, 0x00000000, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+        0xf0000000, 0x00003c00, 0x04f90000, 0x02013e40,
+        0x0081004f, 0x90004060, 0x13e40018, 0x0024f900,
+        0x0802093e, 0x40028102, 0x4f9000c0, 0x6093e400,
+        0x380014f9, 0x00010205, 0x3e4000c1, 0x014f9000,
+        0x506053e4, 0x001c0034, 0xf9000902, 0x0d3e4002,
+        0xc1034f90, 0x00d060d3, 0xe4003fff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xfffffc00,
+        0x00000000, 0x00000000, 0x00000000, 0x00000000,
+        0xffff0000, 0x00000000, 0xf0000000, 0x00000000,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+        0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+        0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+        0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+        0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+        0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+        0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+        0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+        0xffffffff, 0xffffffff },
+
+/* branch_nottaken (pntkn image)
+ *
+ * ctr0: overflow for ctr1
+ * ctr1: counts branches predicted not-taken, but actually taken
+ * ctr2: counts all predictable branches predicted not-taken
+ * ctr3: overflow for ctr2
+ */
+{
+0xcc01e000,00000000,0x00060000,00000000,
+0xc0c0c0e0,0xffb1fffb,0xfff7ffff,0xffffffff,
+0xffffffff,0xfffffffb,0x1fffbfff,0x7fffffff,
+0xfcc7ffff,0xffdffffa,0x5f000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+
+/* imiss image
+ *
+ * ctr0 : counts imiss aligned on 0
+ * ctr1 : counts imiss aligned on 4
+ * ctr2 : counts imiss aligned on 8
+ * ctr3 : counts imiss aligned on C
+ */
+         {
+         0x0c00c000, 0x00000000, 0x00010000, 0x00000000,
+         0xe7ebedee, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+         0xfff55fff, 0xffffffff, 0xffffffff, 0xf0000000,
+         0xf0000000, 0x00003c00, 0x007f0000, 0x01001fc0,
+         0x00408007, 0xf0002030, 0x01fc000c, 0x10007f00,
+         0x0405001f, 0xc0014180, 0x07f00060, 0x7001fc00,
+         0x1c20007f, 0x00080900, 0x1fc00242, 0x8007f000,
+         0xa0b001fc, 0x002c3000, 0x7f000c0d, 0x001fc003,
+         0x438007f0, 0x00e0f001, 0xfc003fff, 0xfffff800,
+         0xfffffffe, 0x003fffff, 0xff800fff, 0xffffe003,
+         0xfffffff8, 0x00ffffff, 0xfe003fff, 0xffff800f,
+         0xffffffe0, 0x03ffffff, 0xf800ffff, 0xfffe003f,
+         0xffffff80, 0x0fffffff, 0xe003ffff, 0xfff800ff,
+         0xfffffe00, 0x3fffffff, 0x800fffff, 0xffe00000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff},
+
+/* dmiss image
+ * 
+ * ctr0 : counts cycles
+ * ctr1 : counts cycles where something retired
+ * ctr2 : counts dmisses
+ * ctr3 : (same as ctr2)
+ */
+         {
+         0x3c00c000, 0x00000000, 0x00060000, 0x00000000,
+         0xe0e0e0e0, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+         0xf0000000, 0x00003c04, 0x007f0009, 0x02001fc0,
+         0x0280c007, 0xf000b040, 0x01fc0030, 0x14007f00,
+         0x0d06001f, 0xc00381c0, 0x07f000f0, 0x8001fc00,
+         0x2024007f, 0x00090a00, 0x1fc00282, 0xc007f000,
+         0xb0c001fc, 0x00303400, 0x7f000d0e, 0x001fc003,
+         0x83c007f0, 0x00f00001, 0xfc0023ff, 0xfffff800,
+         0xfffffffe, 0x003fffff, 0xff800fff, 0xffffe003,
+         0xfffffff8, 0x00ffffff, 0xfe003fff, 0xffff800f,
+         0xffffffe0, 0x03ffffff, 0xf800ffff, 0xfffe003f,
+         0xffffff80, 0x0fffffff, 0xe003ffff, 0xfff800ff,
+         0xfffffe00, 0x3fffffff, 0x800fffff, 0xffe00000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+         0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+         0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+         0xffffffff, 0xffffffff },
+
+/* dcmiss 
+ *
+ * ctr0: counts store instructions retired 
+ * ctr1: counts load instructions retired
+ * ctr2: counts dmisses 
+ * ctr3: counts READ_SHARED_OR_PRIV and READ_PRIVATE transactions on Runway 
+ */
+{
+0x2c90c000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf00000e8,0x00003c02,0x00bf0001,0x02002fc0,
+0x0080a00b,0xf0003040,0x02fc0010,0x1200bf00,
+0x0506002f,0xc00181a0,0x0bf00070,0x8002fc00,
+0x202200bf,0x00090a00,0x2fc00282,0xa00bf000,
+0xb0c002fc,0x00303200,0xbf000d0e,0x002fc003,
+0x83a00bf0,0x00ffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0x6fff0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0x55555555,0xd5555555,
+0x55555555,0x75555555,0x5e1ffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf8000000,00000000,
+00000000,00000000,0xf4000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* big_cpi
+ *
+ * ctr0: counts total cycles 
+ * ctr1: counts overflows of ctr0 (for greater than 32-bit values) 
+ * ctr2: counts overflows of ctr3 (for greater than 32-bit values) 
+ * ctr3: counts unnullified instructions retired 
+ */
+{
+0x0c00c000,00000000,0x00060000,00000000,
+0xe7e7e0e0,0x004e0004,0x07ffffff,0xffc01380,
+0x0101ffff,0xfffff104,0xe000c06a,0xafffc85c,
+0x01380010,0x1fffffff,0xff000000,00000000,
+0x01b9e000,0x0001b8c0,00000000,0x0fffff00,
+0x000fffff,00000000,00000000,0x00400000,
+0x00001000,0x00000004,00000000,0x01000000,
+0x0000ffff,0xfffffff0,00000000,0x0fffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff55ff5,0xffffffff,0xffffffff,0xf0000000,
+0xf0000010,0x00003c00,0x01760008,0x00025d80,
+0x02800417,0x6000c001,0x25d80038,0x04017600,
+0x0901025d,0x8002c044,0x176000d0,0x1125d800,
+0x3c2001f6,0x08080400,0x7d820203,0x001f6080,
+0x804027d8,0x20282009,0xf6080a0c,0x027d8202,
+0x81041f60,0x80c08107,0xd8203030,0x41f6080c,
+0x04127d82,0x0382049f,0x6080e0c1,0x27d82038,
+0x4006f608,0x081011bd,0x82030400,0xef6080a1,
+0x013bd820,0x384806f6,0x00081211,0xbd800304,
+0x80ef6000,0xa1213bd8,0x003bc007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x6fff0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* big_ls
+ *
+ * ctr0:counts the total number of cycles for which local_stall_A1 is asserted. 
+ * ctr1: is the overflow for counter 0. 
+ * ctr2: counts IFLUSH_AV 
+ * ctr3: is the overflow for counter 2. 
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00029408,0x02f50002,0x0800bd40,
+0x0202802f,0x5000a000,0x4bd40004,0x0812f500,
+0x030804bd,0x40024281,0x2f5000b0,0x010bd400,
+0x100842f5,0x00060810,0xbd400302,0x842f5000,
+0xe0014bd4,0x00140852,0xf5000708,0x14bd4003,
+0x42852f50,0x00ff001f,0xffe003c0,0x07fff800,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x0df70000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* br_abort
+ *
+ * ctr0: counts BRAD_STALLH 
+ * ctr1: counts ONE_QUAD 
+ * ctr2: counts BR0_ABRT 
+ * ctr3: counts BR1_ABRT
+ */
+{
+0x0c002000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x1fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x1a250000,00000000,0x10000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* isnt
+ *
+ * ctr0: counts the total number of cycles for which iside_notrans is asserted 
+ * ctr1: counts the number of times iside_notrans is asserted for 1-4 cycles 
+ * ctr2: counts the number of times iside_notrans is asserted for 5-7 cycles 
+ * ctr3: counts the number of times iside_notrans is asserted for > 7 cycles 
+ */
+{
+0x0c018000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xcfffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00021c20,0x03ff0808,0x1800ffc4,
+0x0204003f,0xf0004280,0x0ffc6020,0x8003ff00,
+0x043800ff,0xc8020c00,0x3ff00044,0x800ffca0,
+0x210003ff,0x00045800,0xffcc0214,0x003ff000,
+0x26800ffc,0xe0218003,0xff000278,0x00ffd002,
+0x1c003ff0,0x0028800f,0xfd002200,0x03ff0001,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0xcdff0000,00000000,0xc0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* quadrant
+ *
+ * ctr0: Total number of instructions in quadrant 0 
+ * ctr1: Total number of instructions in quadrant 1 
+ * ctr2: Total number of instructions in quadrant 2 
+ * ctr3: Total number of instructions in quadrant 3 
+ * Works only with 32-bit
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0x004e0004,   0x07ffffff,   0xffc01380,
+   0x0101ffff,   0xfffff004,   0xe000407f,   0xfffffffc,
+   0x01380010,   0x1fffffff,   0xff000000,   0x00000000,
+   0x00000fff,   0xff00000f,   0xffff0000,   0x0fffff00,
+   0x000fffff,   0x00000000,   0x00000000,   0x00ffffff,
+   0xffcff000,   0x0000040f,   0xfffffffc,   0xff000000,
+   0x0080ffff,   0xffffcff0,   0x0000000c,   0x0fffffff,
+   0xfcff0000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xfff55ff5,   0x5fffffff,   0xffffffff,   0xf0000000,
+   0xf00000f0,   0x00003c00,   0x007f0000,   0x01001fc0,
+   0x00408007,   0xf0002030,   0x01fc000c,   0x10007f00,
+   0x0405001f,   0xc0014180,   0x07f00060,   0x7001fc00,
+   0x1c20007f,   0x00080900,   0x1fc00242,   0x8007f000,
+   0xa0b001fc,   0x002c3000,   0x7f000c0d,   0x001fc003,
+   0x438007f0,   0x00e0f001,   0xfc003fff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffffc00,
+   0x00000000,   0x00000000,   0x00000000,   0x00000000,
+   0xffff0000,   0x00000000,   0xf0000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xfffffc00,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xfffffc00,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0x00030000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff},
+
+/* rw_pdfet (READ_PRIV transactions)
+ *
+ * ctr0: counts address valid cycles 
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf8000000,00000000,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff},
+
+/* rw_wdfet (WRITEBACKS)
+ *
+ * ctr0: counts address valid cycles 
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0x98000000,00000000,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff},
+
+/* shlib_cpi
+ *
+ * ctr0: Total number of instructions in quad 0 
+ * ctr1: Total number of CPU clock cycles in quad 0 
+ * ctr2: total instructions without nullified   
+ * ctr3: total number of CPU clock cycles 
+ */
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0x004e0004,   0x07ffffff,   0xffc01380,
+   0x0101ffff,   0xfffff004,   0xe000407f,   0xfffffffc,
+   0x01380010,   0x1fffffff,   0xff000000,   0x00000000,
+   0x00000fff,   0xff00000f,   0xffffffff,   0xffffffff,
+   0xffffffff,   0x00000000,   0x00000000,   0x00ffffff,
+   0xffcff000,   0x0000000f,   0xfffffffc,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xfff77ff5,   0x7fffffff,   0xffffffff,   0xf0000000,
+   0xf00000a0,   0x00003c00,   0x01ff0005,   0x08007fc0,
+   0x03c1001f,   0xf08030c0,   0x07fc203c,   0x4001ff08,
+   0x0118007f,   0xc003c500,   0x1ff08031,   0xc007fc00,
+   0x3fffffff,   0xf800ffff,   0xfffe003f,   0xffffff80,
+   0x0fffffff,   0xe003ffff,   0xfff800ff,   0xfffffe00,
+   0x3fffffff,   0x800fffff,   0xffe003ff,   0xfffff800,
+   0xfffffffe,   0x003fffff,   0xff800fff,   0xffffe003,
+   0xfffffff8,   0x00ffffff,   0xfe003fff,   0xffff800f,
+   0xffffffe0,   0x03ffffff,   0xf800ffff,   0xfffe003f,
+   0xffffff80,   0x0fffffff,   0xe003ffff,   0xfff800ff,
+   0xfffffe00,   0x3fffffff,   0x800fffff,   0xffe00000,
+   0x00000000,   0x00000000,   0x00000000,   0x00000000,
+   0xffff0000,   0x00000000,   0xf0000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xfffffc00,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xfffffc00,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0x00030000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff},
+
+
+/* addr_inv_abort_alu
+ *
+ * ctr0: counts ABORT_ALU0L 
+ * ctr1: counts ABORT_ALU1L 
+ * ctr2: counts ADDR0_INVALID 
+ * ctr3: counts ADDR1_INVALID 
+ */
+
+{
+0x0c00c000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000d,0x01001fc0,
+0x03008007,0xf000f030,0x01fc0038,0x10007f00,
+0x0905001f,0xc0020180,0x07f000b0,0x7001fc00,
+0x2820007f,0x00050900,0x1fc00102,0x8007f000,
+0x70b001fc,0x00183000,0x7f00010d,0x001fc000,
+0x038007f0,0x0030f001,0xfc000bff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x65380000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+
+/* brad_stall
+ *
+ * ctr0: counts the total number of cycles for which brad_stall is asserted 
+ * ctr1: counts the number of times brad_stall is asserted for 1-4 cycles 
+ * ctr2: counts the number of times brad_stall is asserted for 5-7 cycles 
+ * ctr3: counts the number of times brad_stall is asserted for > 7 cycles 
+ */
+{
+0x0c002000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x1fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00021c20,0x03ff0808,0x1800ffc4,
+0x0204003f,0xf0004280,0x0ffc6020,0x8003ff00,
+0x043800ff,0xc8020c00,0x3ff00044,0x800ffca0,
+0x210003ff,0x00045800,0xffcc0214,0x003ff000,
+0x26800ffc,0xe0218003,0xff000278,0x00ffd002,
+0x1c003ff0,0x0028800f,0xfd002200,0x03ff0001,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x1bff0000,00000000,0x10000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* cntl_in_pipel
+ *
+ * ctr0: counts the total number of cycles for which cntl_in_pipel is asserted 
+ * ctr1: counts the number of times cntl_in_pipel is asserted for 1-4 cycles 
+ * ctr2: counts the number of times cntl_in_pipel is asserted for 5-7 cycles 
+ * ctr3: counts the number of times cntl_in_pipel is asserted for > 7 cycles 
+ */
+{
+0x0c006000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x3fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00021c00,0x03ff0808,0x1000ffc4,
+0x0206003f,0xf0004200,0x0ffc6020,0xa003ff00,
+0x043000ff,0xc8020e00,0x3ff00044,0x000ffca0,
+0x212003ff,0x00045000,0xffcc0216,0x003ff000,
+0x26000ffc,0xe021a003,0xff000270,0x00ffd002,
+0x1e003ff0,0x0028000f,0xfd002220,0x03ff0001,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x3fff0000,00000000,0x30000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+/* dsnt_xfh
+ *
+ * ctr0: counts dside_notrans 
+ * ctr1: counts xfhang 
+ * ctr2: is the overflow for ctr0 
+ * ctr3: is the overflow for ctr1 
+ */
+{
+0x0c018000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xcfffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00030000,0x01f30000,0x00087cc0,
+0x0040041f,0x30002001,0x87cc000c,0x1001f300,
+0x0404087c,0xc0014104,0x1f300060,0x4187cc00,
+0x1c2001f3,0x00080808,0x7cc00242,0x041f3000,
+0xa08187cc,0x002c3001,0xf3000c0c,0x087cc003,
+0x43041f30,0x00e0c187,0xcc003fc0,0x07fff800,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0xcb3f0000,00000000,0xc0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff }, 
+
+/* fet_sig1
+ *
+ * ctr0: counts ICORE_AV 
+ * ctr1: counts ITRANS_STALL 
+ * ctr2: counts SEL_PCQH 
+ * ctr3: counts OUT_OF_CONTEXT 
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x07c10000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* fet_sig2
+ *
+ * ctr0: counts ICORE_AV  
+ * ctr1: counts IRTN_AV 
+ * ctr2: counts ADDRESS_INC 
+ * ctr3: counts ADDRESS_DEC 
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x06930000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_1
+ *
+ * ctr0: counts HIT_RETRY0 
+ * ctr1: counts HIT_RETRY1 
+ * ctr2: counts GO_TAG_E 
+ * ctr3: counts GO_TAG_O 
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x71c10000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_2
+ *
+ * ctr0: counts HIT_DM0 
+ * ctr1: counts HIT_DM1 
+ * ctr2: counts GO_STORE_E 
+ * ctr3: counts GO_STORE_O 
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x72930000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_3
+ *
+ * ctr0: counts HIT_DV0 
+ * ctr1: counts HIT_DV1 
+ * ctr2: counts STBYPT_E (load bypasses from store queue) 
+ * ctr3: counts STBYPT_O
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f0002,0x01001fc0,
+0x00c08007,0xf0000030,0x01fc0004,0x10007f00,
+0x0605001f,0xc001c180,0x07f00040,0x7001fc00,
+0x1420007f,0x000a0900,0x1fc002c2,0x8007f000,
+0x80b001fc,0x00243000,0x7f000e0d,0x001fc003,
+0xc38007f0,0x00c0f001,0xfc0037ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x77250000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_4
+ *
+ * ctr0: counts HIT_DIRTY0 
+ * ctr1: counts HIT_DIRTY1 
+ * ctr2: counts CA_BYP_E (quick launch) 
+ * ctr3: counts CA_BYP_O 
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x7bb70000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+/* mpb_labort
+ *
+ * ctr0: counts L_ABORT_ALU0L
+ * ctr1: counts L_ABORT_ALU1L 
+ * ctr2: counts MPB0H 
+ * ctr3: counts MPB1H 
+ */
+{
+0x0c00c000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x605c0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* panic
+ *
+ * ctr0: is the overflow for counter 1 
+ * ctr1: counts traps and RFI's 
+ * ctr2: counts panic traps 
+ * ctr3: is the overflow for counter 2
+ */
+{
+0x0c002000,00000000,0x00060000,00000000,
+0xe7efe0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffffc,
+0x41380030,0x1aabfff2,0x17000000,00000000,
+0x01b80000,0x3effffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,00000000,0x00400000,
+0x00001fff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x1fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+0xb0000000,0x00012c04,0x05790804,0x14013e44,
+0x0008004f,0x90000040,0x15e46000,0xc0047920,
+0x004a003e,0x40011080,0x0f900024,0x4003e460,
+0x00c80479,0x00023301,0x1e400100,0x4157d080,
+0x514053f4,0x40048014,0xfd000104,0x055f4600,
+0x4c0147d2,0x0014a043,0xf4001508,0x10fd0003,
+0x44043f46,0x004c8147,0xd0003330,0x51f40014,
+0x04257908,0x0c14093e,0x44020802,0x4f900080,
+0x4095e460,0x20c02479,0x20084a08,0x3e400310,
+0x820f9000,0xa44083e4,0x6020c824,0x79000a33,
+0x091e4003,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x10400000,00000000,0x10000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* rare_inst
+ *
+ * ctr0: counts sync and syncdma instructions 
+ * ctr1: counts pxtlbx,x instructions 
+ * ctr2: counts ixtlbt instructions 
+ * ctr3: counts cycles 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0x004e000c,0x000843fc,0x85c09380,
+0x0121ebfd,0xff217124,0xe0004000,0x943fc85f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xe00000e0,0x00003c00,0x007f0001,0x01001fc0,
+0x00408007,0xf0003030,0x01fc000c,0x10007f00,
+0x0505001f,0xc0014180,0x07f00070,0x7001fc00,
+0x1c20007f,0x00090900,0x1fc00242,0x8007f000,
+0xb0b001fc,0x002c3000,0x7f000d0d,0x001fc003,
+0x438007f0,0x00f0f001,0xfc003fff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* rw_dfet (for D-cache misses and writebacks)
+ *
+ * ctr0: counts address valid cycles 
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf0000000,00000000,
+00000000,00000000,0x98000000,00000000,
+0xffffffff,0xffffffff,0x0fffffff,0xffffffff,
+00000000,00000000,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* rw_ifet (I-cache misses -- actually dumb READ transactions)
+ *
+ * ctr0: counts address valid cycles 
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xd0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff,00000000,00000000,
+0xffffffff,0xffffffff },
+
+
+/* rw_sdfet (READ_SHARED_OR_PRIVATE transactions)
+ *
+ * ctr0: counts address valid cycles
+ * ctr1: counts *all* data valid cycles 
+ * ctr2: is the overflow from counter 0 
+ * ctr3: is the overflow from counter 1 
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf4000000,00000000,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff },
+
+
+/* spec_ifet
+ *
+ * ICORE_AV fires for every request which the Instruction Fetch Unit sends
+ * to the Runway Interface Block.  Hence, this counts all I-misses, speculative
+ * or not, but does *not* include I-cache prefetches, which are generated by
+ * RIB.
+ * IRTN_AV fires twice for every I-cache miss returning from RIB to the IFU.
+ * It will not fire if a second I-cache miss is issued from the IFU to RIB
+ * before the first returns.  Therefore, if the IRTN_AV count is much less
+ * than 2x the ICORE_AV count, many speculative I-cache misses are occuring
+ * which are "discovered" to be incorrect fairly quickly.
+ * The ratio of I-cache miss transactions on Runway to the ICORE_AV count is
+ * a measure of the effectiveness of instruction prefetching.  This ratio
+ * should be between 1 and 2.  If it is close to 1, most prefetches are
+ * eventually called for by the IFU; if it is close to 2, almost no prefetches
+ * are useful and they are wasted bus traffic.
+ *
+ * ctr0: counts ICORE_AV 
+ * ctr1: counts IRTN_AV 
+ * ctr2: counts all non-coherent READ transactions on Runway. (TTYPE D0) 
+ *	This should be just I-cache miss and I-prefetch transactions.
+ * ctr3: counts total processor cycles 
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x00000008,0x00030c00,0x01bf0001,0x00806fc0,
+0x00c1001b,0xf0005048,0x06fc001c,0x2001bf00,
+0x0908806f,0xc002c300,0x1bf000d0,0xc806fc00,
+0x3fffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0x06bf0000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00110000,00000000,0xd0ffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff,00000000,00000000,
+0xffffffff,0xffffffff },
+
+/* st_cond0
+ *
+ * ctr0: is the overflow for ctr1
+ * ctr1: counts major ops 0C and 0E (fp ops, not fmac or fmpyadd) 
+ * ctr2: counts B,L (including long and push) and GATE (including nullified),
+ *	 predicted not-taken
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc13380,
+0x0101ffff,0xffa1f057,0xe000407f,0xdfffc87f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond1
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts major ops 1x (most of the load/stores) 
+ * ctr2: counts CMPB (dw) predicted not-taken 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc01b80,
+0x0101ffff,0xffb7f03d,0xe000407f,0xffffc8ff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond2
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts major op 03 
+ * ctr2: counts CMPIB (dw) predicted not taken. 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc09780,
+0x0101ffff,0xff21f077,0xe000407f,0xffffc87f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond3
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts major ops 06 & 26 
+ * ctr2: counts BB, BVB, MOVB, MOVIB (incl. nullified) predicted not-taken 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc03780,
+0x0101ffff,0xff29f016,0xe000407f,0xffffe97f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond4
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts major op 2E 
+ * ctr2: counts CMPB, CMPIB, ADDB, ADDIB (incl. nullified) predicted not-taken 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc17780,
+0x0101ffff,0xff21f014,0xe000407f,0xffffe9ff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_unpred0
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts BE and BE,L 
+ * ctr2: counts BE and BE,L including nullified 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0c0c0e0,0xffffffff,0xffffffff,0xffdf5bbf,
+0xffffffff,0xff25f7d6,0xefffffff,0xffffc97f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_unpred1
+ *
+ * ctr0: is the overflow for ctr1 
+ * ctr1: counts BLR, BV, BVE, BVE,L 
+ * ctr2: counts BLR, BV, BVE, BVE,L including nullified 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0c0c0e0,0xffffffff,0xffffffff,0xffc15f80,
+0x0501ff7f,0xff21f057,0xe001407f,0xdfffc87f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* unpred
+ *
+ * ctr0: counts non-nullified unpredictable branches 
+ * ctr1: is the overflow for ctr0 
+ * ctr2: counts all unpredictable branches (nullified or not) 
+ * ctr3: is the overflow for ctr2 
+ */
+{
+0xcc01e000,00000000,0x00060000,00000000,
+0x20202020,0xff31ffff,0xfff7fffe,0x97ffcc7f,
+0xfffffdff,0xffa5fff3,0x1fffffff,0x7fffe97f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf00000a0,0x00003c00,0x02f50000,0x0004bd40,
+0x0040802f,0x50002020,0x4bd4000c,0x0042f500,
+0x040014bd,0x40014084,0x2f500060,0x214bd400,
+0x1c2002f5,0x00080804,0xbd400242,0x802f5000,
+0xa0a04bd4,0x002c2042,0xf5000c08,0x14bd4003,
+0x42842f50,0x00e0a14b,0xd4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+   
+
+/* go_store
+ *
+ * ctr0: Overflow for counter 2 
+ * ctr1: Overflow for counter 3 
+ * ctr2: count of GO_STORE_E signal 
+ * ctr3: count of GO_STORE_O signal 
+ */
+
+   {
+   0x0c00e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffa5ffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xff000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x7fffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xf0000000,
+   0x00000000,   0x0000c000,   0x067c0000,   0x01019f00,
+   0x00408067,   0xc0002030,   0x19f0000c,   0x000e7c00,
+   0x0401039f,   0x00014080,   0xe7c00060,   0x3039f000,
+   0x1c00167c,   0x00080105,   0x9f000240,   0x8167c000,
+   0xa03059f0,   0x002c001e,   0x7c000c01,   0x079f0003,
+   0x4081e7c0,   0x00e03079,   0xf0003fc0,   0x07fff800,
+   0xf001fffe,   0x003c007f,   0xff800f00,   0x1fffe003,
+   0xc007fff8,   0x00f001ff,   0xfe003c00,   0x7fff800f,
+   0x001fffe0,   0x03c007ff,   0xf800f001,   0xfffe003c,
+   0x007fff80,   0x0f001fff,   0xe003c007,   0xfff800f0,
+   0x01fffe00,   0x3c007fff,   0x800f001f,   0xffe00000,
+   0x00000000,   0x00000000,   0x00000000,   0x00000000,
+   0x70130000,   0x00000000,   0x70000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xfffffc00,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xfffffc00,   0x00000000,
+   0xffffaaaa,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffaaaa,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0x00030000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff
+   },
+
+
+/* shlib_call
+ *
+ * ctr0: SharedLib call Depth1 
+ * ctr1: SharedLib call Depth2 
+ * ctr2: SharedLib call Depth3 
+ * ctr3: SharedLib call Depth>3 
+ */
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0xc76fa005,   0x07dd7e9c,   0x87115b80,
+   0x01100200,   0x07200004,   0xe000407f,   0xfffffffc,
+   0x01380010,   0x1fffffff,   0xff000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xf0000000,
+   0xf0000000,   0x00003c20,   0x01ff0808,   0x04007fc0,
+   0x0003001f,   0xf0000180,   0x07fc4010,   0x5001ff00,
+   0x001c007f,   0xc2000a00,   0x1ff18022,   0x4007fc20,
+   0x00b001ff,   0x10003800,   0x7fc8004d,   0x001ff100,
+   0x03c007fc,   0x60012001,   0xff280144,   0x007fc600,
+   0x13001ff2,   0x00058007,   0xfcc00550,   0x01ff2000,
+   0x5c007fca,   0x001a001f,   0xf3801640,   0x07fca001,
+   0xb001ff30,   0x0078007f,   0xd0005d00,   0x1ff30007,
+   0xc007fce0,   0x022001ff,   0x48018400,   0x7fce0023,
+   0x001ff400,   0x098007fd,   0x20065001,   0xff40009c,
+   0x007fd200,   0x3fffffff,   0x800fffff,   0xffe00000,
+   0x00000000,   0x00000000,   0x00000000,   0x00000000,
+   0xffff0000,   0x00000000,   0xf0000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xfffffc00,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xfffffc00,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xf3ffffff,   0xffffffff,
+   0xfdffffff,   0xffffffff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0xffffffff,   0xfffff9ff,   0xfe000000,   0x00000000,
+   0x00030000,   0x00000000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff
+   }
+};
+#define PCXW_IMAGE_SIZE 576
+
+static uint32_t cuda_images[][PCXW_IMAGE_SIZE/sizeof(uint32_t)] = {
+/*
+ * CPI:     FROM CPI.IDF (Image 0)
+ *
+ * Counts the following:
+ *
+ * ctr0 : total cycles
+ * ctr1 : total cycles where nothing retired
+ * ctr2 : total instructions retired, including nullified
+ * ctr3 : total instructions retired, less nullified instructions
+ */
+   {
+   0x4c00c000,   0x00000000,   0x00060000,   0x00000000, 
+   0xe0e0e0e0,   0x00001fff,   0xfc00007f,   0xfff00001, 
+   0xffffc000,   0x07ffff00,   0x07ffffff,   0x6007ffff, 
+   0xff0007ff,   0xffff0007,   0xffffff00,   0x00000000, 
+   0x60f00000,   0x0fffff00,   0x000fffff,   0x00000fff, 
+   0xff00000f,   0xffff0000,   0x00000000,   0x00ffffff, 
+   0xfffff000,   0x0000000f,   0xffffffff,   0xff000000, 
+   0x0000ffff,   0xfffffff0,   0x00000000,   0x0fffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0x00270000,   0x00000055, 
+   0x0200000e,   0x4d300000,   0x00000000,   0x0ff00002, 
+   0x70000000,   0x00000020,   0x0000e400,   0x00000ff0, 
+   0x00000000,   0x00000000,   0x00000055,   0xffffff00, 
+   0x00000000,   0x0000ff00,   0x00000000,   0x0f000000, 
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000, 
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000, 
+   0x00000000,   0x00ff0000,   0x00000000,   0xf0000000, 
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000, 
+   0x00000000,   0x00000000,   0x00055fff,   0xfff00000, 
+   0x00000000,   0x0ff00000,   0x00000030,   0x00000000, 
+   0x00157fff,   0xffc00000,   0x034c0000,   0x00000000, 
+   0x03fc0000,   0x00000000,   0x6fff0000,   0x00000000, 
+   0x60000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* Bus utilization image   FROM BUS_UTIL.IDF (Image 1)
+ *
+ * ctr0 : counts address valid cycles
+ * ctr1 : counts data valid cycles
+ * ctr2 : counts overflow from counter 0
+ * ctr3 : counts overflow from counter 1
+ */
+         {
+	 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+	 0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+	 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+	 0x00000000, 0x00000000, 0x00001b00, 0xaa000000,
+	 0x00000001, 0x30700000, 0x00055aaf, 0xf0000000,
+	 0x01b00000, 0x00000000, 0x00001037, 0x00000000,
+	 0x55aaff00, 0x00c00000, 0x1b55aa00, 0x00000000,
+	 0x0001fff0, 0xcfffff00, 0x00000000, 0x0f0fffff,
+	 0xffffffff, 0xffffffff, 0x30ffff0c, 0xfffff000,
+	 0x00000000, 0x00ffffff, 0xffffffff, 0xfffffff3,
+	 0x0ffff0cf, 0xffff0000, 0x00000000, 0x00ffffff,
+	 0xffffffff, 0xfffffff3, 0x0ffff0cf, 0xffff0000,
+	 0x00000000, 0x0fffffff, 0xffffffff, 0xffffff30,
+	 0xfff70000, 0x000055aa, 0xff000000, 0x000006d5,
+	 0x40000000, 0x00000000, 0x731c0000, 0x000156ab,
+	 0xfc000000, 0x00000000, 0xffff0000, 0x00000000,
+	 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+	 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+	 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+	 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+	 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+	 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+	 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+	 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+	 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+	 0xfe000000, 0x00000000, 0x00100000, 0x00000000,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+   },
+
+/*
+ * TLB counts:    FROM TLBSTATS.IDF (Image 2)
+ *
+ * Counts the following:
+ *
+ * ctr0: DTLB misses
+ * ctr1: ITLB misses
+ * ctr2: total cycles in the miss handlers
+ * ctr3: total cycles
+ */
+
+   {
+   0x0c00c000,   0x00000000,   0x00060000,   0x00000000, 
+   0xe7e7e0e0,   0x00001fff,   0xfc00007f,   0xfff00001, 
+   0xfff00000,   0x07ffff00,   0x07ffffff,   0x6007ffff, 
+   0xa00007ff,   0xffff0007,   0xffffff00,   0x00000000, 
+   0x603001c1,   0xe0000001,   0xc0c00000,   0x00000fff, 
+   0xff00000f,   0xffff0000,   0x00000000,   0x00400000, 
+   0x00001000,   0x00000004,   0x00000000,   0x01000000, 
+   0x0000ffff,   0xfffffff0,   0x00000000,   0x0fffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0x00800000,   0x00153f7f, 
+   0x55000000,   0xaf800000,   0xc0000000,   0x0403f240, 
+   0x00000000,   0x00001010,   0x00004700,   0x00000ff0, 
+   0x00000000,   0x00000000,   0x00000055,   0xffffff00, 
+   0x00000000,   0x0000ff00,   0x00000000,   0x0f000000, 
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000, 
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000, 
+   0x00000000,   0x00ff0000,   0x00000000,   0xf0000000, 
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000, 
+   0x00000000,   0x00000000,   0x00055fff,   0xfff00000, 
+   0x00000000,   0x0ff00000,   0x00000000,   0x00000000, 
+   0x00157fff,   0xffc00000,   0x00000000,   0x3fc00000, 
+   0x00040000,   0x00000000,   0x6fff0000,   0x00000000, 
+   0x60000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* tlbhandler  FROM tlbHandMiss.idf (Image 3)
+ *
+ * ctr0: TLB misses
+ * ctr1: dmisses inside the TLB miss handler
+ * ctr2: cycles in the TLB miss handler
+ * ctr3: overflow of ctr2
+ */
+   {
+   0x1c00c000,   0x00000000,   0x00060000,   0x00000000, 
+   0xe7e7e0e0,   0x00001fff,   0xfc00007f,   0xfff00001, 
+   0xfff00000,   0x07ffff00,   0x07ffffff,   0x6007ffff, 
+   0xa00007ff,   0xffff0007,   0xffffff00,   0x00000000, 
+   0x603001c1,   0xe0000001,   0xc0c00000,   0x00000fff, 
+   0xff00000f,   0xffff0000,   0x00000000,   0x00400000, 
+   0x00001000,   0x00000004,   0x00000000,   0x01000000, 
+   0x0000ffff,   0xfffffff0,   0x00000000,   0x0fffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0x006c0000,   0x01000054, 
+   0x02000002,   0xc3200000,   0xc00aa000,   0x0c03f240, 
+   0x00000000,   0x00001010,   0x000044f4,   0x00000c00, 
+   0xaa0000f0,   0x0f0000b0,   0x00005005,   0x0f5f0000, 
+   0x0001f000,   0x0000ff00,   0x00000000,   0x0f000000, 
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000, 
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000, 
+   0x00000000,   0x00ff0000,   0x00000000,   0xf0000000, 
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000, 
+   0x00000000,   0x00000000,   0x00055fff,   0xfff00000, 
+   0x00000000,   0x0ff00a00,   0x000f0000,   0x24004000, 
+   0x15400001,   0x40c00003,   0x3da00000,   0x0002a800, 
+   0x00ff0000,   0x00000000,   0x6fff0000,   0x00000000, 
+   0x60000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* branch_taken image  FROM PTKN.IDF (Image 4)
+ *
+ * ctr0: mispredicted branches
+ * ctr1: predicted taken branches, actually taken
+ * ctr2: predicted taken branches (includes nullfied)
+ * ctr3: all branches
+ */
+
+   {
+   0xcc01e000,   0x00000000,   0x00000000,   0x00000000, 
+   0xa08080a0,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xfffffeff,   0xfffeffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf4ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900, 
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x0f0fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000000, 
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* branch_nottaken  FROM PNTKN.IDF (Image 5)
+ *
+ * ctr0: mispredicted branches
+ * ctr1: branches predicted not-taken, but actually taken
+ * ctr2: branches predicted not-taken (includes nullified)
+ * ctr3: all branches
+ */
+   {
+   0xcc01e000,   0x00000000,   0x00000000,   0x00000000, 
+   0xe0c0c0e0,   0xffffffff,   0xffffffff,   0xffefffff, 
+   0xffffbfff,   0xfffffeff,   0xfffeffff,   0xfffffeff, 
+   0xfffffffe,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf4ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900, 
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x0f0fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000000, 
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+   
+/* IMISS image (Image 6)
+ *
+ * ctr0 : icache misses for retired instructions
+ * ctr1 : total cycles
+ * ctr2 : dcache misses for retired instructions
+ * ctr3 : number of retired instructions
+ */
+   {
+   0x2801e000,   0x00000000,   0x00010000,   0x00000000, 
+   0x00001000,   0xffffffff,   0xffffffff,   0xfff00fff, 
+   0xfffa3fff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xf2fdf0f0,   0xf0f0f0f0, 
+   0xffffffff,   0xf6c00000,   0x00000000,   0x0ff55800, 
+   0x90000000,   0x00000000,   0x0000b0ff,   0xfffffff0, 
+   0x00000003,   0x0100bfff,   0x3f3f3f3f,   0x3f3f5555, 
+   0x555fffff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xfff00000,   0x000301b0,   0x2fefcfcf, 
+   0xcfcfcfcf,   0xd5555557,   0xf7b40000,   0x00000000, 
+   0x03c14000,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* DMISS image (Image 7)
+ *
+ * ctr0 : icache misses for retired instructions
+ * ctr1 : total cycles
+ * ctr2 : dcache misses for retired instructions
+ * ctr3 : number of retired instructions
+ */
+   {
+   0x2801e000,   0x00000000,   0x00010000,   0x00000000, 
+   0x00001000,   0xffffffff,   0xffffffff,   0xfff00fff, 
+   0xfffa3fff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xf2fdf0f0,   0xf0f0f0f0, 
+   0xffffffff,   0xf6c00000,   0x00000000,   0x0ff55800, 
+   0x90000000,   0x00000000,   0x0000b0ff,   0xfffffff0, 
+   0x00000003,   0x0100bfff,   0x3f3f3f3f,   0x3f3f5555, 
+   0x555fffff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xfff00000,   0x000301b0,   0x2fefcfcf, 
+   0xcfcfcfcf,   0xd5555557,   0xf7b40000,   0x00000000, 
+   0x03c14000,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* dmiss_access image    FROM DMISS_RATIO.IDF  (Image 8)
+ * 
+ * ctr0 : all loads and stores that retire (even lines)
+ * ctr1 : all loads and stores that retire (odd lines)
+ * ctr2 : dcache misses of retired loads/stores
+ * ctr3 : all READ_PRIV and READ_SHAR_OR_PRIV on Runway
+ *        (Speculative and Non-Speculative)
+ */
+   {
+   0x2d81e000,   0x00000000,   0x00000000,   0x00000000, 
+   0x10101010,   0x00ffffff,   0xa003ffff,   0xfe800fff, 
+   0xfffa003f,   0xffffe8ff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd2280a00,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000005,   0x555ff900, 
+   0x80200000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x00005555,   0xff80bf8b,   0xab030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x15153fe0,   0x27628880, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000001, 
+   0x5557fc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00110000,   0x00000000, 
+   0xf4ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xf8ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+
+/* big_cpi image  (Image 9)
+ * 
+ * ctr0 : Total number of CPU clock cycles. 
+ * ctr1 : Unused 
+ * ctr2 : Unused
+ * ctr3 : Total number of Non-Nullified instructions retired. 
+ */
+   {
+   0x0c00c000,   0x00000000,   0x00060000,   0x00000000,
+   0xe7e7e0e0,   0x00001fff,   0xfc00007f,   0xfff00001,
+   0xfff00000,   0x07ffff00,   0x07ffffff,   0x6007ffff,
+   0xa00007ff,   0xffff0007,   0xffffff00,   0x00000000,
+   0x603001c1,   0xe0000001,   0xc0c00000,   0x00000fff,
+   0xff00000f,   0xffff0000,   0x00000000,   0x00400000,
+   0x00001000,   0x00000004,   0x00000000,   0x01000000,
+   0x0000ffff,   0xfffffff0,   0x00000000,   0x0fffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x00550005,   0x00220000,
+   0x0000000c,   0x71f00000,   0x00f00aa0,   0x0aaff000,
+   0x00005002,   0x20000000,   0x0000c413,   0x00000c0f,
+   0x00aa0000,   0xff00b600,   0x000500a0,   0x00000300,
+   0x000cc3f0,   0x0000c0f0,   0x0aa0000f,   0xff000000,
+   0x011000a0,   0x05503000,   0x00d03700,   0x00000f00,
+   0xaa005500,   0x00000000,   0x000055ff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0xf000aa00,
+   0x11000a00,   0x55000000,   0x0d037000,   0x00c0f00a,
+   0xa0055000,   0x0db00005,   0x5002a000,   0x00300000,
+   0xf40f0000,   0x0c0f00aa,   0x0000ff10,   0x27400000,
+   0x00008000,   0x00c00003,   0x037c0000,   0x003c02a8,
+   0x02abfc00,   0x00000000,   0x6fff0000,   0x00000000,
+   0x60000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* big_ls image  (Image 10)
+ * 
+ * ctr0 : Total number of CPU clock cycles during which local_stall_A1 is asserted 
+ * ctr1 : Overflow of Counter 0 
+ * ctr2 : Total number of IFLUSH_AV 
+ * ctr3 : Overflow of Counter 2 
+ */
+   {
+   0x0c000000,   0x00000000,   0x00060000,   0x00000000,
+   0xefefefef,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x28880001,   0x54000000,
+   0x00000004,   0xb6200000,   0x000aaaa0,   0x05555288,
+   0x80000010,   0x00000000,   0x0000486e,   0x00000000,
+   0xaaaa0055,   0x55002888,   0x00545401,   0x03030000,
+   0x0007b000,   0x0000ff00,   0x00000000,   0x05000000,
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000,
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0x00000000,
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000,
+   0x00000000,   0xa0000000,   0x00055fff,   0xfff00000,
+   0x00aa0000,   0x05502a2a,   0x00151500,   0x0a220015,
+   0x40400000,   0x00000001,   0xe2980000,   0x0002aaa8,
+   0x01555400,   0x00000000,   0x0df70000,   0x00000000,
+   0x00000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* br_abort image  (Image 12)
+ * 
+ * ctr0 : Total number of BRAD_STALLH
+ * ctr1 : Total number of ONE_QUAD
+ * ctr2 : Total number of BR0_ABRT
+ * ctr3 : Total number of BR1_ABRT
+ */
+
+   {
+   0x0c002000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0xffffffff,   0xffffffff,   0xff0fffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0x1077ffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x551b0000,   0x00000000,
+   0x0000000c,   0xd4f00000,   0x00000000,   0x0ffff001,
+   0xb0000000,   0x00000000,   0x0000fd4c,   0x00000000,
+   0x000000ff,   0xff00ff1b,   0x00000000,   0x00000000,
+   0x0000d000,   0x0000ff00,   0x00000000,   0x0e0fffff,
+   0xffffffff,   0xfffff000,   0x00000000,   0x000ff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0x00ffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0x00ff0000,
+   0x00000000,   0xffffffff,   0xffffffff,   0xfff00000,
+   0x00400000,   0x00000000,   0x00ffff00,   0x2a86c000,
+   0x00000000,   0x00000000,   0xf50c0000,   0x00000000,
+   0x03fffc00,   0x00000000,   0x1a250000,   0x00000000,
+   0x10000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffafff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffafff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+
+/* isnt image  (Image 13)
+ * 
+ * ctr0 : Total number of cycles for which iside_notrans is asserted. 
+ * ctr1 : Total number of times iside_notrans is asserted for 1-4 cycles. 
+ * ctr2 : Total number of times iside_notrans is asserted for 5-7 cycles. 
+ * ctr3 : Total number of times iside_notrans is asserted for > 7 cycles. 
+ */
+
+   {
+   0x0c018000,   0x00000000,   0x00060000,   0x00000000,
+   0xefefefef,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0xc0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x22000000,   0x000001bc,
+   0x10000006,   0x00900000,   0x50000000,   0x00055a20,
+   0x00000000,   0x00016060,   0x0000c021,   0x00000540,
+   0x00000000,   0x55002200,   0x00000000,   0x56bc4000,
+   0x00048000,   0x0000ff00,   0x00000000,   0x17000000,
+   0x0000055f,   0xfffff000,   0x00000000,   0x000ff000,
+   0x00000000,   0x00000000,   0x000055ff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0x00000000,
+   0x000055ff,   0xffff0000,   0x00000000,   0x00ff0000,
+   0x00000000,   0x80000000,   0x00015bf3,   0xf5500000,
+   0x02210000,   0x00100000,   0x00005500,   0x08800000,
+   0x00001545,   0x85000001,   0x80240000,   0x11000000,
+   0x00015400,   0x00000000,   0xcdff0000,   0x00000000,
+   0xc0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* quadrant image  (image 14)
+ * 
+ * ctr0 : Total number of instructions in quadrant 0. 
+ * ctr1 : Total number of instructions in quadrant 1. 
+ * ctr2 : Total number of instructions in quadrant 2. 
+ * ctr3 : Total number of instructions in quadrant 3. 
+ *
+ * Only works for 32-bit applications.
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0x00001fff,   0xfc00007f,   0xfff00001,
+   0xffffc000,   0x07ffff00,   0x07ffffff,   0x0007ffff,
+   0xff0007ff,   0xffff0007,   0xffffff00,   0x00000000,
+   0xf0000000,   0x0fffff00,   0x000fffff,   0x00000fff,
+   0xff00000f,   0xffff0000,   0x00000000,   0x00ffffff,
+   0xffcff000,   0x0000040f,   0xfffffffc,   0xff000000,
+   0x0080ffff,   0xffffcff0,   0x0000000c,   0x0fffffff,
+   0xfcff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x551b0000,   0x00000000,
+   0x00000003,   0x17000000,   0x00000000,   0x0ffff001,
+   0xb0000000,   0x00000000,   0x00000173,   0x00000000,
+   0x000000ff,   0xff00ff1b,   0x00000000,   0x00000000,
+   0x000f1ff0,   0xcfffff00,   0x00000000,   0x0f0fffff,
+   0xffffffff,   0xffffffff,   0x30ffff0c,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xfffffff3,
+   0x0ffff0cf,   0xffff0000,   0x00000000,   0xf0ffffff,
+   0xffffffff,   0xfffffff3,   0x0ffff0cf,   0xffff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffff30,
+   0xff7f0000,   0x00000000,   0x00fffff0,   0x2a86c000,
+   0x00000000,   0x00000003,   0x05f00000,   0x00000000,
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* rw_pdfet image (Image 15)
+ * 
+ * ctr0 : Total of all READ_PRIV address valid cycles. 
+ * ctr1 : Total of all READ_PRIV data valid cycles. 
+ * ctr2 : Overflow of Counter 0. 
+ * ctr3 : Overflow of Counter 1. 
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xefefefef,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x00001b00,   0xaa000000,
+   0x00000001,   0x30700000,   0x00055aaf,   0xf0000000,
+   0x01b00000,   0x00000000,   0x00001037,   0x00000000,
+   0x55aaff00,   0x00c00000,   0x1b55aa00,   0x00000000,
+   0x0001fff0,   0xcfffff00,   0x00000000,   0x0f0fffff,
+   0xffffffff,   0xffffffff,   0x30ffff0c,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xfffffff3,
+   0x0ffff0cf,   0xffff0000,   0x00000000,   0x00ffffff,
+   0xffffffff,   0xfffffff3,   0x0ffff0cf,   0xffff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffff30,
+   0xfff70000,   0x000055aa,   0xff000000,   0x000006d5,
+   0x40000000,   0x00000000,   0x731c0000,   0x000156ab,
+   0xfc000000,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00100000,   0x00000000,
+   0xf8000000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffffff,
+   0x00ffffff,   0xffffffff,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffffff,
+   },
+
+
+/* rw_wdfet image  (Image 16)
+ * 
+ * ctr0 : Counts total number of writeback transactions. 
+ * ctr1 : Total number of data valid Runway cycles. 
+ * ctr2 : Overflow of Counter 0. 
+ * ctr3 : Overflow of Counter 1. 
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xefefefef,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x00001b00,   0xaa000000,
+   0x00000001,   0x30700000,   0x00055aaf,   0xf0000000,
+   0x01b00000,   0x00000000,   0x00001037,   0x00000000,
+   0x55aaff00,   0x00c00000,   0x1b55aa00,   0x00000000,
+   0x0001fff0,   0xcfffff00,   0x00000000,   0x0f0fffff,
+   0xffffffff,   0xffffffff,   0x30ffff0c,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xfffffff3,
+   0x0ffff0cf,   0xffff0000,   0x00000000,   0x00ffffff,
+   0xffffffff,   0xfffffff3,   0x0ffff0cf,   0xffff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffff30,
+   0xfff70000,   0x000055aa,   0xff000000,   0x000006d5,
+   0x40000000,   0x00000000,   0x731c0000,   0x000156ab,
+   0xfc000000,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00100000,   0x00000000,
+   0x98000000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffffff,
+   0x00ffffff,   0xffffffff,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffffff,
+   },
+
+/* shlib_cpi image  (Image 17)
+ * 
+ * ctr0 : Total number of instructions in quadrant 0. 
+ * ctr1 : Total number of CPU clock cycles in quadrant 0. 
+ * ctr2 : Total number of Non-Nullified instructions retired. 
+ * ctr3 : Total number of CPU clock cycles. 
+ *
+ * Only works for 32-bit shared libraries.
+ */
+
+   {
+   0x0c01e000,   0x00000000,   0x00060000,   0x00000000,
+   0xe0e0e0e0,   0x00001fff,   0xfc00007f,   0xfff00001,
+   0xffffc000,   0x07ffff00,   0x07ffffff,   0x0007ffff,
+   0xff0007ff,   0xffff0007,   0xffffff00,   0x00000000,
+   0xf0150000,   0x0fffff00,   0x000fffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0x00ffffff,
+   0xffcff000,   0x0000000f,   0xfffffffc,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0x27000000,   0x00000055,
+   0x02000005,   0x7f500000,   0xc0000000,   0x000ff270,
+   0x00000000,   0x00000000,   0x00007700,   0x00000ff0,
+   0x00000000,   0x0000ffff,   0xffffffff,   0xffffff00,
+   0x00000000,   0x0000ff00,   0x00000000,   0x0f0fffff,
+   0xffffffff,   0xfffff000,   0x00000000,   0x000ff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffff0000,
+   0x00000000,   0x00ff0000,   0x00000000,   0xf0ffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0x00ff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xfff00000,
+   0x00000000,   0x0ff00000,   0x000000a0,   0x3fffffff,
+   0xffffffff,   0xffc00000,   0x03d40000,   0x20000000,
+   0x0003fc00,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff7fbfc,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff7fbfc,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00030000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* flop image  (Image 18)
+ * 
+ * ctr0 : Total number of floating point instructions (opcode = 0xc). 
+ * ctr1 : Total number of floating point instructions (opcode = 0xe, 0x6, 0x2e, 0x26). 
+ * ctr2 : Unused
+ * ctr3 : Unused 
+ */
+
+   {
+   0x0001e000,   0x00000000,   0x00000000,   0x00000000,
+   0x00001010,   0x33ffffff,   0x006fffff,   0xfc5fffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000,
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900,
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000,
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000,
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000,
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff,
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000,
+   0x00000000,   0x00000002,   0x67840000,   0x00000000,
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000,
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* cachemiss image    FROM I_D_MISSES.IDF  (Image 19)
+ *
+ * ctr0 : icache misses for retired instructions
+ * ctr1 : total cycles
+ * ctr2 : dcache misses for retired instructions
+ * ctr3 : number of retired instructions
+ */
+   {
+   0x2801e000,   0x00000000,   0x00010000,   0x00000000, 
+   0x00001000,   0xffffffff,   0xffffffff,   0xfff00fff, 
+   0xfffa3fff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf0ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xf2fdf0f0,   0xf0f0f0f0, 
+   0xffffffff,   0xf6c00000,   0x00000000,   0x0ff55800, 
+   0x90000000,   0x00000000,   0x0000b0ff,   0xfffffff0, 
+   0x00000003,   0x0100bfff,   0x3f3f3f3f,   0x3f3f5555, 
+   0x555fffff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xfff00000,   0x000301b0,   0x2fefcfcf, 
+   0xcfcfcfcf,   0xd5555557,   0xf7b40000,   0x00000000, 
+   0x03c14000,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* branch   FROM br_report3.idf 
+ *
+ * ctr0 : Total number of mispredicted branches. 
+ * ctr1 : Some Non-Nullified unpredictable branches. 
+ * ctr2 : Total number of branches (Nullified + Non-Nullified)
+ *        (Unpredicted+ Predicted Taken +Predicted Not Taken). 
+ *	  Total of All Branches.
+ * ctr3 : Remaining Non-Nullified unpredictable branches.
+ */
+   {
+   0x4001e000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0xffffffff,   0xff9fffff,   0xfe0fffff, 
+   0xffffbaff,   0xfdffc0ff,   0xfffdffff,   0xfffffeff, 
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf4ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900, 
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000000, 
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* crstack  FROM crs_report.idf
+ *
+ * ctr0: correctly predicted branches by the pop_latch
+ * ctr1: some procedure returns
+ * ctr2: all branches, (includes nullified)
+ * ctr3: remaining procedure returns
+ */
+   {
+   0x4001e000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0xffffffff,   0xffa10300,   0x000fffff, 
+   0xffffbaf8,   0x3000007f,   0xffffffff,   0xfffffeff, 
+   0xff7fffff,   0xffffffff,   0xffffff00,   0x00000000, 
+   0xf2ffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000, 
+   0x00000000,   0x00000000,   0xd22d0000,   0x00000000, 
+   0x0000000b,   0x46000000,   0x00000000,   0x0ffff900, 
+   0x90000000,   0x00000000,   0x0000907e,   0x00000000, 
+   0x000000ff,   0xff00bfdf,   0x03030303,   0x03030000, 
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000, 
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffff0000,   0x00000000,   0xf0ffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000, 
+   0x00000000,   0x0fffffff,   0xffffffff,   0xffffffff, 
+   0xffff5555,   0x55500000,   0x003f3ff0,   0x2766c000, 
+   0x00000000,   0x00000002,   0x67840000,   0x00000000, 
+   0x03fffc00,   0x00000000,   0xffff0000,   0x00000000, 
+   0xf0000000,   0x00000000,   0x00ffffff,   0xff3fffff, 
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000, 
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff, 
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f, 
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc, 
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff, 
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff, 
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   },
+
+/* icache_report image 
+ * 
+ * ctr0 : Icache misses actually used by the core. 
+ * ctr1 : ICORE_AV (Icache misses the core THINKS it needs, including fetching down speculative paths). 
+ * ctr2 : READs on Runway (Icache misses that made it out to Runway, including
+ *	  prefetches).
+ * ctr3 : Prefetch returns (1x and 2x). 
+ */
+   {
+   0x00000000,   0x00000000,   0x00010000,   0x00000000,
+   0x00000000,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffff00,   0x00000000,
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffff0000,   0x00000000,   0x00000000,   0x00000000,
+   0x00000000,   0x00000000,   0xd2002d00,   0x00000000,
+   0x0000000b,   0x46000000,   0x0000000f,   0xf00ff900,
+   0x00900000,   0x00000000,   0x0000907e,   0x00000000,
+   0x0000ff00,   0xff83bf03,   0xdf030303,   0x03030000,
+   0x000dbfff,   0xffffff00,   0x00000000,   0x000fffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xfffff000,
+   0x00000000,   0x00ffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffff0000,   0x00000000,   0x80ffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffff0000,
+   0x00000000,   0x4fffffff,   0xffffffff,   0xffffffff,
+   0xffff5555,   0x55500000,   0x3f003f80,   0x274026c0,
+   0x00000000,   0x00000002,   0x67840000,   0x00000003,
+   0xfc03fc00,   0x00000000,   0x0eff0000,   0x00000000,
+   0x00000000,   0x00000000,   0x00ffffff,   0xff3fffff,
+   0xffffffff,   0xffcfffff,   0xfff6fb7c,   0x00000000,
+   0x00ffffff,   0xff3fffff,   0xffffffff,   0xffcfffff,
+   0xfff6fb7c,   0x00000000,   0xffff0fff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffff0fff,   0xffffff3f,
+   0xffffffff,   0xffffff7f,   0xffffffff,   0xfffffefc,
+   0x00000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0xffffffff,   0xfffff9ff,
+   0xfe000000,   0x00000000,   0x00130000,   0x00000000,
+   0xd0ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0x00ffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   0xffffffff,   0xffffffff,   0xffffffff,   0xffffffff,
+   
+   }
+
+};
+
+#endif
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/power.c linux-2.4.20-pre2/arch/parisc/kernel/power.c
--- linux-2.4.20-pre1/arch/parisc/kernel/power.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/power.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,377 @@
+/*
+ * linux/arch/parisc/kernel/power.c
+ * HP PARISC soft power switch support driver
+ *
+ * Copyright (c) 2001-2002 Helge Deller <deller@gmx.de>
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *
+ *
+ * 
+ *  HINT:
+ *  Support of the soft power switch button may be enabled or disabled at
+ *  runtime through the "/proc/sys/kernel/power" procfs entry.
+ */ 
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+
+#include <asm/gsc.h>
+#include <asm/pdc.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/led.h>
+#include <asm/led.h>
+#include <asm/uaccess.h>
+
+
+#ifdef DEBUG
+# define DPRINTK(x) printk x
+#else
+# define DPRINTK(x) do { } while (0)
+#endif
+
+
+/* filename in /proc which can be used to enable/disable the power switch */
+#define SYSCTL_FILENAME		"sys/kernel/power"
+
+
+#define DIAG_CODE(code)		(0x14000000 + ((code)<<5))
+
+/* this will go to processor.h or any other place... */
+/* taken from PCXL ERS page 82 */
+#define MFCPU_X(rDiagReg, t_ch, t_th, code) \
+	(DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) )
+	
+#define MTCPU(dr, gr)		MFCPU_X(dr, gr,  0, 0x12)       /* move value of gr to dr[dr] */
+#define MFCPU_C(dr, gr)		MFCPU_X(dr, gr,  0, 0x30)	/* for dr0 and dr8 only ! */
+#define MFCPU_T(dr, gr)		MFCPU_X(dr,  0, gr, 0xa0)	/* all dr except dr0 and dr8 */
+	
+#define __getDIAG(dr) ( { 			\
+        register unsigned long __res asm("r28");\
+	 __asm__ __volatile__ (			\
+		".word %1\n nop\n" : "=&r" (__res) : "i" (MFCPU_T(dr,28)) \
+	);					\
+	__res;					\
+} )
+
+
+static void deferred_poweroff(void *dummy)
+{
+	extern int cad_pid;	/* from kernel/sys.c */
+	if (kill_proc(cad_pid, SIGINT, 1)) {
+		/* just in case killing init process failed */
+		machine_power_off();
+	}
+}
+
+/*
+ * This function gets called from interrupt context.
+ * As it's called within an interrupt, it wouldn't sync if we don't
+ * use schedule_task().
+ */
+
+static void poweroff(void)
+{
+	static int powering_off;
+	static struct tq_struct poweroff_tq = {
+		routine: deferred_poweroff,
+	};
+
+	if (powering_off)
+		return;
+
+	powering_off++;
+	schedule_task(&poweroff_tq);
+}
+
+
+/* local time-counter for shutdown */
+static int shutdown_timer;
+
+/* check, give feedback and start shutdown after one second */
+static void process_shutdown(void)
+{
+	if (shutdown_timer == 0)
+		DPRINTK((KERN_INFO "Shutdown requested...\n"));
+
+	shutdown_timer++;
+	
+	/* wait until the button was pressed for 1 second */
+	if (shutdown_timer == HZ) {
+		static char msg[] = "Shutting down...";
+		DPRINTK((KERN_INFO "%s\n", msg));
+#ifdef CONFIG_CHASSIS_LCD_LED
+		lcd_print(msg);
+#endif
+		poweroff();
+	}
+}
+
+
+/* main power switch tasklet struct (scheduled from time.c) */
+DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0);
+
+/* soft power switch enabled/disabled */
+#ifdef CONFIG_PROC_FS
+static int pwrsw_enabled = 1;
+#else
+#define pwrsw_enabled (1)
+#endif
+
+/*
+ * On gecko style machines (e.g. 712/xx and 715/xx) 
+ * the power switch status is stored in Bit 0 ("the highest bit")
+ * of CPU diagnose register 25.
+ * 
+ */
+static void gecko_tasklet_func(unsigned long unused)
+{
+	if (!pwrsw_enabled)
+		return;
+
+	if (__getDIAG(25) & 0x80000000) {
+		/* power switch button not pressed or released again */
+		/* Warning: Some machines do never reset this DIAG flag! */
+		shutdown_timer = 0;
+	} else {
+		process_shutdown();
+	}
+}
+
+
+
+/*
+ * Check the power switch status which is read from the
+ * real I/O location at soft_power_reg.
+ * Bit 31 ("the lowest bit) is the status of the power switch.
+ */
+
+static void polling_tasklet_func(unsigned long soft_power_reg)
+{
+        unsigned long current_status;
+	
+	if (!pwrsw_enabled)
+		return;
+
+	current_status = gsc_readl(soft_power_reg);
+	if (current_status & 0x1) {
+		/* power switch button not pressed */
+		shutdown_timer = 0;
+	} else {
+		process_shutdown();
+	}
+}
+
+
+/*
+ * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2) 
+ */
+#if 0
+static void powerfail_interrupt(int code, void *x, struct pt_regs *regs)
+{
+	printk(KERN_CRIT "POWERFAIL INTERRUPTION !\n");
+	poweroff();
+}
+#endif
+
+
+
+
+/* 
+ * /proc filesystem support 
+ */
+
+#ifdef CONFIG_SYSCTL
+static int power_proc_read(char *page, char **start, off_t off, int count, 
+	int *eof, void *data)
+{
+	char *out = page;
+	int len;
+
+	out += sprintf(out, "Software power switch support: ");
+	out += sprintf(out, pwrsw_enabled ? "enabled (1)" : "disabled (0)" );
+	out += sprintf(out, "\n");
+
+	len = out - page - off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else {
+		len = count;
+	}
+	*start = page + off;
+	return len;
+}
+
+static int power_proc_write(struct file *file, const char *buf, 
+	unsigned long count, void *data)
+{
+	char *cur, lbuf[count];
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	memset(lbuf, 0, count);
+
+	copy_from_user(lbuf, buf, count);
+	cur = lbuf;
+
+	/* skip initial spaces */
+	while (*cur && isspace(*cur))
+		cur++;
+
+	switch (*cur) {
+	case '0':	pwrsw_enabled = 0;
+			break;
+	case '1':	pwrsw_enabled = 1;
+			break;
+	default:	printk(KERN_CRIT "/proc/" SYSCTL_FILENAME 
+					": Parse error: only '0' or '1' allowed!\n");
+			return -EINVAL;
+	} /* switch() */
+
+	return count;
+}
+
+static struct proc_dir_entry *ent;
+
+static void __init power_create_procfs(void)
+{
+	if (!power_tasklet.func)
+		return;
+	
+	ent = create_proc_entry(SYSCTL_FILENAME, S_IFREG|S_IRUGO|S_IWUSR, 0);
+	if (!ent) return;
+	
+	ent->nlink = 1;
+	ent->read_proc = power_proc_read;
+	ent->write_proc = power_proc_write;
+	ent->owner = THIS_MODULE;
+}
+
+static void __exit power_remove_procfs(void)
+{
+	remove_proc_entry(SYSCTL_FILENAME, NULL);
+}
+
+#else
+#define power_create_procfs()	do { } while (0)
+#define power_remove_procfs()	do { } while (0)
+#endif	/* CONFIG_SYSCTL */
+
+
+
+/* parisc_panic_event() is called by the panic handler.
+ * As soon as a panic occurs, our tasklets above will not be
+ * executed any longer. This function then re-enables the 
+ * soft-power switch and allows the user to switch off the system
+ */
+static int parisc_panic_event(struct notifier_block *this,
+		unsigned long event, void *ptr)
+{
+	/* re-enable the soft-power switch */
+	pdc_soft_power_button(0);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block parisc_panic_block = {
+	notifier_call: parisc_panic_event,
+	priority: INT_MAX,
+};
+
+
+static int __init power_init(void)
+{
+	unsigned long ret;
+	unsigned long soft_power_reg = 0;
+
+#if 0
+	request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,
+		0, "powerfail", NULL);
+#endif
+
+	/* enable the soft power switch if possible */
+	ret = pdc_soft_power_info(&soft_power_reg);
+	if (ret == PDC_OK)
+		ret = pdc_soft_power_button(1);
+	if (ret != PDC_OK)
+		soft_power_reg = -1UL;
+	
+	switch (soft_power_reg) {
+	case 0:		printk(KERN_INFO "Gecko-style soft power switch enabled.\n");
+			power_tasklet.func = gecko_tasklet_func;
+			break;
+			
+	case -1UL:	printk(KERN_INFO "Soft power switch support not available.\n");
+			return -ENODEV;
+	
+	default:	printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n",
+				soft_power_reg);
+			power_tasklet.data = soft_power_reg;
+			power_tasklet.func = polling_tasklet_func;
+	}
+
+	/* Register a call for panic conditions. */
+	notifier_chain_register(&panic_notifier_list, &parisc_panic_block);
+
+	power_create_procfs();
+	tasklet_enable(&power_tasklet);
+
+	return 0;
+}
+
+static void __exit power_exit(void)
+{
+	if (!power_tasklet.func)
+		return;
+
+	tasklet_disable(&power_tasklet);
+	notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block);
+	power_remove_procfs();
+	power_tasklet.func = NULL;
+	pdc_soft_power_button(0);
+}
+
+module_init(power_init);
+module_exit(power_exit);
+
+
+MODULE_AUTHOR("Helge Deller");
+MODULE_DESCRIPTION("Soft power switch driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+
+EXPORT_NO_SYMBOLS;
+
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/process.c linux-2.4.20-pre2/arch/parisc/kernel/process.c
--- linux-2.4.20-pre1/arch/parisc/kernel/process.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/process.c	Mon Aug 12 16:34:14 2002
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/elf.h>
+#include <linux/personality.h>
 
 #include <asm/machdep.h>
 #include <asm/offset.h>
@@ -36,19 +37,12 @@
 #include <asm/gsc.h>
 #include <asm/processor.h>
 
-spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
+int hlt_counter;
 
-#ifdef __LP64__
-/* The 64-bit code should work equally well in 32-bit land but I didn't
- * want to take the time to confirm that.  -PB
- */
-extern unsigned int ret_from_kernel_thread;
-#else
-asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
-#endif
-
-
-int hlt_counter=0;
+/*
+ * Power off function, if any
+ */ 
+void (*pm_power_off)(void);
 
 void disable_hlt(void)
 {
@@ -81,35 +75,86 @@
 	}
 }
 
-void __init reboot_setup(char *str, int *ints)
-{
-}
 
-struct notifier_block *mach_notifier;
+#ifdef __LP64__
+#define COMMAND_GLOBAL  0xfffffffffffe0030UL
+#else
+#define COMMAND_GLOBAL  0xfffe0030
+#endif
+
+#define CMD_RESET       5       /* reset any module */
 
-void machine_restart(char *ptr)
+/*
+** The Wright Brothers and Gecko systems have a H/W problem
+** (Lasi...'nuf said) may cause a broadcast reset to lockup
+** the system. An HVERSION dependent PDC call was developed
+** to perform a "safe", platform specific broadcast reset instead
+** of kludging up all the code.
+**
+** Older machines which do not implement PDC_BROADCAST_RESET will
+** return (with an error) and the regular broadcast reset can be
+** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
+** the PDC call will not return (the system will be reset).
+*/
+void machine_restart(char *cmd)
 {
-	notifier_call_chain(&mach_notifier, MACH_RESTART, ptr);
+#ifdef FASTBOOT_SELFTEST_SUPPORT
+	/*
+	 ** If user has modified the Firmware Selftest Bitmap,
+	 ** run the tests specified in the bitmap after the
+	 ** system is rebooted w/PDC_DO_RESET.
+	 **
+	 ** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
+	 **
+	 ** Using "directed resets" at each processor with the MEM_TOC
+	 ** vector cleared will also avoid running destructive
+	 ** memory self tests. (Not implemented yet)
+	 */
+	if (ftc_bitmap) {
+		pdc_do_firm_test_reset(ftc_bitmap);
+	}
+#endif
+
+	/* "Normal" system reset */
+	pdc_do_reset();
+
+	/* Nope...box should reset with just CMD_RESET now */
+	gsc_writel(CMD_RESET, COMMAND_GLOBAL);
+
+	/* Wait for RESET to lay us to rest. */
+	while (1) ;
+
 }
 
 void machine_halt(void)
 {
-	notifier_call_chain(&mach_notifier, MACH_HALT, NULL);
+	/*
+	** The LED/ChassisCodes are updated by the led_halt()
+	** function, called by the reboot notifier chain.
+	*/
 }
 
-void machine_power_on(void)
-{
-	notifier_call_chain(&mach_notifier, MACH_POWER_ON, NULL);
-}
 
+/*
+ * This routine is called from sys_reboot to actually turn off the
+ * machine 
+ */
 void machine_power_off(void)
 {
-	notifier_call_chain(&mach_notifier, MACH_POWER_OFF, NULL);
-}
+	/* If there is a registered power off handler, call it. */
+	if(pm_power_off)
+		pm_power_off();
+
+	/* Put the soft power button back under hardware control.
+	 * If the user had already pressed the power button, the
+	 * following call will immediately power off. */
+	pdc_soft_power_button(0);
 
+	/* It seems we have no way to power the system off via
+	 * software. The user has to press the button himself. */
 
-void machine_heartbeat(void)
-{
+	printk(KERN_EMERG "System shut down completed.\n"
+	       KERN_EMERG "Please power this system off now.");
 }
 
 
@@ -138,6 +183,9 @@
 
 void flush_thread(void)
 {
+	/* Only needs to handle fpu stuff or perf monitors.
+	** REVISIT: several arches implement a "lazy fpu state".
+	*/
 	set_fs(USER_DS);
 }
 
@@ -148,6 +196,7 @@
 /*
  * Fill in the FPU structure for a core dump.
  */
+
 int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r)
 {
 	memcpy(r, regs->fr, sizeof *r);
@@ -176,7 +225,13 @@
 	    struct task_struct * p, struct pt_regs * pregs)
 {
 	struct pt_regs * cregs = &(p->thread.regs);
-	long ksp;
+	
+	/* We have to use void * instead of a function pointer, because
+	 * function pointers aren't a pointer to the function on 64-bit.
+	 * Make them const so the compiler knows they live in .text */
+	extern void * const ret_from_kernel_thread;
+	extern void * const child_return;
+	extern void * const hpux_child_return;
 
 	*cregs = *pregs;
 
@@ -193,34 +248,37 @@
 	 * in zero for usp.
 	 */
 	if (usp == 0) {
-		/* Kernel Thread */
-		ksp = (((unsigned long)(p)) + TASK_SZ_ALGN);
-		cregs->ksp = ksp;	    /* always return to kernel */
-#ifdef __LP64__
+		/* kernel thread */
+		cregs->ksp = (((unsigned long)(p)) + TASK_SZ_ALGN);
+		/* Must exit via ret_from_kernel_thread in order
+		 * to call schedule_tail()
+		 */
 		cregs->kpc = (unsigned long) &ret_from_kernel_thread;
-#else
-		cregs->kpc = (unsigned long) ret_from_kernel_thread;
-#endif
-
 		/*
 		 * Copy function and argument to be called from
 		 * ret_from_kernel_thread.
 		 */
+#ifdef __LP64__
+		cregs->gr[27] = pregs->gr[27];
+#endif
 		cregs->gr[26] = pregs->gr[26];
 		cregs->gr[25] = pregs->gr[25];
-
 	} else {
-		/* User Thread:
-		 *
-		 * Use same stack depth as parent when in wrapper
-		 *
+		/* user thread */
+		/*
 		 * Note that the fork wrappers are responsible
-		 * for setting gr[20] and gr[21].
+		 * for setting gr[21].
 		 */
 
+		/* Use same stack depth as parent */
 		cregs->ksp = ((unsigned long)(p))
-			+ (pregs->gr[20] & (INIT_TASK_SIZE - 1));
-		cregs->kpc = pregs->gr[21];
+			+ (pregs->gr[21] & (INIT_TASK_SIZE - 1));
+		cregs->gr[30] = usp;
+		if (p->personality == PER_HPUX) {
+			cregs->kpc = (unsigned long) &hpux_child_return;
+		} else {
+			cregs->kpc = (unsigned long) &child_return;
+		}
 	}
 
 	return 0;
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/processor.c linux-2.4.20-pre2/arch/parisc/kernel/processor.c
--- linux-2.4.20-pre1/arch/parisc/kernel/processor.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/processor.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,374 @@
+/*    $Id: processor.c,v 1.13 2002/07/04 19:33:01 grundler Exp $
+ *
+ *    Initial setup-routines for HP 9000 based hardware.
+ *
+ *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *    Modifications for PA-RISC (C) 1999 Helge Deller <deller@gmx.de>
+ *    Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
+ *    Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
+ *    Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ *    Modifications copyright 2001 Ryan Bradetich <rbradetich@uswest.net>
+ *
+ *    Initial PA-RISC Version: 04-23-1999 by Helge Deller
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#define PCI_DEBUG
+#include <linux/pci.h>
+#undef PCI_DEBUG
+
+#include <asm/cache.h>
+#include <asm/hardware.h>	/* for register_parisc_driver() stuff */
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/irq.h>		/* for struct irq_region */
+
+struct system_cpuinfo_parisc boot_cpu_data;
+struct cpuinfo_parisc cpu_data[NR_CPUS];
+
+/*
+**  	PARISC CPU driver - claim "device" and initialize CPU data structures.
+**
+** Consolidate per CPU initialization into (mostly) one module.
+** Monarch CPU will initialize boot_cpu_data which shouldn't
+** change once the system has booted.
+**
+** The callback *should* do per-instance initialization of
+** everything including the monarch. "Per CPU" init code in
+** setup.c:start_parisc() has migrated here and start_parisc()
+** will call register_parisc_driver(&cpu_driver) before calling do_inventory().
+**
+** The goal of consolidating CPU initialization into one place is
+** to make sure all CPU's get initialized the same way.
+** The code path not shared is how PDC hands control of the CPU to the OS.
+** The initialization of OS data structures is the same (done below).
+*/
+
+/**
+ * processor_probe - Determine if processor driver should claim this device.
+ * @dev: The device which has been found.
+ *
+ * Determine if processor driver should claim this chip (return 0) or not 
+ * (return 1).  If so, initialize the chip and tell other partners in crime 
+ * they have work to do.
+ */
+static int __init processor_probe(struct parisc_device *dev)
+{
+	unsigned long txn_addr;
+	unsigned long cpuid;
+	struct cpuinfo_parisc *p;
+
+#ifndef CONFIG_SMP
+	if (boot_cpu_data.cpu_count > 0) {
+		printk(KERN_INFO "CONFIG_SMP=n  ignoring additional CPUs\n");
+		return 1;
+	}
+#endif
+
+	/* logical CPU ID and update global counter
+	 * May get overwritten by PAT code.
+	 */
+	cpuid = boot_cpu_data.cpu_count;
+	txn_addr = dev->hpa;	/* for legacy PDC */
+
+#ifdef __LP64__
+	if (is_pdc_pat()) {
+		ulong status;
+		unsigned long bytecnt;
+	        pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+#undef USE_PAT_CPUID
+#ifdef USE_PAT_CPUID
+		struct pdc_pat_cpu_num cpu_info;
+#endif
+
+		status = pdc_pat_cell_module(&bytecnt, dev->pcell_loc,
+			dev->mod_index, PA_VIEW, &pa_pdc_cell);
+
+		ASSERT(PDC_OK == status);
+
+		/* verify it's the same as what do_pat_inventory() found */
+		ASSERT(dev->mod_info == pa_pdc_cell.mod_info);
+		ASSERT(dev->pmod_loc == pa_pdc_cell.mod_location);
+
+		txn_addr = pa_pdc_cell.mod[0];   /* id_eid for IO sapic */
+
+#ifdef USE_PAT_CPUID
+/* We need contiguous numbers for cpuid. Firmware's notion
+ * of cpuid is for physical CPUs and we just don't care yet.
+ * We'll care when we need to query PAT PDC about a CPU *after*
+ * boot time (ie shutdown a CPU from an OS perspective).
+ */
+		/* get the cpu number */
+		status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa);
+
+		ASSERT(PDC_OK == status);
+
+		if (cpu_info.cpu_num >= NR_CPUS) {
+			printk(KERN_WARNING "IGNORING CPU at 0x%x,"
+				" cpu_slot_id > NR_CPUS"
+				" (%ld > %d)\n",
+				dev->hpa, cpu_info.cpu_num, NR_CPUS);
+			/* Ignore CPU since it will only crash */
+			boot_cpu_data.cpu_count--;
+			return 1;
+		} else {
+			cpuid = cpu_info.cpu_num;
+		}
+#endif
+	}
+#endif
+
+	p = &cpu_data[cpuid];
+	boot_cpu_data.cpu_count++;
+
+	/* initialize counters */
+	memset(p, 0, sizeof(struct cpuinfo_parisc));
+
+	p->dev = dev;		/* Save IODC data in case we need it */
+	p->hpa = dev->hpa;	/* save CPU hpa */
+	p->cpuid = cpuid;	/* save CPU id */
+	p->txn_addr = txn_addr;	/* save CPU IRQ address */
+#ifdef CONFIG_SMP
+	p->lock = SPIN_LOCK_UNLOCKED;
+
+	/*
+	** FIXME: review if any other initialization is clobbered
+	**	for boot_cpu by the above memset().
+	*/
+
+	/* stolen from init_percpu_prof() */
+	cpu_data[cpuid].prof_counter = 1;
+	cpu_data[cpuid].prof_multiplier = 1;
+#endif
+
+	/*
+	** CONFIG_SMP: init_smp_config() will attempt to get CPU's into
+	** OS control. RENDEZVOUS is the default state - see mem_set above.
+	**	p->state = STATE_RENDEZVOUS;
+	*/
+
+	/*
+	** itimer and ipi IRQ handlers are statically initialized in
+	** arch/parisc/kernel/irq.c. ie Don't need to register them.
+	*/
+	p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+
+	return 0;
+}
+
+/**
+ * collect_boot_cpu_data - Fill the boot_cpu_data structure.
+ *
+ * This function collects and stores the generic processor information
+ * in the boot_cpu_data structure.
+ */
+void __init collect_boot_cpu_data(void)
+{
+	memset(&boot_cpu_data, 0, sizeof(boot_cpu_data));
+
+	boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
+
+	/* get CPU-Model Information... */
+#define p ((unsigned long *)&boot_cpu_data.pdc.model)
+	if (pdc_model_info(&boot_cpu_data.pdc.model) == PDC_OK)
+		printk(KERN_INFO 
+			"model %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
+#undef p
+
+	if (pdc_model_versions(&boot_cpu_data.pdc.versions, 0) == PDC_OK)
+		printk(KERN_INFO "vers  %08lx\n", 
+			boot_cpu_data.pdc.versions);
+
+	if (pdc_model_cpuid(&boot_cpu_data.pdc.cpuid) == PDC_OK)
+		printk(KERN_INFO "CPUID vers %ld rev %ld (0x%08lx)\n",
+			(boot_cpu_data.pdc.cpuid >> 5) & 127,
+			boot_cpu_data.pdc.cpuid & 31,
+			boot_cpu_data.pdc.cpuid);
+
+	if (pdc_model_capabilities(&boot_cpu_data.pdc.capabilities) == PDC_OK)
+		printk(KERN_INFO "capabilities 0x%lx\n",
+			boot_cpu_data.pdc.capabilities);
+
+	if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name) == PDC_OK)
+		printk(KERN_INFO "model %s\n",
+			boot_cpu_data.pdc.sys_model_name);
+
+	boot_cpu_data.hversion =  boot_cpu_data.pdc.model.hversion;
+	boot_cpu_data.sversion =  boot_cpu_data.pdc.model.sversion;
+
+	boot_cpu_data.cpu_type =
+			parisc_get_cpu_type(boot_cpu_data.hversion);
+
+	boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
+	boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
+}
+
+
+/**
+ * init_cpu_profiler - enable/setup per cpu profiling hooks.
+ * @cpunum: The processor instance.
+ *
+ * FIXME: doesn't do much yet...
+ */
+static inline void __init
+init_percpu_prof(int cpunum)
+{
+	cpu_data[cpunum].prof_counter = 1;
+	cpu_data[cpunum].prof_multiplier = 1;
+}
+
+
+/**
+ * init_per_cpu - Handle individual processor initializations.
+ * @cpunum: logical processor number.
+ *
+ * This function handles initialization for *every* CPU
+ * in the system:
+ *
+ * o Set "default" CPU width for trap handlers
+ *
+ * o Enable FP coprocessor
+ *   REVISIT: this could be done in the "code 22" trap handler.
+ *	(frowands idea - that way we know which processes need FP
+ *	registers saved on the interrupt stack.)
+ *   NEWS FLASH: wide kernels need FP coprocessor enabled to handle
+ *	formatted printing of %lx for example (double divides I think)
+ *
+ * o Enable CPU profiling hooks.
+ */
+int __init init_per_cpu(int cpunum)
+{
+	int ret;
+	struct pdc_coproc_cfg coproc_cfg;
+
+	ret = pdc_coproc_cfg(&coproc_cfg);
+
+	if(ret >= 0 && coproc_cfg.ccr_functional) {
+		mtctl(coproc_cfg.ccr_functional, 10);  /* 10 == Coprocessor Control Reg */
+
+		/* FWIW, FP rev/model is a more accurate way to determine
+		** CPU type. CPU rev/model has some ambiguous cases.
+		*/
+		cpu_data[cpunum].fp_rev = coproc_cfg.revision;
+		cpu_data[cpunum].fp_model = coproc_cfg.model;
+
+		printk(KERN_INFO  "FP[%d] enabled: Rev %ld Model %ld\n",
+			cpunum, coproc_cfg.revision, coproc_cfg.model);
+
+		/*
+		** store status register to stack (hopefully aligned)
+		** and clear the T-bit.
+		*/
+		asm volatile ("fstd    %fr0,8(%sp)");
+
+	} else {
+		printk(KERN_WARNING  "WARNING: No FP CoProcessor?!"
+			" (coproc_cfg.ccr_functional == 0x%lx, expected 0xc0)\n"
+#ifdef __LP64__
+			"Halting Machine - FP required\n"
+#endif
+			, coproc_cfg.ccr_functional);
+#ifdef __LP64__
+		mdelay(100);	/* previous chars get pushed to console */
+		panic("FP CoProc not reported");
+#endif
+	}
+
+	/* FUTURE: Enable Performance Monitor : ccr bit 0x20 */
+	init_percpu_prof(cpunum);
+
+	return ret;
+}
+
+/*
+ * Display cpu info for all cpu's.
+ */
+int
+show_cpuinfo (struct seq_file *m, void *v)
+{
+	int	n;
+
+	for(n=0; n<boot_cpu_data.cpu_count; n++) {
+#ifdef CONFIG_SMP
+		if (0 == cpu_data[n].hpa)
+			continue;
+#ifdef ENTRY_SYS_CPUS
+#error iCOD support wants to show CPU state here
+#endif
+#endif
+		seq_printf(m, "processor\t: %d\n"
+				"cpu family\t: PA-RISC %s\n",
+				 n, boot_cpu_data.family_name);
+
+		seq_printf(m, "cpu\t\t: %s\n",  boot_cpu_data.cpu_name );
+
+		/* cpu MHz */
+		seq_printf(m, "cpu MHz\t\t: %d.%06d\n",
+				 boot_cpu_data.cpu_hz / 1000000,
+				 boot_cpu_data.cpu_hz % 1000000  );
+
+		seq_printf(m, "model\t\t: %s\n"
+				"model name\t: %s\n",
+				 boot_cpu_data.pdc.sys_model_name,
+				 cpu_data[n].dev ? 
+				 cpu_data[n].dev->name : "Unknown" );
+
+		seq_printf(m, "hversion\t: 0x%08x\n"
+			        "sversion\t: 0x%08x\n",
+				 boot_cpu_data.hversion,
+				 boot_cpu_data.sversion );
+
+		/* print cachesize info */
+		show_cache_info(m);
+
+		seq_printf(m, "bogomips\t: %lu.%02lu\n",
+			     loops_per_jiffy / (500000 / HZ),
+			     (loops_per_jiffy / (5000 / HZ)) % 100);
+
+		seq_printf(m, "software id\t: %ld\n\n",
+				boot_cpu_data.pdc.model.sw_id);
+	}
+	return 0;
+}
+
+static struct parisc_device_id processor_tbl[] = {
+	{ HPHW_NPROC, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, SVERSION_ANY_ID },
+	{ 0, }
+};
+
+static struct parisc_driver cpu_driver = {
+	name:		"CPU",
+	id_table:	processor_tbl,
+	probe:		processor_probe
+};
+
+/**
+ * processor_init - Processor initalization procedure.
+ *
+ * Register this driver.
+ */
+void __init processor_init(void)
+{
+	register_parisc_driver(&cpu_driver);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/ptrace.c linux-2.4.20-pre2/arch/parisc/kernel/ptrace.c
--- linux-2.4.20-pre1/arch/parisc/kernel/ptrace.c	Tue Sep 18 16:56:19 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/ptrace.c	Mon Aug 12 16:34:14 2002
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/personality.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -31,6 +32,47 @@
 #define PT_SINGLESTEP	0x10000
 #define PT_BLOCKSTEP	0x20000
 
+/* PSW bits we allow the debugger to modify */
+#define USER_PSW_BITS	(PSW_N | PSW_V | PSW_CB)
+
+#undef DEBUG_PTRACE
+
+#ifdef DEBUG_PTRACE
+#define DBG(x)	printk x
+#else
+#define DBG(x)
+#endif
+
+#ifdef __LP64__
+
+#define CHILD_IS_32BIT	(child->personality == PER_LINUX_32BIT)
+
+/* This function is needed to translate 32 bit pt_regs offsets in to
+ * 64 bit pt_regs offsets.  For example, a 32 bit gdb under a 64 bit kernel
+ * will request offset 12 if it wants gr3, but the lower 32 bits of
+ * the 64 bit kernels view of gr3 will be at offset 28 (3*8 + 4).
+ * This code relies on a 32 bit pt_regs being comprised of 32 bit values
+ * except for the fp registers which (a) are 64 bits, and (b) follow
+ * the gr registers at the start of pt_regs.  The 32 bit pt_regs should
+ * be half the size of the 64 bit pt_regs, plus 32*4 to allow for fr[]
+ * being 64 bit in both cases.
+ */
+
+static long translate_usr_offset(long offset)
+{
+	if (offset < 0)
+		return -1;
+	else if (offset <= 32*4)	/* gr[0..31] */
+		return offset * 2 + 4;
+	else if (offset <= 32*4+32*8)	/* gr[0..31] + fr[0..31] */
+		return offset + 32*4;
+	else if (offset < sizeof(struct pt_regs)/2 + 32*4)
+		return offset * 2 + 4 - 32*8;
+	else
+		return -1;
+}
+#endif
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -49,6 +91,9 @@
 {
 	struct task_struct *child;
 	long ret;
+#ifdef DEBUG_PTRACE
+	long oaddr=addr, odata=data;
+#endif
 
 	lock_kernel();
 	ret = -EPERM;
@@ -91,14 +136,33 @@
 	switch (request) {
 	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))
-			goto out_tsk;
-		ret = put_user(tmp,(unsigned long *) data);
+#ifdef __LP64__
+		if (CHILD_IS_32BIT) {
+			unsigned int tmp;
+
+			addr &= 0xffffffffL;
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			ret = -EIO;
+			if (copied != sizeof(tmp))
+				goto out_tsk;
+			ret = put_user(tmp,(unsigned int *) data);
+			DBG(("sys_ptrace(PEEK%s, %d, %lx, %lx) returning %ld, data %x\n",
+				request == PTRACE_PEEKTEXT ? "TEXT" : "DATA",
+				pid, oaddr, odata, ret, tmp));
+		}
+		else
+#endif
+		{
+			unsigned long tmp;
+
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			ret = -EIO;
+			if (copied != sizeof(tmp))
+				goto out_tsk;
+			ret = put_user(tmp,(unsigned long *) data);
+		}
 		goto out_tsk;
 	}
 
@@ -106,22 +170,53 @@
 	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))
-			goto out_tsk;
+#ifdef __LP64__
+		if (CHILD_IS_32BIT) {
+			unsigned int tmp = (unsigned int)data;
+			DBG(("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
+				request == PTRACE_POKETEXT ? "TEXT" : "DATA",
+				pid, oaddr, odata));
+			addr &= 0xffffffffL;
+			if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) == sizeof(tmp))
+				goto out_tsk;
+		}
+		else
+#endif
+		{
+			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+				goto out_tsk;
+		}
 		ret = -EIO;
 		goto out_tsk;
 
-	/* Read the word at location addr in the USER area.  This will need
-	   to change when the kernel no longer saves all regs on a syscall. */
+	/* Read the word at location addr in the USER area.  For ptraced
+	   processes, the kernel saves all regs on a syscall. */
 	case PTRACE_PEEKUSR: {
-		unsigned long tmp;
-
 		ret = -EIO;
-		if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
-			goto out_tsk;
-
-		tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
-		ret = put_user(tmp, (unsigned long *) data);
+#ifdef __LP64__
+		if (CHILD_IS_32BIT) {
+			unsigned int tmp;
+
+			if (addr & (sizeof(int)-1))
+				goto out_tsk;
+			if ((addr = translate_usr_offset(addr)) < 0)
+				goto out_tsk;
+
+			tmp = *(unsigned int *) ((char *) task_regs(child) + addr);
+			ret = put_user(tmp, (unsigned int *) data);
+			DBG(("sys_ptrace(PEEKUSR, %d, %lx, %lx) returning %ld, addr %lx, data %x\n",
+				pid, oaddr, odata, ret, addr, tmp));
+		}
+		else
+#endif
+		{
+			unsigned long tmp;
+
+			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
+				goto out_tsk;
+			tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
+			ret = put_user(tmp, (unsigned long *) data);
+		}
 		goto out_tsk;
 	}
 
@@ -133,25 +228,73 @@
 	   exit. */
 	case PTRACE_POKEUSR:
 		ret = -EIO;
-		if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
-			goto out_tsk;
-		/* XXX This test probably needs adjusting.  We probably want to
-		 * allow writes to some bits of PSW, and may want to block writes
-		 * to (some) space registers.  Some register values written here
-		 * may be ignored in entry.S:syscall_restore_rfi; e.g. iaoq is
-		 * written with r31/r31+4, and not with the values in pt_regs.
+		/* Some register values written here may be ignored in
+		 * entry.S:syscall_restore_rfi; e.g. iaoq is written with
+		 * r31/r31+4, and not with the values in pt_regs.
+		 */
+		 /* PT_PSW=0, so this is valid for 32 bit processes under 64
+		 * bit kernels.
 		 */
-		/* Allow writing of gr1-gr31, fr*, sr*, iasq*, iaoq*, sar */
-		if (addr == PT_PSW || (addr > PT_IAOQ1 && addr != PT_SAR))
+		if (addr == PT_PSW) {
+			/* PT_PSW=0, so this is valid for 32 bit processes
+			 * under 64 bit kernels.
+			 *
+			 * Allow writing to Nullify, Divide-step-correction,
+			 * and carry/borrow bits.
+			 * BEWARE, if you set N, and then single step, it wont
+			 * stop on the nullified instruction.
+			 */
+			DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx)\n",
+				pid, oaddr, odata));
+			data &= USER_PSW_BITS;
+			task_regs(child)->gr[0] &= ~USER_PSW_BITS;
+			task_regs(child)->gr[0] |= data;
+			ret = 0;
 			goto out_tsk;
-
-		*(unsigned long *) ((char *) task_regs(child) + addr) = data;
-		ret = 0;
-		goto out_tsk;
+		}
+#ifdef __LP64__
+		if (CHILD_IS_32BIT) {
+			if (addr & (sizeof(int)-1))
+				goto out_tsk;
+			if ((addr = translate_usr_offset(addr)) < 0)
+				goto out_tsk;
+			DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx) addr %lx\n",
+				pid, oaddr, odata, addr));
+			if (addr >= PT_FR0 && addr <= PT_FR31) {
+				/* Special case, fp regs are 64 bits anyway */
+				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
+				ret = 0;
+			}
+			else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
+					addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
+					addr == PT_SAR+4) {
+				/* Zero the top 32 bits */
+				*(unsigned int *) ((char *) task_regs(child) + addr - 4) = 0;
+				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
+				ret = 0;
+			}
+			goto out_tsk;
+		}
+		else
+#endif
+		{
+			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
+				goto out_tsk;
+			if ((addr >= PT_GR1 && addr <= PT_GR31) ||
+					addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
+					(addr >= PT_FR0 && addr <= PT_FR31) ||
+					addr == PT_SAR) {
+				*(unsigned long *) ((char *) task_regs(child) + addr) = data;
+				ret = 0;
+			}
+			goto out_tsk;
+		}
 
 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 	case PTRACE_CONT:
 		ret = -EIO;
+		DBG(("sys_ptrace(%s)\n",
+			request == PTRACE_SYSCALL ? "SYSCALL" : "CONT"));
 		if ((unsigned long) data > _NSIG)
 			goto out_tsk;
 		child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
@@ -168,12 +311,14 @@
 		 * sigkill.  perhaps it should be put in the status
 		 * that it wants to exit.
 		 */
+		DBG(("sys_ptrace(KILL)\n"));
 		if (child->state == TASK_ZOMBIE)	/* already dead */
 			goto out_tsk;
 		child->exit_code = SIGKILL;
 		goto out_wake_notrap;
 
 	case PTRACE_SINGLEBLOCK:
+		DBG(("sys_ptrace(SINGLEBLOCK)\n"));
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			goto out_tsk;
@@ -189,6 +334,7 @@
 		goto out_wake;
 
 	case PTRACE_SINGLESTEP:
+		DBG(("sys_ptrace(SINGLESTEP)\n"));
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			goto out_tsk;
@@ -208,10 +354,7 @@
 			pa_psw(child)->y = 0;
 			pa_psw(child)->z = 0;
 			pa_psw(child)->b = 0;
-			pa_psw(child)->r = 0;
-			pa_psw(child)->t = 0;
-			pa_psw(child)->h = 0;
-			pa_psw(child)->l = 0;
+			ptrace_disable(child);
 			/* Don't wake up the child, but let the
 			   parent know something happened. */
 			si.si_code = TRAP_TRACE;
@@ -249,11 +392,7 @@
 	}
 
 out_wake_notrap:
-	/* make sure the trap bits are not set */
-	pa_psw(child)->r = 0;
-	pa_psw(child)->t = 0;
-	pa_psw(child)->h = 0;
-	pa_psw(child)->l = 0;
+	ptrace_disable(child);
 out_wake:
 	wake_up_process(child);
 	ret = 0;
@@ -261,6 +400,8 @@
 	free_task_struct(child);
 out:
 	unlock_kernel();
+	DBG(("sys_ptrace(%ld, %d, %lx, %lx) returning %ld\n",
+		request, pid, oaddr, odata, ret));
 	return ret;
 }
 
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/real1.c linux-2.4.20-pre2/arch/parisc/kernel/real1.c
--- linux-2.4.20-pre1/arch/parisc/kernel/real1.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/real1.c	Wed Dec 31 16:00:00 1969
@@ -1,154 +0,0 @@
-/*
- *
- * 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) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com)
- *
- * most of these calls might reasonably be moved to ../kernel -PB
- *
- * The basic principle is to construct a stack frame in C then call
- * some assembly which adopts that stack, does some rfi magic, may
- * switch wide/narrow mode, and calls the routine described by the
- * 'fn' parameter WHICH IS NOT A FUNCTION POINTER!!!!!!!!!!!!!!!!
- */
-#include <linux/spinlock.h>
-#include <asm/system.h>
-#include <stdarg.h>
-#include <asm/pgtable.h>		/* for __pa() */
-#include <asm/pdc.h>
-
-static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED;
-
-/***************** 32-bit real-mode calls ***********/
-/* The struct below is used
- * to overlay real_stack (real2.S), preparing a 32-bit call frame.
- * real32_call_asm() then uses this stack in narrow real mode
- */
-
-struct narrow_stack {
-    /* use int, not long which is 64 bits */
-    unsigned int arg13;
-    unsigned int arg12;
-    unsigned int arg11;
-    unsigned int arg10;
-    unsigned int arg9;
-    unsigned int arg8;
-    unsigned int arg7;
-    unsigned int arg6;
-    unsigned int arg5;
-    unsigned int arg4;
-    unsigned int arg3;
-    unsigned int arg2;
-    unsigned int arg1;
-    unsigned int arg0;
-    unsigned int frame_marker[8];
-    unsigned int sp;
-    /* in reality, there's nearly 8k of stack after this */
-};
-
-long
-real32_call(unsigned long fn, ...)
-{
-    unsigned long r;
-    va_list args;
-    unsigned long flags;
-    extern struct narrow_stack real_stack;
-    extern unsigned long real32_call_asm(unsigned int *,
-				unsigned int *, unsigned int);
-    
-    va_start(args, fn);
-    real_stack.arg0 = va_arg(args, unsigned int);
-    real_stack.arg1 = va_arg(args, unsigned int);
-    real_stack.arg2 = va_arg(args, unsigned int);
-    real_stack.arg3 = va_arg(args, unsigned int);
-    real_stack.arg4 = va_arg(args, unsigned int);
-    real_stack.arg5 = va_arg(args, unsigned int);
-    real_stack.arg6 = va_arg(args, unsigned int);
-    real_stack.arg7 = va_arg(args, unsigned int);
-    real_stack.arg8 = va_arg(args, unsigned int);
-    real_stack.arg9 = va_arg(args, unsigned int);
-    real_stack.arg10 = va_arg(args, unsigned int);
-    real_stack.arg11 = va_arg(args, unsigned int);
-    real_stack.arg12 = va_arg(args, unsigned int);
-    real_stack.arg13 = va_arg(args, unsigned int);
-    va_end(args);
-
-    if (fn == 0) {
-	    /* mem_pdc call */
-	    fn = PAGE0->mem_pdc;
-    }
-
-    spin_lock_irqsave(&pdc_lock, flags);
-    r = real32_call_asm(&real_stack.sp, &real_stack.arg0, fn);
-    spin_unlock_irqrestore(&pdc_lock, flags);
-
-    return r;
-}
-
-#ifdef __LP64__
-/***************** 64-bit real-mode calls ***********/
-
-struct wide_stack {
-    unsigned long arg0;
-    unsigned long arg1;
-    unsigned long arg2;
-    unsigned long arg3;
-    unsigned long arg4;
-    unsigned long arg5;
-    unsigned long arg6;
-    unsigned long arg7;
-    unsigned long arg8;
-    unsigned long arg9;
-    unsigned long arg10;
-    unsigned long arg11;
-    unsigned long arg12;
-    unsigned long arg13;
-    unsigned long frame_marker[2];	/* rp, previous sp */
-    unsigned long sp;
-    /* in reality, there's nearly 8k of stack after this */
-};
-
-long
-real64_call(unsigned long fn, ...)
-{
-    unsigned long r;
-    va_list args;
-    unsigned long flags;
-    extern struct wide_stack real_stack;
-    extern unsigned long real64_call_asm(unsigned long *,
-				unsigned long *, unsigned long);
-    
-    va_start(args, fn);
-    real_stack.arg0 = va_arg(args, unsigned long);
-    real_stack.arg1 = va_arg(args, unsigned long);
-    real_stack.arg2 = va_arg(args, unsigned long);
-    real_stack.arg3 = va_arg(args, unsigned long);
-    real_stack.arg4 = va_arg(args, unsigned long);
-    real_stack.arg5 = va_arg(args, unsigned long);
-    real_stack.arg6 = va_arg(args, unsigned long);
-    real_stack.arg7 = va_arg(args, unsigned long);
-    real_stack.arg8 = va_arg(args, unsigned long);
-    real_stack.arg9 = va_arg(args, unsigned long);
-    real_stack.arg10 = va_arg(args, unsigned long);
-    real_stack.arg11 = va_arg(args, unsigned long);
-    real_stack.arg12 = va_arg(args, unsigned long);
-    real_stack.arg13 = va_arg(args, unsigned long);
-    va_end(args);
-
-    if (fn == 0) {
-	    /* mem_pdc call */
-	    fn = PAGE0->mem_pdc_hi;
-	    fn <<= 32;
-	    fn |= PAGE0->mem_pdc;
-    }
-
-    spin_lock_irqsave(&pdc_lock, flags);
-    r = real64_call_asm(&real_stack.sp, &real_stack.arg0, fn);
-    spin_unlock_irqrestore(&pdc_lock, flags);
-
-    return r;
-}
-
-#endif
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/real2.S linux-2.4.20-pre2/arch/parisc/kernel/real2.S
--- linux-2.4.20-pre1/arch/parisc/kernel/real2.S	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/real2.S	Mon Aug 12 16:34:14 2002
@@ -7,7 +7,6 @@
  * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com)
  *
  */
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/psw.h>
 
@@ -31,8 +30,11 @@
 
 /************************ 32-bit real-mode calls ***********************/
 /* This can be called in both narrow and wide kernels */
+
 	.text
+
 	.export real32_call_asm
+
 	/* unsigned long real32_call_asm(unsigned int *sp,
 	 *		unsigned int *arg0p,
 	 *		unsigned int iodc_fn)
@@ -40,6 +42,7 @@
 	 *	arg0p points to where saved arg values may be found
 	 *	iodc_fn is the IODC function to call
 	 */
+
 real32_call_asm:
 	STREG	%rp, -RP_OFFSET(%sp)	/* save RP */
 #ifdef __LP64__
@@ -61,7 +64,7 @@
 	ldw	-12(%arg1), %arg3
 	ldw	-4(%arg1), %arg1	/* obviously must do this one last! */
 
-	tophys	%sp
+	tophys_r1  %sp
 
 	b,l	rfi_virt2real,%r2
 	nop
@@ -88,7 +91,7 @@
 	b,l	rfi_real2virt,%r2
 	nop
 
-	tovirt	%sp
+	tovirt_r1 %sp
 	LDREG	-REG_SZ(%sp), %sp	/* restore SP */
 #ifdef __LP64__
 	LDREG	-1*REG_SZ(%sp), %r27
@@ -150,14 +153,14 @@
 	nop
 	nop
 	
-	mtsm		0		/* disable interruptions */
+	rsm             (PSW_SM_Q|PSW_SM_I),%r0  /* disable Q & I bits to load iia queue */
 	mtctl		0, %cr17	/* space 0 */
 	mtctl		0, %cr17
 	load32		PA(rfi_v2r_1), %r1
 	mtctl		%r1, %cr18
 	ldo		4(%r1), %r1
 	mtctl		%r1, %cr18
-	load32		PDC_PSW, %r1
+	load32          REAL_MODE_PSW, %r1
 	mtctl		%r1, %cr22
 	rfi
 	
@@ -170,7 +173,7 @@
 	nop
 	nop
 rfi_v2r_1:
-	tophys	%r2
+	tophys_r1 %r2
 	bv	0(%r2)
 	nop
 
@@ -187,7 +190,7 @@
 	nop
 	nop
 	
-	mtsm		0		/* disable interruptions */
+	rsm             PSW_SM_Q,%r0    /* disable Q bit to load iia queue */
 	mtctl		0, %cr17	/* space 0 */
 	mtctl		0, %cr17
 	load32		(rfi_r2v_1), %r1
@@ -207,7 +210,7 @@
 	nop
 	nop
 rfi_r2v_1:
-	tovirt	%r2
+	tovirt_r1 %r2
 	bv	0(%r2)
 	nop
 
@@ -246,7 +249,7 @@
 	ldd	7*REG_SZ(%arg1), %r19
 	ldd	1*REG_SZ(%arg1), %arg1		/* do this one last! */
 
-	tophys	%sp
+	tophys_r1 %sp
 
 	b,l	rfi_virt2real,%r2
 	nop
@@ -265,10 +268,18 @@
 	b,l	rfi_real2virt,%r2
 	nop
 
-	tovirt	%sp
+	tovirt_r1 %sp
 	ldd	-8(%sp), %sp		/* restore SP */
 	ldd	-0x10(%sp), %rp		/* restore RP */
 	bv	0(%rp)
 	nop
 
 #endif
+	.export pc_in_user_space
+	.text
+	/* Doesn't belong here but I couldn't find a nicer spot. */
+	/* Should never get called, only used by profile stuff in time.c */
+pc_in_user_space:
+	bv,n	0(%rp)
+	nop
+
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/sba_iommu.c linux-2.4.20-pre2/arch/parisc/kernel/sba_iommu.c
--- linux-2.4.20-pre1/arch/parisc/kernel/sba_iommu.c	Fri Oct 12 15:35:53 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/sba_iommu.c	Mon Aug 12 16:34:14 2002
@@ -15,7 +15,6 @@
 ** This module initializes the IOC (I/O Controller) found on B1000/C3000/
 ** J5000/J7000/N-class/L-class machines and their successors.
 **
-** FIXME: Multi-IOC support missing - depends on hp_device data
 ** FIXME: add DMA hint support programming in both sba and lba modules.
 */
 
@@ -28,7 +27,7 @@
 
 #include <linux/mm.h>
 #include <linux/string.h>
-#define PCI_DEBUG		/* for ASSERT */
+#undef PCI_DEBUG		/* for ASSERT */
 #include <linux/pci.h>
 #undef PCI_DEBUG
 
@@ -36,19 +35,19 @@
 #include <asm/io.h>
 #include <asm/dma.h>		/* for DMA_CHUNK_SIZE */
 
-#include <asm/hardware.h>	/* for register_driver() stuff */
+#include <asm/hardware.h>	/* for register_parisc_driver() stuff */
 #include <asm/gsc.h>		/* FIXME: for gsc_read/gsc_write */
 
 #include <linux/proc_fs.h>
 #include <asm/runway.h>		/* for proc_runway_root */
-
+#include <asm/pdc.h>		/* for PDC_MODEL_* */
 
 #define MODULE_NAME "SBA"
 
 /*
 ** The number of debug flags is a clue - this code is fragile.
 ** Don't even think about messing with it unless you have
-** plenty of 710's to sacrafice to the computer gods. :^)
+** plenty of 710's to sacrifice to the computer gods. :^)
 */
 #undef DEBUG_SBA_INIT
 #undef DEBUG_SBA_RUN
@@ -56,12 +55,9 @@
 #undef DEBUG_SBA_RESOURCE
 #undef ASSERT_PDIR_SANITY
 #undef DEBUG_LARGE_SG_ENTRIES
+#undef DEBUG_DMB_TRAP
 
-#if 1
-#define SBA_INLINE
-#else
 #define SBA_INLINE	__inline__
-#endif
 
 #ifdef DEBUG_SBA_INIT
 #define DBG_INIT(x...)	printk(x)
@@ -95,73 +91,43 @@
 ** allocated and free'd/purged at a time might make this
 ** less interesting).
 */
-#if 0
 #define DELAYED_RESOURCE_CNT	16
-#else
-#undef DELAYED_RESOURCE_CNT
-#endif
 
 #define DEFAULT_DMA_HINT_REG	0
 
-#define ASTRO_RUNWAY_PORT    0x582
-#define ASTRO_ROPES_PORT     0x780
-
-#define IKE_MERCED_PORT      0x803
-#define IKE_ROPES_PORT       0x781
-
-int sba_driver_callback(struct hp_device *, struct pa_iodc_driver *);
+#define ASTRO_RUNWAY_PORT	0x582
+#define ASTRO_ROPES_PORT	0x780
 
-static struct pa_iodc_driver sba_drivers_for[] = {
+#define IKE_MERCED_PORT		0x803
+#define IKE_ROPES_PORT		0x781
 
-/* FIXME: why is SVERSION checked? */
-
-   {HPHW_IOA, ASTRO_RUNWAY_PORT, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
-
-   {HPHW_BCPORT, ASTRO_ROPES_PORT, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
-
-#if 0
-/* FIXME : N-class! Use a different "callback"? */
-   {HPHW_BCPORT, IKE_MERCED_PORT, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
-
-   {HPHW_BCPORT, IKE_ROPES_PORT, 0x0, 0xb, 0, 0x10,
-		DRIVER_CHECK_HVERSION +
-		DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE,
-                MODULE_NAME, "I/O MMU", (void *) sba_driver_callback},
-#endif
-
-   {0,0,0,0,0,0,
-   0,
-   (char *) NULL, (char *) NULL, (void *) NULL }
-};
+#define REO_MERCED_PORT		0x804
+#define REO_ROPES_PORT		0x782
 
+#define REOG_MERCED_PORT	0x805
+#define REOG_ROPES_PORT		0x783
 
 #define SBA_FUNC_ID	0x0000	/* function id */
 #define SBA_FCLASS	0x0008	/* function class, bist, header, rev... */
 
-#define IS_ASTRO(id) ( \
-    (((id)->hw_type == HPHW_IOA) && ((id)->hversion == ASTRO_RUNWAY_PORT)) || \
-    (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == ASTRO_ROPES_PORT))  \
-)
+#define IS_ASTRO(id) \
+(((id)->hversion == ASTRO_RUNWAY_PORT) || ((id)->hversion == ASTRO_ROPES_PORT))
+
+#define IS_IKE(id) \
+(((id)->hversion == IKE_MERCED_PORT) || ((id)->hversion == IKE_ROPES_PORT))
 
-#define CONFIG_FUNC_SIZE 4096   /* SBA configuration function reg set */
+#define SBA_FUNC_SIZE 4096   /* SBA configuration function reg set */
 
 #define ASTRO_IOC_OFFSET 0x20000
 /* Ike's IOC's occupy functions 2 and 3 (not 0 and 1) */
-#define IKE_IOC_OFFSET(p) ((p+2)*CONFIG_FUNC_SIZE)
+#define IKE_IOC_OFFSET(p) ((p+2)*SBA_FUNC_SIZE)
 
 #define IOC_CTRL          0x8	/* IOC_CTRL offset */
-#define IOC_CTRL_TE       (0x1 << 0) /* TOC Enable */
-#define IOC_CTRL_RM       (0x1 << 8) /* Real Mode */
-#define IOC_CTRL_NC       (0x1 << 9) /* Non Coherent Mode */
+#define IOC_CTRL_TC       (1 << 0) /* TOC Enable */
+#define IOC_CTRL_CE       (1 << 1) /* Coalesce Enable */
+#define IOC_CTRL_DE       (1 << 2) /* Dillon Enable */
+#define IOC_CTRL_RM       (1 << 8) /* Real Mode */
+#define IOC_CTRL_NC       (1 << 9) /* Non Coherent Mode */
 
 #define MAX_IOC		2	/* per Ike. Astro only has 1 */
 
@@ -233,18 +199,22 @@
 
 
 struct ioc {
-	char    *ioc_hpa;	/* I/O MMU base address */
+	unsigned long	ioc_hpa;	/* I/O MMU base address */
 	char	*res_map;	/* resource map, bit == pdir entry */
 	u64	*pdir_base;	/* physical base address */
 
-	unsigned long	*res_hint;	/* next available IOVP - circular search */
+	unsigned long	*res_hint;	/* next avail IOVP - circular search */
+	spinlock_t	res_lock;
+	unsigned long	hint_mask_pdir;	/* bits used for DMA hints */
 	unsigned int	res_bitshift;	/* from the LEFT! */
 	unsigned int	res_size;	/* size of resource map in bytes */
 	unsigned int	hint_shift_pdir;
-	spinlock_t	res_lock;
-	unsigned long	hint_mask_pdir;		/* bits used for DMA hints */
-#ifdef DELAYED_RESOURCE_CNT
-	dma_addr_t res_delay[DELAYED_RESOURCE_CNT];
+#if DELAYED_RESOURCE_CNT > 0
+	int saved_cnt;
+	struct sba_dma_pair {
+		dma_addr_t	iova;
+		size_t		size;
+	} saved[DELAYED_RESOURCE_CNT];
 #endif
 
 #ifdef CONFIG_PROC_FS
@@ -269,23 +239,32 @@
 };
 
 struct sba_device {
-	struct sba_device	*next;	/* list of LBA's in system */
-	struct hp_device	*iodc;	/* data about dev from firmware */
-	char			*sba_hpa; /* base address */
+	struct sba_device	*next;	/* list of SBA's in system */
+	struct parisc_device	*dev;	/* dev found in bus walk */
+	struct parisc_device_id	*iodc;	/* data about dev from firmware */
+	const char 		*name;
+	unsigned long		sba_hpa; /* base address */
 	spinlock_t		sba_lock;
-	unsigned int			flags;  /* state/functionality enabled */
-	unsigned int			hw_rev;  /* HW revision of chip */
+	unsigned int		flags;  /* state/functionality enabled */
+	unsigned int		hw_rev;  /* HW revision of chip */
 
-	unsigned int			num_ioc;  /* number of on-board IOC's */
+	unsigned int		num_ioc;  /* number of on-board IOC's */
 	struct ioc		ioc[MAX_IOC];
 };
 
 
 static struct sba_device *sba_list;
-static int sba_count;
+
+static unsigned long ioc_needs_fdc = 0;
 
 /* Ratio of Host MEM to IOV Space size */
-static unsigned long sba_mem_ratio = 4;
+static unsigned long sba_mem_ratio = 8;
+
+/* global count of IOMMUs in the system */
+static unsigned int global_ioc_cnt = 0;
+
+/* PA8700 (Piranha 2.2) bug workaround */
+static unsigned long piranha_bad_128k = 0;
 
 /* Looks nice and keeps the compiler happy */
 #define SBA_DEV(d) ((struct sba_device *) (d))
@@ -299,73 +278,75 @@
 **
 ** BE WARNED: register writes are posted.
 **  (ie follow writes which must reach HW with a read)
+**
+** Superdome (in particular, REO) allows only 64-bit CSR accesses.
 */
-#define READ_U8(addr)  gsc_readb(addr)
-#define READ_U16(addr) gsc_readw((u16 *) (addr))
-#define READ_U32(addr) gsc_readl((u32 *) (addr))
-#define WRITE_U8(value, addr) gsc_writeb(value, addr)
-#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr))
-#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr))
-
-#define READ_REG8(addr)  gsc_readb(addr)
-#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr)))
-#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr)))
-#define READ_REG64(addr) le64_to_cpu(gsc_readq((u64 *) (addr)))
-#define WRITE_REG8(value, addr) gsc_writeb(value, addr)
-#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr))
-#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr))
-#define WRITE_REG64(value, addr) gsc_writeq(cpu_to_le64(value), (u64 *) (addr))
+#define READ_REG32(addr)	 le32_to_cpu(__raw_readl(addr))
+#define READ_REG64(addr)	 le64_to_cpu(__raw_readq(addr))
+#define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr)
+#define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr)
+
+#ifdef __LP64__
+#define READ_REG(addr)		READ_REG64(addr)
+#define WRITE_REG(value, addr)	WRITE_REG64(value, addr)
+#else
+#define READ_REG(addr)		READ_REG32(addr)
+#define WRITE_REG(value, addr)	WRITE_REG32(value, addr)
+#endif
 
 #ifdef DEBUG_SBA_INIT
 
+/* NOTE: When __LP64__ isn't defined, READ_REG64() is two 32-bit reads */
+
+/**
+ * sba_dump_ranges - debugging only - print ranges assigned to this IOA
+ * @hpa: base address of the sba
+ *
+ * Print the MMIO and IO Port address ranges forwarded by an Astro/Ike/RIO
+ * IO Adapter (aka Bus Converter).
+ */
 static void
-sba_dump_ranges(char *hpa)
+sba_dump_ranges(unsigned long hpa)
 {
-	printk("SBA at 0x%p\n", hpa);
-	printk("IOS_DIST_BASE   : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIST_BASE+4),
-			READ_REG32(hpa+IOS_DIST_BASE));
-	printk("IOS_DIST_MASK   : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIST_MASK+4),
-			READ_REG32(hpa+IOS_DIST_MASK));
-	printk("IOS_DIST_ROUTE  : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIST_ROUTE+4),
-			READ_REG32(hpa+IOS_DIST_ROUTE));
-	printk("\n");
-	printk("IOS_DIRECT_BASE : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIRECT_BASE+4),
-			READ_REG32(hpa+IOS_DIRECT_BASE));
-	printk("IOS_DIRECT_MASK : %08x %08x\n",
-			READ_REG32(hpa+IOS_DIRECT_MASK+4),
-			READ_REG32(hpa+IOS_DIRECT_MASK));
-	printk("IOS_DIRECT_ROUTE: %08x %08x\n",
-			READ_REG32(hpa+IOS_DIRECT_ROUTE+4),
-			READ_REG32(hpa+IOS_DIRECT_ROUTE));
+	DBG_INIT("SBA at 0x%lx\n", hpa);
+	DBG_INIT("IOS_DIST_BASE   : %Lx\n", READ_REG64(hpa+IOS_DIST_BASE));
+	DBG_INIT("IOS_DIST_MASK   : %Lx\n", READ_REG64(hpa+IOS_DIST_MASK));
+	DBG_INIT("IOS_DIST_ROUTE  : %Lx\n", READ_REG64(hpa+IOS_DIST_ROUTE));
+	DBG_INIT("\n");
+	DBG_INIT("IOS_DIRECT_BASE : %Lx\n", READ_REG64(hpa+IOS_DIRECT_BASE));
+	DBG_INIT("IOS_DIRECT_MASK : %Lx\n", READ_REG64(hpa+IOS_DIRECT_MASK));
+	DBG_INIT("IOS_DIRECT_ROUTE: %Lx\n", READ_REG64(hpa+IOS_DIRECT_ROUTE));
 }
 
+/**
+ * sba_dump_tlb - debugging only - print IOMMU operating parameters
+ * @hpa: base address of the IOMMU
+ *
+ * Print the size/location of the IO MMU PDIR.
+ */
 static void
-sba_dump_tlb(char *hpa)
+sba_dump_tlb(unsigned long hpa)
 {
-	printk("IO TLB at 0x%p\n", hpa);
-	printk("IOC_IBASE   : %08x %08x\n",
-			READ_REG32(hpa+IOC_IBASE+4),
-			READ_REG32(hpa+IOC_IBASE));
-	printk("IOC_IMASK   : %08x %08x\n",
-			READ_REG32(hpa+IOC_IMASK+4),
-			READ_REG32(hpa+IOC_IMASK));
-	printk("IOC_TCNFG   : %08x %08x\n",
-			READ_REG32(hpa+IOC_TCNFG+4),
-			READ_REG32(hpa+IOC_TCNFG));
-	printk("IOC_PDIR_BASE: %08x %08x\n",
-			READ_REG32(hpa+IOC_PDIR_BASE+4),
-			READ_REG32(hpa+IOC_PDIR_BASE));
-	printk("\n");
+	DBG_INIT("IO TLB at 0x%lx\n", hpa);
+	DBG_INIT("IOC_IBASE    : %Lx\n", READ_REG64(hpa+IOC_IBASE));
+	DBG_INIT("IOC_IMASK    : %Lx\n", READ_REG64(hpa+IOC_IMASK));
+	DBG_INIT("IOC_TCNFG    : %Lx\n", READ_REG64(hpa+IOC_TCNFG));
+	DBG_INIT("IOC_PDIR_BASE: %Lx\n", READ_REG64(hpa+IOC_PDIR_BASE));
+	DBG_INIT("\n");
 }
 #endif
 
 
 #ifdef ASSERT_PDIR_SANITY
 
+/**
+ * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ * @pide: pdir index.
+ *
+ * Print one entry of the IO MMU PDIR in human readable form.
+ */
 static void
 sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
 {
@@ -374,24 +355,30 @@
 	unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]);
 	uint rcnt;
 
-	printk("SBA: %s rp %p bit %d rval 0x%lx\n",
+	printk(KERN_DEBUG "SBA: %s rp %p bit %d rval 0x%lx\n",
 		 msg,
 		 rptr, pide & (BITS_PER_LONG - 1), *rptr);
 
 	rcnt = 0;
 	while (rcnt < BITS_PER_LONG) {
-		printk("%s %2d %p %016Lx\n",
+		printk(KERN_DEBUG "%s %2d %p %016Lx\n",
 			(rcnt == (pide & (BITS_PER_LONG - 1)))
 				? "    -->" : "       ",
 			rcnt, ptr, *ptr );
 		rcnt++;
 		ptr++;
 	}
-	printk(msg);
+	printk(KERN_DEBUG "%s", msg);
 }
 
 
-/* Verify the resource map and pdir state is consistent */
+/**
+ * sba_check_pdir - debugging only - consistency checker
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ *
+ * Verify the resource map and pdir state is consistent
+ */
 static int
 sba_check_pdir(struct ioc *ioc, char *msg)
 {
@@ -428,15 +415,23 @@
 }
 
 
+/**
+ * sba_dump_sg - debugging only - print Scatter-Gather list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: head of the SG list
+ * @nents: number of entries in SG list
+ *
+ * print the SG list so we can verify it's correct by hand.
+ */
 static void
 sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
 {
 	while (nents-- > 0) {
-		printk(" %d : %08lx/%05x %p/%05x\n",
+		printk(KERN_DEBUG " %d : %08lx/%05x %p/%05x\n",
 				nents,
 				(unsigned long) sg_dma_address(startsg),
 				sg_dma_len(startsg),
-				startsg->address, startsg->length);
+				sg_virt_addr(startsg), startsg->length);
 		startsg++;
 	}
 }
@@ -445,25 +440,6 @@
 
 
 
-/*
-** One time initialization to let the world know the LBA was found.
-** This is the only routine which is NOT static.
-** Must be called exactly once before pci_init().
-*/
-void __init
-sba_init(void)
-{
-	sba_list = (struct sba_device *) NULL;
-	sba_count = 0;
-
-#ifdef DEBUG_SBA_INIT
-	sba_dump_ranges((char *) 0xFED00000L);
-#endif
-
-	register_driver(sba_drivers_for);
-}
-
-
 
 /**************************************************************
 *
@@ -489,13 +465,15 @@
 #define RESMAP_IDX_MASK   (sizeof(unsigned long) - 1)
 
 
-/*
-** Perf optimizations:
-** o search for log2(size) bits at a time.
-**
-** Search should use register width as "stride" to search the res_map. 
-*/
-
+/**
+ * sba_search_bitmap - find free space in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @bits_wanted: number of entries we need.
+ *
+ * Find consecutive free bits in resource bitmap.
+ * Each bit represents one entry in the IO Pdir.
+ * Cool perf optimization: search for log2(size) bits at a time.
+ */
 static SBA_INLINE unsigned long
 sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted)
 {
@@ -512,7 +490,6 @@
 				*res_ptr = RESMAP_MASK(bits_wanted);
 				pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
 				pide <<= 3;	/* convert to bit address */
-				ASSERT(0 != pide);
 				break;
 			}
 		}
@@ -536,7 +513,7 @@
 		}
 		mask = RESMAP_MASK(bits_wanted) >> bitshiftcnt;
 
-		DBG_RES("sba_search_bitmap() o %ld %p", o, res_ptr);
+		DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr);
 		while(res_ptr < res_end)
 		{ 
 			DBG_RES("    %p %lx %lx\n", res_ptr, mask, *res_ptr);
@@ -546,7 +523,6 @@
 				pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
 				pide <<= 3;	/* convert to bit address */
 				pide += bitshiftcnt;
-				ASSERT(0 != pide);
 				break;
 			}
 			mask >>= o;
@@ -562,11 +538,24 @@
 	}
 
 	/* wrapped ? */
-	ioc->res_hint = (res_end == res_ptr) ? (unsigned long *) ioc->res_map : res_ptr;
+	if (res_end <= res_ptr) {
+		ioc->res_hint = (unsigned long *) ioc->res_map;
+		ioc->res_bitshift = 0;
+	} else {
+		ioc->res_hint = res_ptr;
+	}
 	return (pide);
 }
 
 
+/**
+ * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @size: number of bytes to create a mapping for
+ *
+ * Given a size, find consecutive unmarked and then mark those bits in the
+ * resource bit map.
+ */
 static int
 sba_alloc_range(struct ioc *ioc, size_t size)
 {
@@ -577,8 +566,8 @@
 	unsigned long pide;
 
 	ASSERT(pages_needed);
-	ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(pages_needed < BITS_PER_LONG);
+	ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(pages_needed <= BITS_PER_LONG);
 	ASSERT(0 == (size & ~IOVP_MASK));
 
 	/*
@@ -590,7 +579,7 @@
 	if (pide >= (ioc->res_size << 3)) {
 		pide = sba_search_bitmap(ioc, pages_needed);
 		if (pide >= (ioc->res_size << 3))
-			panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", ioc->ioc_hpa);
+			panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa);
 	}
 
 #ifdef ASSERT_PDIR_SANITY
@@ -600,8 +589,8 @@
 	}
 #endif
 
-	DBG_RES("sba_alloc_range(%x) %d -> %lx hint %x/%x\n",
-		size, pages_needed, pide,
+	DBG_RES("%s(%x) %d -> %lx hint %x/%x\n",
+		__FUNCTION__, size, pages_needed, pide,
 		(uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
 		ioc->res_bitshift );
 
@@ -622,9 +611,14 @@
 }
 
 
-/*
-** clear bits in the ioc's resource map
-*/
+/**
+ * sba_free_range - unmark bits in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova: IO virtual address which was previously allocated.
+ * @size: number of bytes to create a mapping for
+ *
+ * clear bits in the ioc's resource map
+ */
 static SBA_INLINE void
 sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
 {
@@ -638,8 +632,8 @@
 	/* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */
 	unsigned long m = RESMAP_MASK(bits_not_wanted) >> (pide & (BITS_PER_LONG - 1));
 
-	DBG_RES("sba_free_range( ,%x,%x) %x/%lx %x %p %lx\n",
-		(uint) iova, size,
+	DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n",
+		__FUNCTION__, (uint) iova, size,
 		bits_not_wanted, m, pide, res_ptr, *res_ptr);
 
 #ifdef CONFIG_PROC_FS
@@ -648,8 +642,8 @@
 
 	ASSERT(m != 0);
 	ASSERT(bits_not_wanted);
-	ASSERT((bits_not_wanted * IOVP_SIZE) < DMA_CHUNK_SIZE);
-	ASSERT(bits_not_wanted < BITS_PER_LONG);
+	ASSERT((bits_not_wanted * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+	ASSERT(bits_not_wanted <= BITS_PER_LONG);
 	ASSERT((*res_ptr & m) == m); /* verify same bits are set */
 	*res_ptr &= ~m;
 }
@@ -667,31 +661,37 @@
 typedef unsigned long space_t;
 #define KERNEL_SPACE 0
 
-/*
-* SBA Mapping Routine
-*
-* Given a virtual address (vba, arg2) and space id, (sid, arg1)
-* sba_io_pdir_entry() loads the I/O PDIR entry pointed to by
-* pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as
-* shown below (MSB == bit 0):
-*
-*  0                    19                                 51   55       63
-* +-+---------------------+----------------------------------+----+--------+
-* |V|        U            |            PPN[43:12]            | U  |   VI   |
-* +-+---------------------+----------------------------------+----+--------+
-*
-*  V  == Valid Bit
-*  U  == Unused
-* PPN == Physical Page Number
-* VI  == Virtual Index (aka Coherent Index)
-*
-* The physical address fields are filled with the results of the LPA
-* instruction.  The virtual index field is filled with the results of
-* of the LCI (Load Coherence Index) instruction.  The 8 bits used for
-* the virtual index are bits 12:19 of the value returned by LCI.
-*
-* We need to pre-swap the bytes since PCX-W is Big Endian.
-*/
+/**
+ * sba_io_pdir_entry - fill in one IO PDIR entry
+ * @pdir_ptr:  pointer to IO PDIR entry
+ * @sid: process Space ID
+ * @vba: Virtual CPU address of buffer to map
+ *
+ * SBA Mapping Routine
+ *
+ * Given a virtual address (vba, arg2) and space id, (sid, arg1)
+ * sba_io_pdir_entry() loads the I/O PDIR entry pointed to by
+ * pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as
+ * shown below (MSB == bit 0):
+ *
+ *  0                    19                                 51   55       63
+ * +-+---------------------+----------------------------------+----+--------+
+ * |V|        U            |            PPN[43:12]            | U  |   VI   |
+ * +-+---------------------+----------------------------------+----+--------+
+ *
+ *  V  == Valid Bit
+ *  U  == Unused
+ * PPN == Physical Page Number
+ * VI  == Virtual Index (aka Coherent Index)
+ *
+ * The physical address fields are filled with the results of the LPA
+ * instruction.  The virtual index field is filled with the results of
+ * of the LCI (Load Coherence Index) instruction.  The 8 bits used for
+ * the virtual index are bits 12:19 of the value returned by LCI.
+ *
+ * We need to pre-swap the bytes since PCX-W is Big Endian.
+ */
+
 
 void SBA_INLINE
 sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba)
@@ -699,9 +699,11 @@
 	u64 pa; /* physical address */
 	register unsigned ci; /* coherent index */
 
-	/* We currently only support kernel addresses */
-	ASSERT(sid == 0);
-	ASSERT(((unsigned long) vba & 0xc0000000UL) == 0xc0000000UL);
+	/* We currently only support kernel addresses.
+	 * fdc instr below will need to reload sr1 with KERNEL_SPACE
+	 * once we try to support direct DMA to user space.
+	 */
+	ASSERT(sid == KERNEL_SPACE);
 
 	pa = virt_to_phys(vba);
 	pa &= ~4095ULL;			/* clear out offset bits */
@@ -712,25 +714,41 @@
 
 	pa |= 0x8000000000000000ULL;	/* set "valid" bit */
 	*pdir_ptr = cpu_to_le64(pa);	/* swap and store into I/O Pdir */
+
+	/*
+	 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set
+	 * (bit #61, big endian), we have to flush and sync every time
+	 * IO-PDIR is changed in Ike/Astro.
+	 */
+	if (ioc_needs_fdc) {
+		asm volatile("fdc 0(%%sr1,%0)\n\tsync" : : "r" (pdir_ptr));
+	}
 }
 
 
-/***********************************************************
- * The Ike PCOM (Purge Command Register) is to purge
- * stale entries in the IO TLB when unmapping entries.
+/**
+ * sba_mark_invalid - invalidate one or more IO PDIR entries
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova:  IO Virtual Address mapped earlier
+ * @byte_cnt:  number of bytes this mapping covers.
+ *
+ * Marking the IO PDIR entry(ies) as Invalid and invalidate
+ * corresponding IO TLB entry. The Ike PCOM (Purge Command Register)
+ * is to purge stale entries in the IO TLB when unmapping entries.
  *
  * The PCOM register supports purging of multiple pages, with a minium
  * of 1 page and a maximum of 2GB. Hardware requires the address be
  * aligned to the size of the range being purged. The size of the range
- * must be a power of 2.
- ***********************************************************/
+ * must be a power of 2. The "Cool perf optimization" in the
+ * allocation routine helps keep that true.
+ */
 static SBA_INLINE void
 sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
 {
 	u32 iovp = (u32) SBA_IOVP(ioc,iova);
 
 	/* Even though this is a big-endian machine, the entries
-	** in the iopdir are swapped. That's why we clear the byte
+	** in the iopdir are little endian. That's why we clear the byte
 	** at +7 instead of at +0.
 	*/
 	int off = PDIR_INDEX(iovp)*sizeof(u64)+7;
@@ -775,32 +793,45 @@
 		} while (byte_cnt > 0);
 	}
 
-	WRITE_REG32(iovp, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
 }
 
+/**
+ * sba_dma_supported - PCI driver can query DMA support
+ * @dev: instance of PCI owned by the driver that's asking
+ * @mask:  number of address bits this PCI device can handle
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static int
 sba_dma_supported( struct pci_dev *dev, u64 mask)
 {
 	if (dev == NULL) {
-		printk(MODULE_NAME ": EISA/ISA/et al not supported\n");
+		printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
 		BUG();
 		return(0);
 	}
 
 	dev->dma_mask = mask;	/* save it */
 
-	/* only support PCI devices */
-	return((int) (mask >= 0xffffffff));
+	/* only support 32-bit PCI devices - no DAC support (yet) */
+	return((int) (mask == 0xffffffff));
 }
 
 
-/*
-** map_single returns a fully formed IOVA
-*/
+/**
+ * sba_map_single - map one buffer and return IOVA for DMA
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @addr:  driver buffer to map.
+ * @size:  number of bytes to map in driver buffer.
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static dma_addr_t
 sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
 {
-	struct ioc *ioc = &sba_list->ioc[0];  /* FIXME : see Multi-IOC below */
+	struct ioc *ioc;
 	unsigned long flags; 
 	dma_addr_t iovp;
 	dma_addr_t offset;
@@ -808,9 +839,14 @@
 	int pide;
 
 	ASSERT(size > 0);
+	ASSERT(size <= DMA_CHUNK_SIZE);
+
+	ASSERT(dev->sysdata);
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
 
 	/* save offset bits */
-	offset = ((dma_addr_t) addr) & ~IOVP_MASK;
+	offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
 
 	/* round up to nearest IOVP_SIZE */
 	size = (size + offset + ~IOVP_MASK) & IOVP_MASK;
@@ -827,7 +863,8 @@
 	pide = sba_alloc_range(ioc, size);
 	iovp = (dma_addr_t) pide << IOVP_SHIFT;
 
-	DBG_RUN("sba_map_single() 0x%p -> 0x%lx", addr, (long) iovp | offset);
+	DBG_RUN("%s() 0x%p -> 0x%lx",
+		__FUNCTION__, addr, (long) iovp | offset);
 
 	pdir_start = &(ioc->pdir_base[pide]);
 
@@ -860,72 +897,85 @@
 }
 
 
+/**
+ * sba_unmap_single - unmap one IOVA and free resources
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @iova:  IOVA of driver buffer previously mapped.
+ * @size:  number of bytes mapped in driver buffer.
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static void
 sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction)
 {
-#ifdef FIXME
-/* Multi-IOC (ie N-class) :  need to lookup IOC from dev
-** o If we can't know about lba PCI data structs, that eliminates ->sysdata.
-** o walking up pcidev->parent dead ends at elroy too
-** o leaves hashing dev->bus->number into some lookup.
-**   (may only work for N-class)
-** o use (struct pci_hba) and put fields in there for DMA.
-**   (ioc and per device dma_hint.)
-**
-** Last one seems the clearest and most promising.
-** sba_dma_supported() fill in those fields when the driver queries
-** the system for support.
-*/
-	struct ioc *ioc = (struct ioc *) ((struct pci_hba *) (dev->sysdata))->dma_data;
-#else
-	struct ioc *ioc = &sba_list->ioc[0];
+	struct ioc *ioc;
+#if DELAYED_RESOURCE_CNT > 0
+	struct sba_dma_pair *d;
 #endif
-	
 	unsigned long flags; 
 	dma_addr_t offset;
+
+	ASSERT(dev->sysdata);
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
+
 	offset = iova & ~IOVP_MASK;
 
-	DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long) iova, size);
+	DBG_RUN("%s() iovp 0x%lx/%x\n",
+		__FUNCTION__, (long) iova, size);
 
 	iova ^= offset;        /* clear offset bits */
 	size += offset;
 	size = ROUNDUP(size, IOVP_SIZE);
 
-	ASSERT(0 != iova);
-
 	spin_lock_irqsave(&ioc->res_lock, flags);
+
 #ifdef CONFIG_PROC_FS
 	ioc->usingle_calls++;
 	ioc->usingle_pages += size >> IOVP_SHIFT;
 #endif
-#ifdef DELAYED_RESOURCE_CNT
-	if (ioc->saved_cnt < DELAYED_RESOURCE_CNT) {
-		ioc->saved_iova[ioc->saved_cnt] = iova;
-		ioc->saved_size[ioc->saved_cnt] = size;
-		ioc_saved_cnt++;
-	} else {
-		do {
-#endif
-			sba_mark_invalid(ioc, iova, size);
-			sba_free_range(ioc, iova, size);
 
-#ifdef DELAYED_RESOURCE_CNT
-			ioc->saved_cnt--;
-			iova = ioc->saved_iova[ioc->saved_cnt];
-			size = ioc->saved_size[ioc->saved_cnt];
-		} while (ioc->saved_cnt)
-
-		/* flush purges */
-		(void) (volatile) READ_REG32(ioc->ioc_hpa+IOC_PCOM);
+#if DELAYED_RESOURCE_CNT > 0
+	d = &(ioc->saved[ioc->saved_cnt]);
+	d->iova = iova;
+	d->size = size;
+	if (++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT) {
+		int cnt = ioc->saved_cnt;
+		while (cnt--) {
+			sba_mark_invalid(ioc, d->iova, d->size);
+			sba_free_range(ioc, d->iova, d->size);
+			d--;
+		}
+		ioc->saved_cnt = 0;
+		READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
 	}
-#else
-	/* flush purges */
-	READ_REG32(ioc->ioc_hpa+IOC_PCOM);
-#endif
+#else /* DELAYED_RESOURCE_CNT == 0 */
+	sba_mark_invalid(ioc, iova, size);
+	sba_free_range(ioc, iova, size);
+	READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
+#endif /* DELAYED_RESOURCE_CNT == 0 */
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+	/* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support.
+	** For Astro based systems this isn't a big deal WRT performance.
+	** As long as 2.4 kernels copyin/copyout data from/to userspace,
+	** we don't need the syncdma. The issue here is I/O MMU cachelines
+	** are *not* coherent in all cases.  May be hwrev dependent.
+	** Need to investigate more.
+	asm volatile("syncdma");	
+	*/
 }
 
 
+/**
+ * sba_alloc_consistent - allocate/map shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size:  number of bytes mapped in driver buffer.
+ * @dma_handle:  IOVA of new buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static void *
 sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
 {
@@ -948,6 +998,15 @@
 }
 
 
+/**
+ * sba_free_consistent - free/unmap shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size:  number of bytes mapped in driver buffer.
+ * @vaddr:  virtual address IOVA of "consistent" buffer.
+ * @dma_handler:  IO virtual address of "consistent" buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static void
 sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
 {
@@ -955,27 +1014,6 @@
 	free_pages((unsigned long) vaddr, get_order(size));
 }
 
-/*
-** Two address ranges are "virtually contiguous" iff:
-** 1) end of prev == start of next, or...	 append case
-** 3) end of next == start of prev		 prepend case
-**
-** and they are DMA contiguous *iff*:
-** 2) end of prev and start of next are both on a page boundry
-**
-** (shift left is a quick trick to mask off upper bits)
-*/
-#define DMA_CONTIG(__X, __Y) \
-	(((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
-
-/*
-** Assumption is two transactions are mutually exclusive.
-** ie both go to different parts of memory.
-** If both are true, then both transaction are on the same page.
-*/
-#define DMA_SAME_PAGE(s1,e1,s2,e2) \
-	( ((((s1) ^ (s2)) >> PAGE_SHIFT) == 0) \
-		&& ((((e1) ^ (e2)) >> PAGE_SHIFT) == 0) )
 
 /*
 ** Since 0 is a valid pdir_base index value, can't use that
@@ -988,6 +1026,17 @@
 int dump_run_sg = 0;
 #endif
 
+
+/**
+ * sba_fill_pdir - write allocated SG entries into IO PDIR
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg:  list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * Take preprocessed SG list and write corresponding entries
+ * in the IO PDIR.
+ */
+
 static SBA_INLINE int
 sba_fill_pdir(
 	struct ioc *ioc,
@@ -1006,16 +1055,16 @@
 
 #ifdef DEBUG_LARGE_SG_ENTRIES
 		if (dump_run_sg)
-			printk(" %d : %08lx/%05x %p/%05x\n",
+			printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n",
 				nents,
 				(unsigned long) sg_dma_address(startsg), cnt,
-				startsg->address, startsg->length
+				sg_virt_address(startsg), startsg->length
 		);
 #else
 		DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n",
 				nents,
 				(unsigned long) sg_dma_address(startsg), cnt,
-				startsg->address, startsg->length
+				sg_virt_addr(startsg), startsg->length
 		);
 #endif
 		/*
@@ -1024,11 +1073,10 @@
 		if (sg_dma_address(startsg) & PIDE_FLAG) {
 			u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG;
 			dma_offset = (unsigned long) pide & ~IOVP_MASK;
-			pide >>= IOVP_SHIFT;
-			pdirp = &(ioc->pdir_base[pide]);
 			sg_dma_address(startsg) = 0;
-			++dma_sg;
-			sg_dma_address(dma_sg) = (pide << IOVP_SHIFT) + dma_offset;
+			dma_sg++;
+			sg_dma_address(dma_sg) = pide;
+			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
 			n_mappings++;
 		}
 
@@ -1036,9 +1084,12 @@
 		** Look for a VCONTIG chunk
 		*/
 		if (cnt) {
-			unsigned long vaddr = (unsigned long) startsg->address;
+			unsigned long vaddr = (unsigned long) sg_virt_addr(startsg);
 			ASSERT(pdirp);
 
+			/* Since multiple Vcontig blocks could make up
+			** one DMA stream, *add* cnt to dma_len.
+			*/
 			sg_dma_len(dma_sg) += cnt;
 			cnt += dma_offset;
 			dma_offset=0;	/* only want offset on first chunk */
@@ -1062,133 +1113,142 @@
 }
 
 
-
 /*
-** First pass is to walk the SG list and determine where the breaks are
-** in the DMA stream. Allocates PDIR entries but does not fill them.
-** Returns the number of DMA chunks.
+** Two address ranges are DMA contiguous *iff* "end of prev" and
+** "start of next" are both on a page boundry.
 **
-** Doing the fill seperate from the coalescing/allocation keeps the
-** code simpler. Future enhancement could make one pass through
-** the sglist do both.
+** (shift left is a quick trick to mask off upper bits)
 */
+#define DMA_CONTIG(__X, __Y) \
+	(((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
+
+
+/**
+ * sba_coalesce_chunks - preprocess the SG list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg:  list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * First pass is to walk the SG list and determine where the breaks are
+ * in the DMA stream. Allocates PDIR entries but does not fill them.
+ * Returns the number of DMA chunks.
+ *
+ * Doing the fill seperate from the coalescing/allocation keeps the
+ * code simpler. Future enhancement could make one pass through
+ * the sglist do both.
+ */
 static SBA_INLINE int
 sba_coalesce_chunks( struct ioc *ioc,
 	struct scatterlist *startsg,
 	int nents)
 {
+	struct scatterlist *vcontig_sg;    /* VCONTIG chunk head */
+	unsigned long vcontig_len;         /* len of VCONTIG chunk */
+	unsigned long vcontig_end;
+	struct scatterlist *dma_sg;        /* next DMA stream head */
+	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
 	int n_mappings = 0;
 
 	while (nents > 0) {
-		struct scatterlist *dma_sg;  /* next DMA stream head */
-		unsigned long dma_offset, dma_len;   /* start/len of DMA stream */
-		struct scatterlist *chunksg; /* virtually contig chunk head */
-		unsigned long chunk_addr, chunk_len; /* start/len of VCONTIG chunk */
+		unsigned long vaddr = (unsigned long) sg_virt_addr(startsg); 
 
 		/*
 		** Prepare for first/next DMA stream
 		*/
-		dma_sg = chunksg = startsg;
-		dma_len = chunk_len  = startsg->length;
-		chunk_addr = (unsigned long) startsg->address;
-		dma_offset = 0UL;
+		dma_sg = vcontig_sg = startsg;
+		dma_len = vcontig_len = vcontig_end = startsg->length;
+		vcontig_end +=  vaddr;
+		dma_offset = vaddr & ~IOVP_MASK;
+
+		/* PARANOID: clear entries */
+		sg_dma_address(startsg) = 0;
+		sg_dma_len(startsg) = 0;
 
 		/*
 		** This loop terminates one iteration "early" since
 		** it's always looking one "ahead".
 		*/
 		while (--nents > 0) {
-			/* ptr to coalesce prev and next */
-			struct scatterlist *prev_sg = startsg;
-			unsigned long prev_end = (unsigned long) prev_sg->address + prev_sg->length;
-			unsigned long current_end;
+			unsigned long vaddr;	/* tmp */
+
+			startsg++;
 
 			/* PARANOID: clear entries */
 			sg_dma_address(startsg) = 0;
 			sg_dma_len(startsg) = 0;
 
-			/* Now start looking ahead */
-			startsg++;
-			current_end  = (unsigned long) startsg->address + startsg->length;
+			/* catch brokenness in SCSI layer */
+			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
 
 			/*
-			** First look for virtually contiguous blocks.
-			** PARISC needs this since it's cache is virtually
-			** indexed and we need the associated virtual
-			** address for each I/O address we map.
-			**
-			** 1) can we *prepend* the next transaction?
+			** First make sure current dma stream won't
+			** exceed DMA_CHUNK_SIZE if we coalesce the
+			** next entry.
 			*/
-			if (current_end == (unsigned long) prev_sg->address)
-			{
-				/* prepend : get new offset */
-				chunksg = startsg;
-				chunk_addr = (unsigned long) prev_sg->address;
-				chunk_len += startsg->length;
-				dma_len   += startsg->length;
-				continue;
-			}
+			if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE)
+				break;
 
 			/*
-			** 2) or append the next transaction?
+			** Then look for virtually contiguous blocks.
+			** PARISC needs to associate a virtual address
+			** with each IO address mapped. The CPU cache is
+			** virtually tagged and the IOMMU uses part
+			** of the virtual address to participate in
+			** CPU cache coherency.
+			**
+			** append the next transaction?
 			*/
-			if  (prev_end == (unsigned long) startsg->address)
+			vaddr = (unsigned long) sg_virt_addr(startsg);
+			if  (vcontig_end == vaddr)
 			{
-				chunk_len += startsg->length;
-				dma_len   += startsg->length;
+				vcontig_len += startsg->length;
+				vcontig_end += startsg->length;
+				dma_len     += startsg->length;
 				continue;
 			}
 
 #ifdef DEBUG_LARGE_SG_ENTRIES
-			dump_run_sg = (chunk_len > IOVP_SIZE);
+			dump_run_sg = (vcontig_len > IOVP_SIZE);
 #endif
+
 			/*
 			** Not virtually contigous.
 			** Terminate prev chunk.
 			** Start a new chunk.
 			**
-			** Once we start a new VCONTIG chunk, the offset
+			** Once we start a new VCONTIG chunk, dma_offset
 			** can't change. And we need the offset from the first
 			** chunk - not the last one. Ergo Successive chunks
 			** must start on page boundaries and dove tail
 			** with it's predecessor.
 			*/
-			sg_dma_len(prev_sg) = chunk_len;
+			sg_dma_len(vcontig_sg) = vcontig_len;
 
-			chunk_len = startsg->length;
-			dma_offset |= (chunk_addr & ~IOVP_MASK);
-			ASSERT((0 == (chunk_addr & ~IOVP_MASK)) ||
-				(dma_offset == (chunk_addr & ~IOVP_MASK)));
+			vcontig_sg = startsg;
+			vcontig_len = startsg->length;
 
-#if 0
 			/*
-			** 4) do the chunks end/start on page boundaries?
-			**  Easier than 3 since no offsets are involved.
+			** 3) do the entries end/start on page boundaries?
+			**    Don't update vcontig_end until we've checked.
 			*/
-			if (DMA_CONTIG(prev_end, startsg->address))
+			if (DMA_CONTIG(vcontig_end, vaddr))
 			{
-				/*
-				** Yes.
-				** Reset chunk ptr.
-				*/
-				chunksg = startsg;
-				chunk_addr = (unsigned long) startsg->address;
-
+				vcontig_end = vcontig_len + vaddr;
+				dma_len += vcontig_len;
 				continue;
-			} else
-#endif
-			{
+			} else {
 				break;
 			}
 		}
 
 		/*
 		** End of DMA Stream
-		** Terminate chunk.
+		** Terminate last VCONTIG block.
 		** Allocate space for DMA stream.
 		*/
-		sg_dma_len(startsg) = chunk_len;
+		sg_dma_len(vcontig_sg) = vcontig_len;
 		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
+		ASSERT(dma_len <= DMA_CHUNK_SIZE);
 		sg_dma_address(dma_sg) =
 			PIDE_FLAG 
 			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
@@ -1200,24 +1260,34 @@
 }
 
 
-/*
-** And this algorithm still generally only ends up coalescing entries
-** that happens to be on the same page due to how sglists are assembled.
-*/
+/**
+ * sba_map_sg - map Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist:  array of buffer/length pairs
+ * @nents:  number of entries in list
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static int
 sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
 {
-	struct ioc *ioc = &sba_list->ioc[0];  /* FIXME : see Multi-IOC below */
+	struct ioc *ioc;
 	int coalesced, filled = 0;
 	unsigned long flags;
 
 	DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
 
+	ASSERT(dev->sysdata);
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
+
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sg_dma_address(sglist)= sba_map_single(dev, sglist->address,
+		sg_dma_address(sglist) = sba_map_single(dev,
+						sg_virt_addr(sglist),
 						sglist->length, direction);
-		sg_dma_len(sglist)= sglist->length;
+		sg_dma_len(sglist)     = sglist->length;
 		return 1;
 	}
 
@@ -1272,16 +1342,29 @@
 }
 
 
+/**
+ * sba_unmap_sg - unmap Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist:  array of buffer/length pairs
+ * @nents:  number of entries in list
+ * @direction:  R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
 static void 
 sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
 {
-	struct ioc *ioc = &sba_list->ioc[0];  /* FIXME : see Multi-IOC below */
+	struct ioc *ioc;
 #ifdef ASSERT_PDIR_SANITY
 	unsigned long flags;
 #endif
 
 	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
-		__FUNCTION__, nents, sglist->address, sglist->length);
+		__FUNCTION__, nents, sg_virt_addr(sglist), sglist->length);
+
+	ASSERT(dev->sysdata);
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
 
 #ifdef CONFIG_PROC_FS
 	ioc->usg_calls++;
@@ -1295,10 +1378,11 @@
 
 	while (sg_dma_len(sglist) && nents--) {
 
+		sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
 #ifdef CONFIG_PROC_FS
-	ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
+		ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+		ioc->usingle_calls--;	/* kluge since call is unmap_sg() */
 #endif
-		sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
 		++sglist;
 	}
 
@@ -1359,21 +1443,117 @@
 *   Initialization and claim
 *
 ***************************************************************/
+#define PIRANHA_ADDR_MASK	0x00160000UL /* bit 17,18,20 */
+#define PIRANHA_ADDR_VAL	0x00060000UL /* bit 17,18 on */
+static void *
+sba_alloc_pdir(unsigned int pdir_size)
+{
+        unsigned long pdir_base;
+	unsigned long pdir_order = get_order(pdir_size);
+
+	pdir_base = __get_free_pages(GFP_KERNEL, pdir_order);
+	if (NULL == (void *) pdir_base)
+		panic("sba_ioc_init() could not allocate I/O Page Table\n");
+
+	/* If this is not PA8700 (PCX-W2)
+	**	OR newer than ver 2.2
+	**	OR in a system that doesn't need VINDEX bits from SBA,
+	**
+	** then we aren't exposed to the HW bug.
+	*/
+	if ( ((boot_cpu_data.pdc.cpuid >> 5) & 0x7f) != 0x13
+			|| (boot_cpu_data.pdc.versions > 0x202)
+			|| (boot_cpu_data.pdc.capabilities & 0x08L) )
+		return (void *) pdir_base;
+
+	/*
+	 * PA8700 (PCX-W2, aka piranha) silent data corruption fix
+	 *
+	 * An interaction between PA8700 CPU (Ver 2.2 or older) and
+	 * Ike/Astro can cause silent data corruption. This is only
+	 * a problem if the I/O PDIR is located in memory such that
+	 * (little-endian)  bits 17 and 18 are on and bit 20 is off.
+	 *
+	 * Since the max IO Pdir size is 2MB, by cleverly allocating the
+	 * right physical address, we can either avoid (IOPDIR <= 1MB)
+	 * or minimize (2MB IO Pdir) the problem if we restrict the
+	 * IO Pdir to a maximum size of 2MB-128K (1902K).
+	 *
+	 * Because we always allocate 2^N sized IO pdirs, either of the
+	 * "bad" regions will be the last 128K if at all. That's easy
+	 * to test for.
+	 * 
+	 */
+	if (pdir_order <= (19-12)) {
+		if (((virt_to_phys(pdir_base)+pdir_size-1) & PIRANHA_ADDR_MASK) == PIRANHA_ADDR_VAL) {
+			/* allocate a new one on 512k alignment */
+			unsigned long new_pdir = __get_free_pages(GFP_KERNEL, (19-12));
+			/* release original */
+			free_pages(pdir_base, pdir_order);
+
+			pdir_base = new_pdir;
+
+			/* release excess */
+			while (pdir_order < (19-12)) {
+				new_pdir += pdir_size;
+				free_pages(new_pdir, pdir_order);
+				pdir_order +=1;
+				pdir_size <<=1;
+			}
+		}
+	} else {
+		/*
+		** 1MB or 2MB Pdir
+		** Needs to be aligned on an "odd" 1MB boundary.
+		*/
+		unsigned long new_pdir = __get_free_pages(GFP_KERNEL, pdir_order+1); /* 2 or 4MB */
+
+		/* release original */
+		free_pages( pdir_base, pdir_order);
+
+		/* release first 1MB */
+		free_pages(new_pdir, 20-12);
+
+		pdir_base = new_pdir + 1024*1024;
+
+		if (pdir_order > (20-12)) {
+			/*
+			** 2MB Pdir.
+			**
+			** Flag tells init_bitmap() to mark bad 128k as used
+			** and to reduce the size by 128k.
+			*/
+			piranha_bad_128k = 1;
+
+			new_pdir += 3*1024*1024;
+			/* release last 1MB */
+			free_pages(new_pdir, 20-12);
+
+			/* release unusable 128KB */
+			free_pages(new_pdir - 128*1024 , 17-12);
+
+			pdir_size -= 128*1024;
+		}
+	}
+
+	memset((void *) pdir_base, 0, pdir_size);
+	return (void *) pdir_base;
+}
 
 
 static void
-sba_ioc_init(struct ioc *ioc)
+sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
 {
-	extern unsigned long mem_max;          /* arch.../setup.c */
-	extern void lba_init_iregs(void *, u32, u32);   /* arch.../lba_pci.c */
+	/* lba_set_iregs() is in arch/parisc/kernel/lba_pci.c */
+	extern void lba_set_iregs(struct parisc_device *, u32, u32);
 
 	u32 iova_space_size, iova_space_mask;
-	void * pdir_base;
 	int pdir_size, iov_order;
+	unsigned long physmem;
+	struct parisc_device *lba;
 
 	/*
 	** Determine IOVA Space size from memory size.
-	** Using "mem_max" is a kluge.
 	**
 	** Ideally, PCI drivers would register the maximum number
 	** of DMA they can have outstanding for each device they
@@ -1385,20 +1565,24 @@
 	** While we have 32-bits "IOVA" space, top two 2 bits are used
 	** for DMA hints - ergo only 30 bits max.
 	*/
+
+	physmem = num_physpages << PAGE_SHIFT;
+	iova_space_size = (u32) (physmem/(sba_mem_ratio*global_ioc_cnt));
+
 	/* limit IOVA space size to 1MB-1GB */
-	if (mem_max < (sba_mem_ratio*1024*1024)) {
+	if (iova_space_size < 1024*1024) {
 		iova_space_size = 1024*1024;
+	}
 #ifdef __LP64__
-	} else if (mem_max > (sba_mem_ratio*512*1024*1024)) {
+	else if (iova_space_size > 512*1024*1024) {
 		iova_space_size = 512*1024*1024;
-#endif
-	} else {
-		iova_space_size = (u32) (mem_max/sba_mem_ratio);
 	}
+#endif
 
 	/*
 	** iova space must be log2() in size.
 	** thus, pdir/res_map will also be log2().
+	** PIRANHA BUG: Exception is when IO Pdir is 2MB (gets reduced)
 	*/
 	iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT));
 	ASSERT(iov_order <= (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
@@ -1407,35 +1591,27 @@
 
 	ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
 
-	ASSERT(pdir_size < 4*1024*1024);   /* max pdir size < 4MB */
+	ASSERT(pdir_size < 4*1024*1024);   /* max pdir size == 2MB */
 
 	/* Verify it's a power of two */
 	ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT));
 
-	DBG_INIT("%s() hpa 0x%p mem %dMBIOV %dMB (%d bits) PDIR size 0x%0x",
-		__FUNCTION__, ioc->ioc_hpa, (int) (mem_max>>20),
+	DBG_INIT("%s() hpa 0x%lx mem %dMB IOV %dMB (%d bits) PDIR size 0x%0x\n",
+		__FUNCTION__, ioc->ioc_hpa, (int) (physmem>>20),
 		iova_space_size>>20, iov_order + PAGE_SHIFT, pdir_size);
 
 	/* FIXME : DMA HINTs not used */
 	ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
 	ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
 
-	ioc->pdir_base =
-	pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
-	if (NULL == pdir_base)
-	{
-		panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
-	}
-	memset(pdir_base, 0, pdir_size);
+	ioc->pdir_base = sba_alloc_pdir(pdir_size);
 
-	DBG_INIT("sba_ioc_init() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
-		pdir_base, pdir_size,
+	DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
+		__FUNCTION__, ioc->pdir_base, pdir_size,
 		ioc->hint_shift_pdir, ioc->hint_mask_pdir);
 
-	ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
-	WRITE_REG64(virt_to_phys(pdir_base), (u64 *)(ioc->ioc_hpa+IOC_PDIR_BASE));
-
-	DBG_INIT(" base %p\n", pdir_base);
+	ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base);
+	WRITE_REG64(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
 
 	/* build IMASK for IOC and Elroy */
 	iova_space_mask =  0xffffffff;
@@ -1448,8 +1624,8 @@
 	ioc->ibase = IOC_IOVA_SPACE_BASE | 1;	/* bit 0 == enable bit */
 	ioc->imask = iova_space_mask;	/* save it */
 
-	DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", __FUNCTION__,
-		ioc->ibase, ioc->imask);
+	DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n",
+		__FUNCTION__, ioc->ibase, ioc->imask);
 
 	/*
 	** FIXME: Hint registers are programmed with default hint
@@ -1460,22 +1636,26 @@
 	/*
 	** setup Elroy IBASE/IMASK registers as well.
 	*/
-	lba_init_iregs(ioc->ioc_hpa, ioc->ibase, ioc->imask);
+	for (lba = sba->child; lba; lba = lba->sibling) {
+		int rope_num = (lba->hpa >> 13) & 0xf;
+		if (rope_num >> 3 == ioc_num)
+			lba_set_iregs(lba, ioc->ibase, ioc->imask);
+	}
 
 	/*
 	** Program the IOC's ibase and enable IOVA translation
 	*/
-	WRITE_REG32(ioc->ibase, ioc->ioc_hpa+IOC_IBASE);
-	WRITE_REG32(ioc->imask, ioc->ioc_hpa+IOC_IMASK);
+	WRITE_REG(ioc->ibase, ioc->ioc_hpa+IOC_IBASE);
+	WRITE_REG(ioc->imask, ioc->ioc_hpa+IOC_IMASK);
 
 	/* Set I/O PDIR Page size to 4K */
-	WRITE_REG32(0, ioc->ioc_hpa+IOC_TCNFG);
+	WRITE_REG(0, ioc->ioc_hpa+IOC_TCNFG);
 
 	/*
 	** Clear I/O TLB of any possible entries.
-	** (Yes. This is a it paranoid...but so what)
+	** (Yes. This is a bit paranoid...but so what)
 	*/
-	WRITE_REG32(0 | 31, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(0 | 31, ioc->ioc_hpa+IOC_PCOM);
 
 	DBG_INIT("%s() DONE\n", __FUNCTION__);
 }
@@ -1498,23 +1678,24 @@
 { 
 	int i;
 	int num_ioc;
-	u32 ioc_ctl;
+	u64 ioc_ctl;
+
+	ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
+	DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
+		__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
+	ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC | IOC_CTRL_CE);
+	ioc_ctl |= IOC_CTRL_TC;	/* Astro: firmware enables this */
 
-	ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL);
-	DBG_INIT("%s() hpa 0x%p ioc_ctl 0x%x ->", __FUNCTION__, sba_dev->sba_hpa, ioc_ctl );
-	ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC);
-	ASSERT(ioc_ctl & IOC_CTRL_TE);	/* astro: firmware enables this */
-
-	WRITE_REG32(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL);
-
-#ifdef SBA_DEBUG_INIT
-	ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL);
-	DBG_INIT(" 0x%x\n", ioc_ctl );
+	WRITE_REG(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL);
+
+#ifdef DEBUG_SBA_INIT
+	ioc_ctl = READ_REG64(sba_dev->sba_hpa+IOC_CTRL);
+	DBG_INIT(" 0x%Lx\n", ioc_ctl);
 #endif
 
 	if (IS_ASTRO(sba_dev->iodc)) {
 		/* PAT_PDC (L-class) also reports the same goofy base */
-		sba_dev->ioc[0].ioc_hpa = (char *) ASTRO_IOC_OFFSET;
+		sba_dev->ioc[0].ioc_hpa = ASTRO_IOC_OFFSET;
 		num_ioc = 1;
 	} else {
 		sba_dev->ioc[0].ioc_hpa = sba_dev->ioc[1].ioc_hpa = 0;
@@ -1522,26 +1703,25 @@
 	}
 
 	sba_dev->num_ioc = num_ioc;
-	for( i = 0; i < num_ioc; i++)
-	{
-		(unsigned long) sba_dev->ioc[i].ioc_hpa += (unsigned long) sba_dev->sba_hpa + IKE_IOC_OFFSET(i);
+	for (i = 0; i < num_ioc; i++) {
+		sba_dev->ioc[i].ioc_hpa += sba_dev->sba_hpa + IKE_IOC_OFFSET(i);
 
 		/*
 		** Make sure the box crashes if we get any errors on a rope.
 		*/
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL);
-		WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL);
+		WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
 
 		/* flush out the writes */
-		READ_REG32(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
+		READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
 
-		sba_ioc_init(&(sba_dev->ioc[i]));
+		sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i);
 	}
 }
 
@@ -1555,11 +1735,10 @@
 	*/
 	sba_dev->next = sba_list;
 	sba_list = sba_dev;
-	sba_count++;
 
 	for(i=0; i< sba_dev->num_ioc; i++) {
 		int res_size;
-#ifdef CONFIG_DMB_TRAP
+#ifdef DEBUG_DMB_TRAP
 		extern void iterate_pages(unsigned long , unsigned long ,
 					  void (*)(pte_t * , unsigned long),
 					  unsigned long );
@@ -1567,13 +1746,20 @@
 #endif
 		/* resource map size dictated by pdir_size */
 		res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */
+
+		/* Second part of PIRANHA BUG */
+		if (piranha_bad_128k) {
+			res_size -= (128*1024)/sizeof(u64);
+		}
+
 		res_size >>= 3;  /* convert bit count to byte count */
-		DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, res_size);
+		DBG_INIT("%s() res_size 0x%x\n",
+			__FUNCTION__, res_size);
 
 		sba_dev->ioc[i].res_size = res_size;
 		sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
 
-#ifdef CONFIG_DMB_TRAP
+#ifdef DEBUG_DMB_TRAP
 		iterate_pages( sba_dev->ioc[i].res_map, res_size,
 				set_data_memory_break, 0);
 #endif
@@ -1594,39 +1780,66 @@
 		sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL;
 #endif
 
-#ifdef CONFIG_DMB_TRAP
+		/* Third (and last) part of PIRANHA BUG */
+		if (piranha_bad_128k) {
+			/* region from +1408K to +1536 is un-usable. */
+
+			int idx_start = (1408*1024/sizeof(u64)) >> 3;
+			int idx_end   = (1536*1024/sizeof(u64)) >> 3;
+			long *p_start = (long *) &(sba_dev->ioc[i].res_map[idx_start]);
+			long *p_end   = (long *) &(sba_dev->ioc[i].res_map[idx_end]);
+
+			/* mark that part of the io pdir busy */
+			while (p_start < p_end)
+				*p_start++ = -1;
+				
+		}
+
+#ifdef DEBUG_DMB_TRAP
 		iterate_pages( sba_dev->ioc[i].res_map, res_size,
 				set_data_memory_break, 0);
 		iterate_pages( sba_dev->ioc[i].pdir_base, sba_dev->ioc[i].pdir_size,
 				set_data_memory_break, 0);
 #endif
 
-		DBG_INIT("sba_common_init() %d res_map %x %p\n",
-					i, res_size, sba_dev->ioc[i].res_map);
+		DBG_INIT("%s() %d res_map %x %p\n",
+			__FUNCTION__, i, res_size, sba_dev->ioc[i].res_map);
 	}
 
 	sba_dev->sba_lock = SPIN_LOCK_UNLOCKED;
+	ioc_needs_fdc = boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC;
+
+#ifdef DEBUG_SBA_INIT
+	/*
+	 * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set
+	 * (bit #61, big endian), we have to flush and sync every time
+	 * IO-PDIR is changed in Ike/Astro.
+	 */
+	if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) {
+		printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n");
+	} else {
+		printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n");
+	}
+#endif
 }
 
 #ifdef CONFIG_PROC_FS
 static int sba_proc_info(char *buf, char **start, off_t offset, int len)
 {
 	struct sba_device *sba_dev = sba_list;
-/* FIXME: Multi-IOC support broken! */
-	struct ioc *ioc = &sba_dev->ioc[0];
+	struct ioc *ioc = &sba_dev->ioc[0];	/* FIXME: Multi-IOC support! */
 	int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
 	unsigned long i = 0, avg = 0, min, max;
 
 	sprintf(buf, "%s rev %d.%d\n",
-		parisc_getHWdescription(sba_dev->iodc->hw_type,
-			sba_dev->iodc->hversion, sba_dev->iodc->sversion),
+		sba_dev->name,
 		(sba_dev->hw_rev & 0x7) + 1,
 		(sba_dev->hw_rev & 0x18) >> 3
 		);
 	sprintf(buf, "%sIO PDIR size    : %d bytes (%d entries)\n",
 		buf,
-		((ioc->res_size << 3) * sizeof(u64)), /* 8 bits per byte */
-		total_pages);                  /* 8 bits per byte */
+		(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
+		total_pages);
 
 	sprintf(buf, "%sIO PDIR entries : %ld free  %ld used (%d%%)\n", buf,
 		total_pages - ioc->used_pages, ioc->used_pages,
@@ -1645,46 +1858,72 @@
 	sprintf(buf, "%s  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
 		buf, min, avg, max);
 
-	sprintf(buf, "%spci_map_single(): %8ld calls  %8ld pages (avg %d/1000)\n",
+	sprintf(buf, "%spci_map_single(): %12ld calls  %12ld pages (avg %d/1000)\n",
 		buf, ioc->msingle_calls, ioc->msingle_pages,
 		(int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
 
 	/* KLUGE - unmap_sg calls unmap_single for each mapped page */
-	min = ioc->usingle_calls - ioc->usg_calls;
+	min = ioc->usingle_calls;
 	max = ioc->usingle_pages - ioc->usg_pages;
-	sprintf(buf, "%spci_unmap_single: %8ld calls  %8ld pages (avg %d/1000)\n",
+	sprintf(buf, "%spci_unmap_single: %12ld calls  %12ld pages (avg %d/1000)\n",
 		buf, min, max,
 		(int) ((max * 1000)/min));
 
-	sprintf(buf, "%spci_map_sg()    : %8ld calls  %8ld pages (avg %d/1000)\n",
+	sprintf(buf, "%spci_map_sg()    : %12ld calls  %12ld pages (avg %d/1000)\n",
 		buf, ioc->msg_calls, ioc->msg_pages,
 		(int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
 
-	sprintf(buf, "%spci_unmap_sg()  : %8ld calls  %8ld pages (avg %d/1000)\n",
+	sprintf(buf, "%spci_unmap_sg()  : %12ld calls  %12ld pages (avg %d/1000)\n",
 		buf, ioc->usg_calls, ioc->usg_pages,
 		(int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
 
 	return strlen(buf);
 }
 
+#if 0
+/* XXX too much output - exceeds 4k limit and needs to be re-written */
 static int
 sba_resource_map(char *buf, char **start, off_t offset, int len)
 {
 	struct sba_device *sba_dev = sba_list;
-	struct ioc *ioc = &sba_dev->ioc[0];
-	unsigned long *res_ptr = (unsigned long *)ioc->res_map;
+	struct ioc *ioc = &sba_dev->ioc[0];	/* FIXME: Mutli-IOC suppoer! */
+	unsigned int *res_ptr = (unsigned int *)ioc->res_map;
 	int i;
 
-	for(i = 0; i < (ioc->res_size / sizeof(unsigned long)); ++i, ++res_ptr) {
+	buf[0] = '\0';
+	for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) {
 		if ((i & 7) == 0)
 		    strcat(buf,"\n   ");
-		sprintf(buf, "%s %08lx", buf, *res_ptr);
+		sprintf(buf, "%s %08x", buf, *res_ptr);
 	}
 	strcat(buf, "\n");
 
 	return strlen(buf);
 }
-#endif
+#endif /* 0 */
+#endif /* CONFIG_PROC_FS */
+
+static struct parisc_device_id sba_tbl[] = {
+	{ HPHW_IOA, HVERSION_REV_ANY_ID, ASTRO_RUNWAY_PORT, 0xb },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_MERCED_PORT, 0xc },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REO_MERCED_PORT, 0xc },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REOG_MERCED_PORT, 0xc },
+/* These two entries commented out because we don't find them in a
+ * buswalk yet.  If/when we do, they would cause us to think we had
+ * many more SBAs then we really do.
+ *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, ASTRO_ROPES_PORT, 0xc },
+ *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_ROPES_PORT, 0xc },
+ */
+	{ 0, }
+};
+
+int sba_driver_callback(struct parisc_device *);
+
+static struct parisc_driver sba_driver = {
+	name:		MODULE_NAME,
+	id_table:	sba_tbl,
+	probe:		sba_driver_callback,
+};
 
 /*
 ** Determine if lba should claim this chip (return 0) or not (return 1).
@@ -1692,47 +1931,75 @@
 ** have work to do.
 */
 int
-sba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+sba_driver_callback(struct parisc_device *dev)
 {
 	struct sba_device *sba_dev;
 	u32 func_class;
 	int i;
+	char *version;
 
-	if (IS_ASTRO(d)) {
+#ifdef DEBUG_SBA_INIT
+	sba_dump_ranges(dev->hpa);
+#endif
+
+	/* Read HW Rev First */
+	func_class = READ_REG(dev->hpa + SBA_FCLASS);
+
+	if (IS_ASTRO(&dev->id)) {
+		unsigned long fclass;
 		static char astro_rev[]="Astro ?.?";
 
-		/* Read HW Rev First */
-		func_class = READ_REG32(d->hpa);
+		/* Astro is broken...Read HW Rev First */
+		fclass = READ_REG(dev->hpa);
 
-		astro_rev[6] = '1' + (char) (func_class & 0x7);
-		astro_rev[8] = '0' + (char) ((func_class & 0x18) >> 3);
-		dri->version = astro_rev;
-	} else {
-		static char ike_rev[]="Ike rev ?";
+		astro_rev[6] = '1' + (char) (fclass & 0x7);
+		astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
+		version = astro_rev;
 
-		/* Read HW Rev First */
-		func_class = READ_REG32(d->hpa + SBA_FCLASS);
+	} else if (IS_IKE(&dev->id)) {
+		static char ike_rev[]="Ike rev ?";
 
 		ike_rev[8] = '0' + (char) (func_class & 0xff);
-		dri->version = ike_rev;
+		version = ike_rev;
+	} else {
+		static char reo_rev[]="REO rev ?";
+
+		reo_rev[8] = '0' + (char) (func_class & 0xff);
+		version = reo_rev;
+	}
+
+	if (!global_ioc_cnt) {
+		global_ioc_cnt = count_parisc_driver(&sba_driver);
+
+		/* Only Astro has one IOC per SBA */
+		if (!IS_ASTRO(&dev->id))
+			global_ioc_cnt *= 2;
 	}
 
-	printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa);
+	printk(KERN_INFO "%s found %s at 0x%lx\n",
+		MODULE_NAME, version, dev->hpa);
+
+#ifdef DEBUG_SBA_INIT
+	sba_dump_tlb(dev->hpa);
+#endif
 
 	sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
-	if (NULL == sba_dev)
-	{
-		printk(MODULE_NAME " - couldn't alloc sba_device\n");
+	if (NULL == sba_dev) {
+		printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n");
 		return(1);
 	}
+
+	dev->sysdata = (void *) sba_dev;
 	memset(sba_dev, 0, sizeof(struct sba_device));
+
 	for(i=0; i<MAX_IOC; i++)
 		spin_lock_init(&(sba_dev->ioc[i].res_lock));
 
-
+	sba_dev->dev = dev;
 	sba_dev->hw_rev = func_class;
-	sba_dev->iodc = d;
-	sba_dev->sba_hpa = d->hpa;  /* faster access */
+	sba_dev->iodc = &dev->id;
+	sba_dev->name = dev->name;
+	sba_dev->sba_hpa = dev->hpa;  /* faster access */
 
 	sba_get_pat_resources(sba_dev);
 	sba_hw_init(sba_dev);
@@ -1741,12 +2008,46 @@
 	hppa_dma_ops = &sba_ops;
 
 #ifdef CONFIG_PROC_FS
-	if (IS_ASTRO(d)) {
+	if (IS_ASTRO(&dev->id)) {
 		create_proc_info_entry("Astro", 0, proc_runway_root, sba_proc_info);
-	} else {
+	} else if (IS_IKE(&dev->id)) {
 		create_proc_info_entry("Ike", 0, proc_runway_root, sba_proc_info);
+	} else {
+		create_proc_info_entry("Reo", 0, proc_runway_root, sba_proc_info);
 	}
+#if 0
 	create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map);
 #endif
+#endif
 	return 0;
 }
+
+/*
+** One time initialization to let the world know the SBA was found.
+** This is the only routine which is NOT static.
+** Must be called exactly once before pci_init().
+*/
+void __init sba_init(void)
+{
+	register_parisc_driver(&sba_driver);
+}
+
+
+/**
+ * sba_get_iommu - Assign the iommu pointer for the pci bus controller.
+ * @dev: The parisc device.
+ *
+ * This function searches through the registerd IOMMU's and returns the
+ * appropriate IOMMU data for the given parisc PCI controller.
+ */
+void * sba_get_iommu(struct parisc_device *pci_hba)
+{
+	struct sba_device *sba = (struct sba_device *) pci_hba->parent->sysdata;
+	char t = pci_hba->parent->id.hw_type;
+	int iocnum = (pci_hba->hw_path >> 3);	/* rope # */
+
+	if ((t!=HPHW_IOA) && (t!=HPHW_BCPORT))
+		BUG();
+
+	return &(sba->ioc[iocnum]);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/semaphore.c linux-2.4.20-pre2/arch/parisc/kernel/semaphore.c
--- linux-2.4.20-pre1/arch/parisc/kernel/semaphore.c	Tue Apr 17 17:19:25 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/semaphore.c	Mon Aug 12 16:34:14 2002
@@ -1,131 +1,100 @@
 /*
- * Just taken from alpha implementation.
- * This can't work well, perhaps.
- */
-/*
- *  Generic semaphore code. Buyer beware. Do your own
- * specific changes in <asm/semaphore-helper.h>
+ * Semaphore implementation Copyright (c) 2001 Matthew Wilcox, Hewlett-Packard
  */
 
 #include <linux/sched.h>
-#include <asm/semaphore-helper.h>
+#include <linux/spinlock.h>
 
 /*
- * Semaphores are implemented using a two-way counter:
- * The "count" variable is decremented for each process
- * that tries to sleep, while the "waking" variable is
- * incremented when the "up()" code goes to wake up waiting
- * processes.
- *
- * Notably, the inline "up()" and "down()" functions can
- * efficiently test if they need to do any extra work (up
- * needs to do something only if count was negative before
- * the increment operation.
- *
- * waking_non_zero() (from asm/semaphore.h) must execute
- * atomically.
- *
- * When __up() is called, the count was negative before
- * incrementing it, and we need to wake up somebody.
- *
- * This routine adds one to the count of processes that need to
- * wake up and exit.  ALL waiting processes actually wake up but
- * only the one that gets to the "waking" field first will gate
- * through and acquire the semaphore.  The others will go back
- * to sleep.
- *
- * Note that these functions are only called when there is
- * contention on the lock, and as such all this is the
- * "non-critical" part of the whole semaphore business. The
- * critical part is the inline stuff in <asm/semaphore.h>
- * where we want to avoid any extra jumps and calls.
+ * Semaphores are complex as we wish to avoid using two variables.
+ * `count' has multiple roles, depending on its value.  If it is positive
+ * or zero, there are no waiters.  The functions here will never be
+ * called; see <asm/semaphore.h>
+ *
+ * When count is -1 it indicates there is at least one task waiting
+ * for the semaphore.
+ *
+ * When count is less than that, there are '- count - 1' wakeups
+ * pending.  ie if it has value -3, there are 2 wakeups pending.
+ *
+ * Note that these functions are only called when there is contention
+ * on the lock, and as such all this is the "non-critical" part of the
+ * whole semaphore business. The critical part is the inline stuff in
+ * <asm/semaphore.h> where we want to avoid any extra jumps and calls.
  */
 void __up(struct semaphore *sem)
 {
-	wake_one_more(sem);
+	sem->count--;
 	wake_up(&sem->wait);
 }
 
-/*
- * Perform the "down" function.  Return zero for semaphore acquired,
- * return negative for signalled out of the function.
- *
- * If called from __down, the return is ignored and the wait loop is
- * not interruptible.  This means that a task waiting on a semaphore
- * using "down()" cannot be killed until someone does an "up()" on
- * the semaphore.
- *
- * If called from __down_interruptible, the return value gets checked
- * upon return.  If the return value is negative then the task continues
- * with the negative value in the return register (it can be tested by
- * the caller).
- *
- * Either form may be used in conjunction with "up()".
- *
- */
-
+#define wakers(count) (-1 - count)
 
-#define DOWN_HEAD(task_state)						\
+#define DOWN_HEAD							\
+	int ret = 0;							\
+	DECLARE_WAITQUEUE(wait, current);				\
 									\
+	/* Note that someone is waiting */				\
+	if (sem->count == 0)						\
+		sem->count = -1;					\
 									\
-	current->state = (task_state);					\
-	add_wait_queue(&sem->wait, &wait);				\
-									\
-	/*								\
-	 * Ok, we're set up.  sem->count is known to be less than zero	\
-	 * so we must wait.						\
-	 *								\
-	 * We can let go the lock for purposes of waiting.		\
-	 * We re-acquire it after awaking so as to protect		\
-	 * all semaphore operations.					\
-	 *								\
-	 * If "up()" is called before we call waking_non_zero() then	\
-	 * we will catch it right away.  If it is called later then	\
-	 * we will have to go through a wakeup cycle to catch it.	\
-	 *								\
-	 * Multiple waiters contend for the semaphore lock to see	\
-	 * who gets to gate through and who has to wait some more.	\
-	 */								\
-	for (;;) {
-
-#define DOWN_TAIL(task_state)			\
-		current->state = (task_state);	\
-	}					\
-	current->state = TASK_RUNNING;		\
-	remove_wait_queue(&sem->wait, &wait);
+	/* protected by the sentry still -- use unlocked version */	\
+	wait.flags = WQ_FLAG_EXCLUSIVE;					\
+	__add_wait_queue_tail(&sem->wait, &wait);			\
+ lost_race:								\
+	spin_unlock_irq(&sem->sentry);					\
+
+#define DOWN_TAIL							\
+	spin_lock_irq(&sem->sentry);					\
+	if (wakers(sem->count) == 0 && ret == 0)			\
+		goto lost_race;	/* Someone stole our wakeup */		\
+	__remove_wait_queue(&sem->wait, &wait);				\
+	current->state = TASK_RUNNING;					\
+	if (!waitqueue_active(&sem->wait) && (sem->count < 0))		\
+		sem->count = wakers(sem->count);
+
+#define UPDATE_COUNT							\
+	sem->count += (sem->count < 0) ? 1 : - 1;
+	
 
 void __down(struct semaphore * sem)
 {
-	DECLARE_WAITQUEUE(wait, current);
+	DOWN_HEAD
+
+	for(;;) {
+		set_task_state(current, TASK_UNINTERRUPTIBLE);
+		/* we can _read_ this without the sentry */
+		if (sem->count != -1)
+			break;
+ 		schedule();
+ 	}
 
-	DOWN_HEAD(TASK_UNINTERRUPTIBLE)
-	if (waking_non_zero(sem))
-		break;
-	schedule();
-	DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+	DOWN_TAIL
+	UPDATE_COUNT
 }
 
 int __down_interruptible(struct semaphore * sem)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	int ret = 0;
+	DOWN_HEAD
 
-	DOWN_HEAD(TASK_INTERRUPTIBLE)
+	for(;;) {
+		set_task_state(current, TASK_INTERRUPTIBLE);
+		/* we can _read_ this without the sentry */
+		if (sem->count != -1)
+			break;
+
+		if (signal_pending(current)) {
+			ret = -EINTR;
+			break;
+		}
+		schedule();
+	}
 
-	ret = waking_non_zero_interruptible(sem, current);
-	if (ret)
-	{
-		if (ret == 1)
-			/* ret != 0 only if we get interrupted -arca */
-			ret = 0;
-		break;
+	DOWN_TAIL
+
+	if (!ret) {
+		UPDATE_COUNT
 	}
-	schedule();
-	DOWN_TAIL(TASK_INTERRUPTIBLE)
-	return ret;
-}
 
-int __down_trylock(struct semaphore * sem)
-{
-	return waking_non_zero_trylock(sem);
+	return ret;
 }
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/setup.c linux-2.4.20-pre2/arch/parisc/kernel/setup.c
--- linux-2.4.20-pre1/arch/parisc/kernel/setup.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/setup.c	Mon Aug 12 16:34:14 2002
@@ -1,12 +1,13 @@
 /*    $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $
  *
  *    Initial setup-routines for HP 9000 based hardware.
- * 
+ *
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *    Modifications for PA-RISC (C) 1999 Helge Deller <helge.deller@ruhr-uni-bochum.de>
+ *    Modifications for PA-RISC (C) 1999 Helge Deller <deller@gmx.de>
  *    Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
  *    Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
  *    Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ *    Modifications copyright 2001 Ryan Bradetich <rbradetich@uswest.net>
  *
  *    Initial PA-RISC Version: 04-23-1999 by Helge Deller
  *
@@ -19,596 +20,308 @@
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    GNU General Public License for more details.
- * 
+ *
  *    You should have received a copy of the GNU General Public License
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
 
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/ptrace.h>
-#include <linux/sched.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/user.h>
-#include <linux/tty.h>
 #include <linux/config.h>
-#include <linux/fs.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/blk.h>          /* for initrd_start and initrd_end */
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/console.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
+#include <linux/seq_file.h>
+#define PCI_DEBUG
 #include <linux/pci.h>
-#include <linux/threads.h>
+#undef PCI_DEBUG
+#include <linux/proc_fs.h>
 
-#include <asm/cache.h>
-#include <asm/hardware.h>	/* for register_driver() stuff */
 #include <asm/processor.h>
-#include <asm/page.h>
 #include <asm/pdc.h>
 #include <asm/led.h>
-#include <asm/real.h>
-#include <asm/system.h>
 #include <asm/machdep.h>	/* for pa7300lc_init() proto */
 
-#include <asm/irq.h>		/* for struct irq_region */
-#include <asm/pdcpat.h>		/* for PA_VIEW PDC_PAT_CPU_GET_NUMBER etc */
-
-#include <linux/proc_fs.h>
-
 #define COMMAND_LINE_SIZE 1024
 char	saved_command_line[COMMAND_LINE_SIZE];
+char	command_line[COMMAND_LINE_SIZE];
 
-/*
-** KLUGE ALERT!
-**
-** We *really* should be using a combination of request_resource()
-** and request_region()! But request_region() requires kmalloc since
-** returns a new struct resource. And kmalloc just isn't available
-** until after mem_init() is called from start_kernel().
-**
-** FIXME: assume contiguous memory initially.
-**     Additional chunks of memory might be added to sysram_resource.sibling.
-*/
-static struct resource sysrom_resource  = {
-	name: "System ROM", start: 0x0f0000000UL, end: 0x0f00fffffUL,
-	flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-	parent: &iomem_resource, sibling: NULL, child: NULL };
-
-static struct resource pdcdata_resource;
-
-static struct resource sysram_resource  = {
-	name: "System RAM", start: 0UL, end: ~0UL /* bogus */,
-	flags: IORESOURCE_MEM,
-	parent: &iomem_resource, sibling: &sysrom_resource, child: &pdcdata_resource};
-
-extern char _text;	/* start of kernel code, defined by linker */
-extern int  data_start; 
-extern char _edata;	/* end of data, begin BSS, defined by linker */
-extern char _end;	/* end of BSS, defined by linker */
-
-static struct resource data_resource    = {
-	name: "kernel Data", start: virt_to_phys(&data_start), end: virt_to_phys(&_end)-1,
-	flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-	parent: &sysram_resource, sibling: NULL, child: NULL};
-
-static struct resource code_resource = {
-	name: "Kernel Code", start: virt_to_phys(&_text), end: virt_to_phys(&data_start)-1,
-	flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-	parent: &sysram_resource, sibling: &data_resource, child: NULL};
-
-static struct resource pdcdata_resource = {
-	name: "PDC data (Page Zero)", start: 0, end: 0x9ff,
-	flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-	parent: &sysram_resource, sibling: &code_resource, child: NULL};
-
-
+/* Intended for ccio/sba/cpu statistics under /proc/bus/{runway|gsc} */
+struct proc_dir_entry * proc_runway_root = NULL;
+struct proc_dir_entry * proc_gsc_root = NULL;
 
+#ifdef CONFIG_EISA
+int EISA_bus;	/* This has to go somewhere in architecture specific code. */
+#endif
 
-struct system_cpuinfo_parisc boot_cpu_data;
-struct cpuinfo_parisc cpu_data[NR_CPUS];
-
-extern void do_inventory(void);
-extern void cache_init(void);
-extern struct hp_device * register_module(void *hpa);
-
-static int cpu_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-static struct pa_iodc_driver cpu_drivers_for[] = {
-	{HPHW_NPROC, 0x0, 0x0, 0x0, 0, 0,
-		DRIVER_CHECK_HWTYPE,
-		"CPU", "PARISC", (void *) cpu_driver_callback},
-	{0,0,0,0,0,0,
-		0,
-		(char *) NULL, (char *) NULL, (void *) NULL }
-};
+void __init setup_cmdline(char **cmdline_p)
+{
+	extern unsigned int boot_args[];
 
-static long fallback_cpu_hpa[] = { 0xfffa0000L, 0xfffbe000L, 0x0 };
+	/* Collect stuff passed in from the boot loader */
 
+	/* boot_args[0] is free-mem start, boot_args[1] is ptr to command line */
+	if (boot_args[0] < 64) {
+		/* called from hpux boot loader */
+		saved_command_line[0] = '\0';
+	} else {
+		strcpy(saved_command_line, (char *)__va(boot_args[1]));
 
-/*
-**  	PARISC CPU driver - claim "device" and initialize CPU data structures.
-**
-** Consolidate per CPU initialization into (mostly) one module.
-** Monarch CPU will initialize boot_cpu_data which shouldn't
-** change once the system has booted.
-**
-** The callback *should* do per-instance initialization of
-** everything including the monarch. Some of the code that's
-** in setup.c:start_parisc() should migrate here and start_parisc()
-** should "register_driver(cpu_driver_for)" before calling
-** do_inventory().
-**
-** The goal of consolidating CPU initialization into one place is
-** to make sure all CPU's get initialized the same way.
-** It would be nice if the even the manarch through the exact same code path.
-** (up to rendevous at least).
-*/
-#undef ASSERT
-#define ASSERT(expr) \
-	if(!(expr)) { \
-		printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
-		panic(#expr); \
+#ifdef CONFIG_BLK_DEV_INITRD
+		if (boot_args[2] != 0) /* did palo pass us a ramdisk? */
+		{
+		    initrd_start = (unsigned long)__va(boot_args[2]);
+		    initrd_end = (unsigned long)__va(boot_args[3]);
+		}
+#endif
 	}
 
-static int
-cpu_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+	strcpy(command_line, saved_command_line);
+	*cmdline_p = command_line;
+}
+
+#ifdef CONFIG_PA11
+void __init dma_ops_init(void)
 {
-#ifdef __LP64__
-	extern int pdc_pat;	/* arch/parisc/kernel/inventory.c */
-	static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
-#endif
-	struct cpuinfo_parisc *p;
+	switch (boot_cpu_data.cpu_type) {
+	case pcx:
+		/*
+		 * We've got way too many dependencies on 1.1 semantics
+		 * to support 1.0 boxes at this point.
+		 */
+		panic(	"PA-RISC Linux currently only supports machines that conform to\n"
+			"the PA-RISC 1.1 or 2.0 architecture specification.\n");
 
-#ifndef CONFIG_SMP
-	if (boot_cpu_data.cpu_count > 0) {
-		printk(KERN_INFO "CONFIG_SMP disabled - not claiming addional CPUs\n");
-		return(1);
+	case pcxs:
+	case pcxt:
+		hppa_dma_ops = &pcx_dma_ops;
+		break;
+	case pcxl2:
+		pa7300lc_init();
+	case pcxl: /* falls through */
+		hppa_dma_ops = &pcxl_dma_ops;
+		break;
+	default:
+		break;
 	}
+}
 #endif
 
-	p = &cpu_data[boot_cpu_data.cpu_count];
-	boot_cpu_data.cpu_count++;
-
-/* TODO: Enable FP regs - done early in start_parisc() now */
-
-	/* initialize counters */
-	memset(p, 0, sizeof(struct cpuinfo_parisc));
+extern int init_per_cpu(int cpuid);
+extern void collect_boot_cpu_data(void);
 
-	p->hpa = (unsigned long) d->hpa; /* save CPU hpa */
+void __init setup_arch(char **cmdline_p)
+{
+	init_per_cpu(smp_processor_id());	/* Set Modes & Enable FP */
 
 #ifdef __LP64__
-	if (pdc_pat) {
-		ulong status;
-	        pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
-
-		status = pdc_pat_cell_module(& pdc_result, d->pcell_loc,
-			d->mod_index, PA_VIEW, & pa_pdc_cell);
-
-		ASSERT(PDC_RET_OK == status);
-
-		/* verify it's the same as what do_pat_inventory() found */
-		ASSERT(d->mod_info == pa_pdc_cell.mod_info);
-		ASSERT(d->pmod_loc == pa_pdc_cell.mod_location);
-		ASSERT(d->mod_path == pa_pdc_cell.mod_path);
-
-		p->txn_addr = pa_pdc_cell.mod[0];   /* id_eid for IO sapic */
-
-		/* get the cpu number */
-		status = mem_pdc_call( PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
-				__pa(& pdc_result), d->hpa);
+	printk(KERN_INFO "The 64-bit Kernel has started...\n");
+#else
+	printk(KERN_INFO "The 32-bit Kernel has started...\n");
+#endif
 
-		ASSERT(PDC_RET_OK == status);
+	pdc_console_init();
 
-		p->cpuid = pdc_result[0];
+#ifdef CONFIG_PDC_NARROW
+	printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
+#endif
+	setup_pdc();
+	setup_cmdline(cmdline_p);
+	collect_boot_cpu_data();
+	do_memory_inventory();  /* probe for physical memory */
+	cache_init();
+	paging_init();
 
-	} else
+#ifdef CONFIG_CHASSIS_LCD_LED
+	/* initialize the LCD/LED after boot_cpu_data is available ! */
+        led_init();				/* LCD/LED initialization */
 #endif
-	{
-		p->txn_addr = (unsigned long) d->hpa;	/* for normal parisc */
 
-		/* logical CPU ID and update global counter */
-		p->cpuid = boot_cpu_data.cpu_count - 1;
-	}
+#ifdef CONFIG_PA11
+	dma_ops_init();
+#endif
 
-	/*
-	** itimer and ipi IRQ handlers are statically initialized in
-	** arch/parisc/kernel/irq.c
-	*/
-	p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+#ifdef CONFIG_VT
+# if defined(CONFIG_STI_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+        conswitchp = &dummy_con;        /* we use take_over_console() later ! */
+# endif
+#endif
 
-	return(0);
 }
 
+/*
+ * Display cpu info for all cpu's.
+ * for parisc this is in processor.c
+ */
+extern int show_cpuinfo (struct seq_file *m, void *v);
 
-void __xchg_called_with_bad_pointer(void)
+static void *
+c_start (struct seq_file *m, loff_t *pos)
 {
-    printk(KERN_EMERG "xchg() called with bad pointer !\n");
+    	/* Looks like the caller will call repeatedly until we return
+	 * 0, signaling EOF perhaps.  This could be used to sequence
+	 * through CPUs for example.  Since we print all cpu info in our
+	 * show_cpuinfo() disregarding 'pos' (which I assume is 'v' above)
+	 * we only allow for one "position".  */
+	return ((long)*pos < 1) ? (void *)1 : NULL;
 }
 
-
-/* Some versions of IODC don't list the CPU, and since we don't walk
- * the bus yet, we have to probe for processors at well known hpa
- * addresses.  
- */
-
-void __init register_fallback_cpu (void)
+static void *
+c_next (struct seq_file *m, void *v, loff_t *pos)
 {
-	struct hp_device *d = NULL;
-	int i = 0;
-	
-#ifdef CONFIG_SMP
-#error "Revisit CPU fallback addresses for SMP (Assuming bus walk hasn't been implemented)"
-#endif
-	printk ("No CPUs reported by firmware - probing...\n");
-	
-	while (fallback_cpu_hpa[i]) {
-		
-		d = register_module ((void *) fallback_cpu_hpa[i]);
-		
-		if (d > 0) {
-			printk ("Found CPU at %lx\n", fallback_cpu_hpa[i]);
-			cpu_driver_callback (d, 0);
-			return;
-		}
-		
-		i++;
-	}
-	
-	panic ("No CPUs found.  System halted.\n");
-	return;
+	++*pos;
+	return c_start(m, pos);
 }
 
-
-/*
- * Get CPU information and store it in the boot_cpu_data structure.  */
-void __init collect_boot_cpu_data(void)
+static void
+c_stop (struct seq_file *m, void *v)
 {
-	memset(&boot_cpu_data,0,sizeof(boot_cpu_data));
-
-	boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
-
-	/* get CPU-Model Information... */
-#define p ((unsigned long *)&boot_cpu_data.pdc.model)
-	if(pdc_model_info(&boot_cpu_data.pdc.model)==0)
-		printk("model	%08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
-#undef p
-
-	if(pdc_model_versions(&boot_cpu_data.pdc.versions, 0)==0)
-		printk("vers	%08lx\n", boot_cpu_data.pdc.versions.cpuid);
-
-	if(pdc_model_cpuid(&boot_cpu_data.pdc.cpuid)==0)
-		printk("cpuid	%08lx\n", boot_cpu_data.pdc.cpuid.cpuid);
-	
-	printk("CPUID	vers %ld rev %ld\n",
-		(boot_cpu_data.pdc.cpuid.cpuid >> 5) & 127,
-		boot_cpu_data.pdc.cpuid.cpuid & 31);
-
-	if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name)==0)
-		printk("model	%s\n",boot_cpu_data.pdc.sys_model_name);
-
-	boot_cpu_data.model_name = parisc_getHWdescription(HPHW_NPROC,
-		boot_cpu_data.pdc.model.hversion>>4,
-		boot_cpu_data.pdc.model.sversion>>8);
-	
-	boot_cpu_data.hversion =  boot_cpu_data.pdc.model.hversion;
-	boot_cpu_data.sversion =  boot_cpu_data.pdc.model.sversion;
-
-	boot_cpu_data.cpu_type =
-			parisc_get_cpu_type(boot_cpu_data.pdc.model.hversion);
-
-	boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
-	boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
 }
 
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo
+};
 
-#ifdef __LP64__
-#define COMMAND_GLOBAL  0xfffffffffffe0030UL
-#else
-#define COMMAND_GLOBAL  0xfffe0030
-#endif
-
-#define CMD_RESET       5       /* reset any module */
-
-/*
-** The Wright Brothers and Gecko systems have a H/W problem
-** (Lasi...'nuf said) may cause a broadcast reset to lockup
-** the system. An HVERSION dependent PDC call was developed
-** to perform a "safe", platform specific broadcast reset instead
-** of kludging up all the code.
-**
-** Older machines which do not implement PDC_BROADCAST_RESET will
-** return (with an error) and the regular broadcast reset can be
-** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
-** the PDC call will not return (the system will be reset).
-*/
-static int
-reset_parisc(struct notifier_block *self, unsigned long command, void *ptr)
+static void parisc_proc_mkdir(void)
 {
-	printk("%s: %s(cmd=%lu)\n", __FILE__, __FUNCTION__, command);
-
-	switch(command) {
-	case MACH_RESTART:
-#ifdef FASTBOOT_SELFTEST_SUPPORT
-		/*
-		** If user has modified the Firmware Selftest Bitmap,
-		** run the tests specified in the bitmap after the
-		** system is rebooted w/PDC_DO_RESET.
-		**
-		** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
-		**
-		** Using "directed resets" at each processor with the MEM_TOC
-		** vector cleared will also avoid running destructive
-		** memory self tests. (Not implemented yet)
-		*/
-		if (ftc_bitmap) {
-			mem_pdc_call( PDC_BROADCAST_RESET,
-				PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC,
-				ftc_bitmap);
+	/*
+	** Can't call proc_mkdir() until after proc_root_init() has been
+	** called by start_kernel(). In other words, this code can't
+	** live in arch/.../setup.c because start_parisc() calls
+	** start_kernel().
+	*/
+	switch (boot_cpu_data.cpu_type) {
+	case pcxl:
+	case pcxl2:
+		if (NULL == proc_gsc_root)
+		{
+			proc_gsc_root = proc_mkdir("bus/gsc", 0);
 		}
-#endif
-
-		/* "Normal" system reset */
-		(void) mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET,
-			0L, 0L, 0L);
-
-		/* Nope...box should reset with just CMD_RESET now */
-		gsc_writel(CMD_RESET, COMMAND_GLOBAL);
-
-		/* Wait for RESET to lay us to rest. */
-		while (1) ;
-
 		break;
+        case pcxt_:
+        case pcxu:
+        case pcxu_:
+        case pcxw:
+        case pcxw_:
+        case pcxw2:
+                if (NULL == proc_runway_root)
+                {
+                        proc_runway_root = proc_mkdir("bus/runway", 0);
+                }
+                break;
 	}
-	return NOTIFY_DONE;
 }
 
-static struct notifier_block parisc_block = { reset_parisc, NULL, 0 };
+static struct resource central_bus = {
+	name:	"Central Bus",
+	start:	(unsigned long)0xfffffffffff80000,
+	end:    (unsigned long)0xfffffffffffaffff,
+	flags:	IORESOURCE_MEM,
+};
 
+static struct resource local_broadcast = {
+	name:	"Local Broadcast",
+	start:	(unsigned long)0xfffffffffffb0000,
+	end:	(unsigned long)0xfffffffffffdffff,
+	flags:	IORESOURCE_MEM,
+};
 
-/*  start_parisc() will be called from head.S to setup our new memory_start 
-    and actually start our kernel !
-    Memory-Layout is:
-	- Kernel-Image (code+data+BSS)
-	- Stack (stack-size see below!, stack-setup-code is in head.S)
-	- memory_start at end of stack..
-*/
-
-unsigned long mem_start, mem_max;
-unsigned long start_pfn, max_pfn;
-extern asmlinkage void __init start_kernel(void);
-
-#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+static struct resource global_broadcast = {
+	name:	"Global Broadcast",
+	start:	(unsigned long)0xfffffffffffe0000,
+	end:	(unsigned long)0xffffffffffffffff,
+	flags:	IORESOURCE_MEM,
+};
 
-void __init start_parisc(unsigned arg0, unsigned arg1,
-			 unsigned arg2, unsigned arg3)
+int __init parisc_init_resources(void)
 {
-	register unsigned long ccr;
-	unsigned long memory_start;
-
-	/* Clear BSS */
+	int result;
 
-	{
-		char *p = &_edata, *q = &_end;
-
-		while (p < q) {
-			*p++ = 0;
-		}
+	result = request_resource(&iomem_resource, &central_bus);
+	if (result < 0) {
+		printk(KERN_ERR 
+		       "%s: failed to claim %s address space!\n", 
+		       __FILE__, central_bus.name);
+		return result;
 	}
 
-
-	pdc_console_init();
-
-#ifdef __LP64__
-	printk("The 64-bit Kernel has started...\n");
-#else
-	printk("The 32-bit Kernel has started...\n");
-#endif
-
-	/*
-	** Enable FP coprocessor
-	**
-	** REVISIT: ccr should be set by PDC_COPROC results to support PA1.0.
-	** Hardcoding works for PA1.1 processors.
-	**
-	** REVISIT: this could be done in the "code 22" trap handler.
-	** (frowands idea - that way we know which processes need FP
-	** registers saved on the interrupt stack.)
-	**
-	** NEWS FLASH: wide kernels need FP coprocessor enabled to handle
-	** formatted printing of %lx for example (double divides I think)
-	*/
-	ccr = 0xc0;
-	mtctl(ccr, 10);
-	printk("Enabled FP coprocessor\n");
-
-#ifdef __LP64__
-	printk( "If this is the LAST MESSAGE YOU SEE, you're probably using\n"
-		"32-bit millicode by mistake.\n");
-#endif
-
-	memory_start = (unsigned long) &_end;
-	memory_start = (memory_start + PAGE_SIZE) & PAGE_MASK;
-	printk("Free memory starts at: 0x%lx\n", memory_start);
-
-	/* Collect stuff passed in from the boot loader */
-	printk(KERN_WARNING  "%s(0x%x,0x%x,0x%x,0x%x)\n", 
-		    __FUNCTION__, arg0, arg1, arg2, arg3);
-
-	/* arg0 is free-mem start, arg1 is ptr to command line */
-	if (arg0 < 64) {
-		/* called from hpux boot loader */
-		saved_command_line[0] = '\0';
-	} else {
-		strcpy(saved_command_line, (char *)__va(arg1));
-		printk("PALO command line: '%s'\nPALO initrd %x-%x\n",
-		    saved_command_line, arg2, arg3);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-		if (arg2 != 0) /* did palo pass us a ramdisk? */
-		{
-		    initrd_start = (unsigned long)__va(arg2);
-		    initrd_end = (unsigned long)__va(arg3);
-		}
-#endif
+	result = request_resource(&iomem_resource, &local_broadcast);
+	if (result < 0) {
+		printk(KERN_ERR 
+		       "%s: failed to claim %saddress space!\n", 
+		       __FILE__, local_broadcast.name);
+		return result;
 	}
 
-	mem_start = __pa(memory_start);
-#define MAX_MEM (512*1024*1024)
-	mem_max = (PAGE0->imm_max_mem > MAX_MEM ? MAX_MEM : PAGE0->imm_max_mem);
-
-	collect_boot_cpu_data();
+	result = request_resource(&iomem_resource, &global_broadcast);
+	if (result < 0) {
+		printk(KERN_ERR 
+		       "%s: failed to claim %s address space!\n", 
+		       __FILE__, global_broadcast.name);
+		return result;
+	}
 
-	/* initialize the LCD/LED after boot_cpu_data is available ! */
-        led_init();				/* LCD/LED initialization */
+	return 0;
+}
 
-	do_inventory();				/* probe for hardware */
-        register_driver(cpu_drivers_for);	/* claim all the CPUs */
+extern void gsc_init(void);
+extern void processor_init(void);
+extern void ccio_init(void);
+extern void dino_init(void);
+extern void iosapic_init(void);
+extern void lba_init(void);
+extern void sba_init(void);
+extern void eisa_init(void);
 
-	if (boot_cpu_data.cpu_count == 0)
-	    register_fallback_cpu();
+void __init parisc_init(void)
+{
+	parisc_proc_mkdir();
+	parisc_init_resources();
+	do_device_inventory();                  /* probe for hardware */
 
-	printk("CPU(s): %d x %s at %d.%06d MHz\n", 
+	processor_init();
+	printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n",
 			boot_cpu_data.cpu_count,
 			boot_cpu_data.cpu_name,
-			boot_cpu_data.cpu_hz / 1000000, 
+			boot_cpu_data.cpu_hz / 1000000,
 			boot_cpu_data.cpu_hz % 1000000	);
 
-	switch (boot_cpu_data.cpu_type) {
-	case pcx:
-	case pcxs:
-	case pcxt:
-		hppa_dma_ops = &pcx_dma_ops;
-		break;
-	case pcxl2:
-		pa7300lc_init();
-	case pcxl: /* falls through */
-		hppa_dma_ops = &pcxl_dma_ops;
-		break;
-	default:
-		break;
-	}
-
-#if 1
-	/* KLUGE! this really belongs in kernel/resource.c! */
-	iomem_resource.end = ~0UL;
-#endif
-	sysram_resource.end = mem_max - 1;
-	notifier_chain_register(&mach_notifier, &parisc_block);
-	start_kernel(); 	/* now back to arch-generic code... */
-}
-
-void __init setup_arch(char **cmdline_p)
-{
-	unsigned long bootmap_size;
-	unsigned long start_pfn;
-	unsigned long mem_free;
-
-	*cmdline_p = saved_command_line;
-
-	/* initialize bootmem */
-
-	start_pfn = PFN_UP(mem_start);
-	max_pfn = PFN_DOWN(mem_max);
-
-	bootmap_size = init_bootmem(start_pfn, max_pfn);
-
-	mem_start += bootmap_size;
-	mem_free = mem_max - mem_start;
-
-	/* free_bootmem handles rounding nicely */
-	printk("free_bootmem(0x%lx, 0x%lx)\n", (unsigned long)mem_start,
-			(unsigned long)mem_free);
-	free_bootmem(mem_start, mem_free);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	printk("initrd: %08x-%08x\n", (int) initrd_start, (int) initrd_end);
-
-	if (initrd_end != 0) {
-		initrd_below_start_ok = 1;
-		reserve_bootmem(__pa(initrd_start), initrd_end - initrd_start);
-	}
+	/* These are in a non-obvious order, will fix when we have an iotree */
+#if defined(CONFIG_IOSAPIC)
+	iosapic_init();
 #endif
-
-	cache_init();
-
-	paging_init();
-
-	if((unsigned long)&init_task_union&(INIT_TASK_SIZE - 1)) {
-		printk("init_task_union not aligned.  Please recompile the kernel after changing the first line in arch/parisc/kernel/init_task.c from \n\"#define PAD 0\" to\n\"#define PAD 1\" or vice versa\n");
-		for(;;);
-	}
-
-
-#ifdef CONFIG_SERIAL_CONSOLE
-	/* nothing */
-#elif CONFIG_VT
-#if   defined(CONFIG_STI_CONSOLE)
-	conswitchp = &dummy_con;	/* we use take_over_console() later ! */
-#elif defined(CONFIG_IODC_CONSOLE)
-	conswitchp = &prom_con;		/* it's currently really "prom_con" */
-#elif defined(CONFIG_DUMMY_CONSOLE)
-	conswitchp = &dummy_con;
+#if defined(CONFIG_IOMMU_SBA)
+	sba_init();
 #endif
+#if defined(CONFIG_PCI_LBA)
+	lba_init();
 #endif
 
-}
-
-#ifdef CONFIG_PROC_FS
-/*
- *	Get CPU information for use by procfs.
- */
-
-int get_cpuinfo(char *buffer)
-{
-	char		  *p = buffer;
-	int		  n;
+	/* CCIO before any potential subdevices */
+#if defined(CONFIG_IOMMU_CCIO)
+	ccio_init();
+#endif
 
-	for(n=0; n<boot_cpu_data.cpu_count; n++) {
-#ifdef CONFIG_SMP
-		if (!(cpu_online_map & (1<<n)))
-			continue;
-#endif
-		p += sprintf(p, "processor\t: %d\n"
-				"cpu family\t: PA-RISC %s\n",
-				n, boot_cpu_data.family_name);
-
-		p += sprintf(p, "cpu\t\t: %s\n",  boot_cpu_data.cpu_name );
-	
-		/* cpu MHz */
-		p += sprintf(p, "cpu MHz\t\t: %d.%06d\n",
-				 boot_cpu_data.cpu_hz / 1000000, 
-				 boot_cpu_data.cpu_hz % 1000000  );
-
-		p += sprintf(p, "model\t\t: %s\n"
-				"model name\t: %s\n",
-				boot_cpu_data.pdc.sys_model_name,
-				boot_cpu_data.model_name);
-
-		p += sprintf(p, "hversion\t: 0x%08x\n"
-			        "sversion\t: 0x%08x\n",
-				boot_cpu_data.hversion,
-				boot_cpu_data.sversion );
-
-		p += get_cache_info(p);
-		/* print cachesize info ? */
-		p += sprintf(p, "bogomips\t: %lu.%02lu\n",
-			     (loops_per_sec+2500)/500000,
-			     ((loops_per_sec+2500)/5000) % 100);
-	}
-	return p - buffer;
-}
+	/*
+	 * Need to register Asp & Wax before the EISA adapters for the IRQ
+	 * regions.  EISA must come before PCI to be sure it gets IRQ region
+	 * 0.
+	 */
+#if defined(CONFIG_GSC_LASI) || defined(CONFIG_GSC_WAX)
+	gsc_init();
+#endif
+#ifdef CONFIG_EISA
+	eisa_init();
+#endif
+#if defined(CONFIG_GSC_DINO)
+	dino_init();
 #endif
 
+#ifdef CONFIG_CHASSIS_LCD_LED
+	register_led_regions();	/* register LED port info in procfs */
+#endif
+}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/signal.c linux-2.4.20-pre2/arch/parisc/kernel/signal.c
--- linux-2.4.20-pre1/arch/parisc/kernel/signal.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/parisc/kernel/signal.c	Mon Aug 12 16:34:14 2002
@@ -26,20 +26,24 @@
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <asm/ucontext.h>
+#include <asm/rt_sigframe.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 
 #define DEBUG_SIG 0
 
+#if DEBUG_SIG
+#define DBG(x)	printk x
+#else
+#define DBG(x)
+#endif
+
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-extern long sys_wait4 (int, int *, int, struct rusage *);
 int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall);
 
 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 {
@@ -128,30 +132,15 @@
  * Do a signal return - restore sigcontext.
  */
 
-struct rt_sigframe {
-	unsigned int tramp[4];
-	struct siginfo info;
-	struct ucontext uc;
-};
-
 /* Trampoline for calling rt_sigreturn() */
 #define INSN_LDI_R25_0	 0x34190000 /* ldi  0,%r25 (in_syscall=0) */
 #define INSN_LDI_R25_1	 0x34190002 /* ldi  1,%r25 (in_syscall=1) */
 #define INSN_LDI_R20	 0x3414015a /* ldi  __NR_rt_sigreturn,%r20 */
 #define INSN_BLE_SR2_R0  0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */
-#define INSN_NOP	 0x80000240 /* nop */
+#define INSN_NOP	 0x08000240 /* nop */
 /* For debugging */
 #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */
 
-/*
- * The 32-bit ABI wants at least 48 bytes for a function call frame:
- * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of
- * which Linux/parisc uses is sp-20 for the saved return pointer...)
- * Then, the stack pointer must be rounded to a cache line (64 bytes).
- */
-#define PARISC_RT_SIGFRAME_SIZE					\
-	(((sizeof(struct rt_sigframe) + 48) + 63) & -64)
-
 static long
 restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
 {
@@ -162,10 +151,7 @@
 	err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq));
 	err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq));
 	err |= __get_user(regs->sar, &sc->sc_sar);
-
-#if DEBUG_SIG
-	printk("restore_sigcontext: r28 is %ld\n", regs->gr[28]);
-#endif
+	DBG(("restore_sigcontext: r28 is %ld\n", regs->gr[28]));
 	return err;
 }
 
@@ -180,13 +166,8 @@
 	/* Unwind the user stack to get the rt_sigframe structure. */
 	frame = (struct rt_sigframe *)
 		(usp - PARISC_RT_SIGFRAME_SIZE);
-#if DEBUG_SIG
-	printk("in sys_rt_sigreturn, frame is %p\n", frame);
-#endif
+	DBG(("in sys_rt_sigreturn, frame is %p\n", frame));
 
-	/* Verify that it's a good sigcontext before using it */
-	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-		goto give_sigsegv;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 		goto give_sigsegv;
 
@@ -200,10 +181,7 @@
 	if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
 		goto give_sigsegv;
 
-#if DEBUG_SIG
-	printk("usp: %#08lx stack %p",
-	       usp, &frame->uc.uc_stack);
-#endif
+	DBG(("usp: %#08lx stack %p", usp, &frame->uc.uc_stack));
 
 	/* I don't know why everyone else assumes they can call this
            with a pointer to a stack_t on the kernel stack.  That
@@ -218,16 +196,14 @@
 	if (in_syscall)
 		regs->gr[31] = regs->iaoq[0];
 #if DEBUG_SIG
-	printk("returning to %#lx\n", regs->iaoq[0]);
-	printk("in sys_rt_sigreturn:\n");
+	DBG(("returning to %#lx\n", regs->iaoq[0]));
+	DBG(("in sys_rt_sigreturn:\n"));
 	show_regs(regs);
 #endif
 	return;
 
 give_sigsegv:
-#if DEBUG_SIG
-	printk("fuckup in sys_rt_sigreturn, sending SIGSEGV\n");
-#endif
+	DBG(("sys_rt_sigreturn sending SIGSEGV\n"));
 	si.si_signo = SIGSEGV;
 	si.si_errno = 0;
 	si.si_code = SI_KERNEL;
@@ -246,7 +222,7 @@
 get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
 {
 	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
-		sp = current->sas_ss_sp + current->sas_ss_size;
+		sp = current->sas_ss_sp; /* Stacks grow up! */
 
 	return (void *) sp; /* Stacks grow up.  Fun. */
 }
@@ -265,24 +241,22 @@
 		/* regs->iaoq is undefined in the syscall return path */
 		err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]);
 		err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]);
-#if DEBUG_SIG
-		printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->gr[31], regs->gr[31]);
-#endif
+		err |= __put_user(regs->sr[3], &sc->sc_iasq[0]);
+		err |= __put_user(regs->sr[3], &sc->sc_iasq[1]);
+		DBG(("setup_sigcontext: iaoq %#lx/%#lx\n",
+			regs->gr[31], regs->gr[31]));
 	} else {
 		err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq));
 		err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq));
-#if DEBUG_SIG
-		printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->iaoq[0], regs->iaoq[1]);
-#endif
+		DBG(("setup_sigcontext: iaoq %#lx/%#lx\n", 
+			regs->iaoq[0], regs->iaoq[1]));
 	}
 
 	err |= __put_user(flags, &sc->sc_flags);
 	err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr));
 	err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
 	err |= __put_user(regs->sar, &sc->sc_sar);
-#if DEBUG_SIG
-	printk("setup_sigcontext: r28 is %ld\n", regs->gr[28]);
-#endif
+	DBG(("setup_sigcontext: r28 is %ld\n", regs->gr[28]));
 
 	return err;
 }
@@ -297,22 +271,9 @@
 	int err = 0;
 
 	usp = regs->gr[30];
-	/* access_ok is broken, so do a simplistic "are we stomping on
-           kernel space" assertion. */
-	if (usp > PAGE_OFFSET) {
-		printk("setup_rt_frame: called on kernel space (usp=%#lx),  NOW YOU MUST DIE!!!\n",
-		       usp);
-		show_regs(regs);
-		while(1);
-	}
-		
 	frame = get_sigframe(ka, usp, sizeof(*frame));
-	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto give_sigsegv;
 
-#if DEBUG_SIG
-	printk("setup_rt_frame 1: frame %p info %p\n", frame, info);
-#endif
+	DBG(("setup_rt_frame 1: frame %p info %p\n", frame, info));
 
 	err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t));
 	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
@@ -337,8 +298,8 @@
 	{
 		int sid;
 		asm ("mfsp %%sr3,%0" : "=r" (sid));
-		printk("flushing 64 bytes at space %#x offset %p\n",
-		       sid, frame->tramp);
+		DBG(("flushing 64 bytes at space %#x offset %p\n",
+		       sid, frame->tramp));
 	}
 #endif
 
@@ -387,6 +348,7 @@
 	if (in_syscall)
 		regs->gr[31] = (HACK) haddr;
 	else {
+		regs->gr[0] = USER_PSW;
 		regs->iaoq[0] = (HACK) haddr | 3;
 		regs->iaoq[1] = regs->iaoq[0] + 4;
 	}
@@ -395,26 +357,20 @@
 	regs->gr[26] = sig;               /* signal number */
 	regs->gr[25] = (HACK) &frame->info; /* siginfo pointer */
 	regs->gr[24] = (HACK) &frame->uc;   /* ucontext pointer */
-#if DEBUG_SIG
-	printk("making sigreturn frame: %#lx + %#lx = %#lx\n",
+	DBG(("making sigreturn frame: %#lx + %#x = %#lx\n",
 	       regs->gr[30], PARISC_RT_SIGFRAME_SIZE,
-	       regs->gr[30] + PARISC_RT_SIGFRAME_SIZE);
-#endif
+	       regs->gr[30] + PARISC_RT_SIGFRAME_SIZE));
 	/* Raise the user stack pointer to make a proper call frame. */
 	regs->gr[30] = ((HACK) frame + PARISC_RT_SIGFRAME_SIZE);
 
-#if DEBUG_SIG
-	printk("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
+	DBG(("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
 	       current->comm, current->pid, frame, regs->gr[30],
-	       regs->iaoq[0], regs->iaoq[1], rp);
-#endif
+	       regs->iaoq[0], regs->iaoq[1], rp));
 
 	return 1;
 
 give_sigsegv:
-#if DEBUG_SIG
-	printk("fuckup in setup_rt_frame, sending SIGSEGV\n");
-#endif
+	DBG(("setup_rt_frame sending SIGSEGV\n"));
 	if (sig == SIGSEGV)
 		ka->sa.sa_handler = SIG_DFL;
 	si.si_signo = SIGSEGV;
@@ -436,10 +392,9 @@
 	      siginfo_t *info, sigset_t *oldset,
 	      struct pt_regs *regs, int in_syscall)
 {
-#if DEBUG_SIG
-	printk("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",
-	       sig, ka, info, oldset, regs);
-#endif
+	DBG(("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",
+	       sig, ka, info, oldset, regs));
+	
 	/* Set up the stack frame */
 	if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
 		return 0;
@@ -468,16 +423,16 @@
  * registers).  As noted below, the syscall number gets restored for
  * us due to the magic of delayed branching.
  */
+
 asmlinkage int
 do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
 {
 	siginfo_t info;
 	struct k_sigaction *ka;
 
-#if DEBUG_SIG
-	printk("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",
-	       oldset, regs, regs->sr[7], current->sigpending, in_syscall);
-#endif
+	DBG(("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",
+	       oldset, regs, regs->sr[7], current->sigpending, in_syscall));
+
 	/* Everyone else checks to see if they are in kernel mode at
 	   this point and exits if that's the case.  I'm not sure why
 	   we would be called in that case, but for some reason we
@@ -486,9 +441,8 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-#if DEBUG_SIG
-	printk("do_signal: oldset %08lx:%08lx\n", oldset->sig[0], oldset->sig[1]);
-#endif
+	DBG(("do_signal: oldset %08lx:%08lx\n", 
+		oldset->sig[0], oldset->sig[1]));
 
 	for (;;) {
 		unsigned long signr;
@@ -496,10 +450,7 @@
 		spin_lock_irq(&current->sigmask_lock);
 		signr = dequeue_signal(&current->blocked, &info);
 		spin_unlock_irq(&current->sigmask_lock);
-#if DEBUG_SIG
-		printk("do_signal: signr=%ld, pid=%d\n", signr, current->pid);
-#endif
-
+		DBG(("do_signal: signr=%ld, pid=%d\n", signr, current->pid));
 		if (!signr)
 			break;
 
@@ -536,10 +487,9 @@
 		}
 
 		ka = &current->sig->action[signr-1];
-#if DEBUG_SIG
-		printk("sa_handler is %lx\n", ka->sa.sa_handler);
-#endif
-		if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_IGN) {
+		DBG(("sa_handler is %x\n", 
+			(unsigned int) ka->sa.sa_handler));
+		if (ka->sa.sa_handler == SIG_IGN) {
 			if (signr != SIGCHLD)
 				continue;
 			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
@@ -547,7 +497,7 @@
 			continue;
 		}
 
-		if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_DFL) {
+		if (ka->sa.sa_handler == SIG_DFL) {
 			int exit_code = signr;
 
 			/* Init gets no signals it doesn't want.  */
@@ -591,17 +541,13 @@
 			/* Check the return code */
 			switch (regs->gr[28]) {
 			case -ERESTARTNOHAND:
-#if DEBUG_SIG
-				printk("ERESTARTNOHAND: returning -EINTR\n");
-#endif
+				DBG(("ERESTARTNOHAND: returning -EINTR\n"));
 				regs->gr[28] = -EINTR;
 				break;
 
 			case -ERESTARTSYS:
 				if (!(ka->sa.sa_flags & SA_RESTART)) {
-#if DEBUG_SIG
-					printk("ERESTARTSYS: putting -EINTR\n");
-#endif
+					DBG(("ERESTARTSYS: putting -EINTR\n"));
 					regs->gr[28] = -EINTR;
 					break;
 				}
@@ -620,9 +566,9 @@
 		   delivery failed, we need to continue to iterate in
 		   this loop so we can deliver the SIGSEGV... */
 		if (handle_signal(signr, ka, &info, oldset, regs, in_syscall)) {
-#if DEBUG_SIG
-			printk("Exiting do_signal (success), regs->gr[28] = %ld\n", regs->gr[28]);
-#endif
+			DBG((KERN_DEBUG
+				"Exiting do_signal (success), regs->gr[28] = %ld\n",
+				regs->gr[28]));
 			return 1;
 		}
 	}
@@ -642,8 +588,9 @@
 			regs->gr[28] = regs->orig_r28;
 		}
 	}
-#if DEBUG_SIG
-	printk("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", regs->gr[28]);
-#endif
+	
+	DBG(("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", 
+		regs->gr[28]));
+
 	return 0;
 }
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/signal32.c linux-2.4.20-pre2/arch/parisc/kernel/signal32.c
--- linux-2.4.20-pre1/arch/parisc/kernel/signal32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/signal32.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,213 @@
+/* mostly borrowed from kernel/signal.c */
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/unistd.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+#include "sys32.h"
+
+struct k_sigaction32 {
+	struct sigaction32 sa;
+};
+
+typedef unsigned int old_sigset_t32;
+
+static int
+put_old_sigset32(old_sigset_t32 *up, old_sigset_t *set)
+{
+	old_sigset_t32 set32 = *set;
+	return put_user(set32, up);
+}
+
+static int
+get_old_segset32(old_sigset_t32 *up, old_sigset_t *set)
+{
+	old_sigset_t32 set32;
+	int r;
+
+	if ((r = get_user(set32, up)) == 0)
+		*set = set32;
+
+	return r;
+}
+
+long
+sys32_sigpending(old_sigset_t32 *set)
+{
+	extern long sys_sigpending(old_sigset_t *set);
+	old_sigset_t pending;
+	int ret;
+
+	KERNEL_SYSCALL(ret, sys_sigpending, &pending);
+
+	/* can't put_user an old_sigset_t -- it is too big */
+	if (put_old_sigset32(set, &pending))
+		return -EFAULT;
+
+	return ret;
+}
+
+int sys32_sigprocmask(int how, old_sigset_t32 *set, 
+				 old_sigset_t32 *oset)
+{
+	extern int sys_sigprocmask(int how, old_sigset_t *set, 
+				 old_sigset_t *oset);
+	old_sigset_t s;
+	int ret;
+
+	if (set && get_old_segset32 (set, &s))
+		return -EFAULT;
+	KERNEL_SYSCALL(ret, sys_sigprocmask, how, set ? &s : NULL, oset ? &s : NULL);
+	if (!ret && oset && put_old_sigset32(oset, &s))
+		return -EFAULT;
+	return ret;
+}
+
+static inline void
+sigset_32to64(sigset_t *s64, sigset_t32 *s32)
+{
+	s64->sig[0] = s32->sig[0] | ((unsigned long)s32->sig[1] << 32);
+}
+
+static inline void
+sigset_64to32(sigset_t32 *s32, sigset_t *s64)
+{
+	s32->sig[0] = s64->sig[0] & 0xffffffffUL;
+	s32->sig[1] = (s64->sig[0] >> 32) & 0xffffffffUL;
+}
+
+static int
+put_sigset32(sigset_t32 *up, sigset_t *set, size_t sz)
+{
+	sigset_t32 s;
+
+	if (sz != sizeof *set) panic("put_sigset32()");
+	sigset_64to32(&s, set);
+
+	return copy_to_user(up, &s, sizeof s);
+}
+
+static int
+get_sigset32(sigset_t32 *up, sigset_t *set, size_t sz)
+{
+	sigset_t32 s;
+	int r;
+
+	if (sz != sizeof *set) panic("put_sigset32()");
+
+	if ((r = copy_from_user(&s, up, sz)) == 0) {
+		sigset_32to64(set, &s);
+	}
+
+	return r;
+}
+
+int sys32_rt_sigprocmask(int how, sigset_t32 *set, sigset_t32 *oset,
+				    unsigned int sigsetsize)
+{
+	extern long sys_rt_sigprocmask(int how,
+				    sigset_t *set, sigset_t *oset,
+				   size_t sigsetsize);
+	sigset_t old_set, new_set;
+	int ret;
+
+	if (set && get_sigset32(set, &new_set, sigsetsize))
+		return -EFAULT;
+	
+	KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? &new_set : NULL,
+				 oset ? &old_set : NULL, sigsetsize);
+
+	if (!ret && oset && put_sigset32(oset, &old_set, sigsetsize))
+		return -EFAULT;
+
+	return ret;
+}
+
+
+int sys32_rt_sigpending(sigset_t32 *uset, unsigned int sigsetsize)
+{
+	int ret;
+	sigset_t set;
+	extern long sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
+
+	KERNEL_SYSCALL(ret, sys_rt_sigpending, &set, sigsetsize);
+
+	if (!ret && put_sigset32(uset, &set, sigsetsize))
+		return -EFAULT;
+
+	return ret;
+}
+
+long
+sys32_rt_sigaction(int sig, const struct sigaction32 *act, struct sigaction32 *oact,
+                 size_t sigsetsize)
+{
+	struct k_sigaction32 new_sa32, old_sa32;
+	struct k_sigaction new_sa, old_sa;
+	int ret = -EINVAL;
+
+	if (act) {
+		if (copy_from_user(&new_sa32.sa, act, sizeof new_sa32.sa))
+			return -EFAULT;
+		new_sa.sa.sa_handler = (__sighandler_t)(unsigned long)new_sa32.sa.sa_handler;
+		new_sa.sa.sa_flags = new_sa32.sa.sa_flags;
+		sigset_32to64(&new_sa.sa.sa_mask, &new_sa32.sa.sa_mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
+
+	if (!ret && oact) {
+		sigset_64to32(&old_sa32.sa.sa_mask, &old_sa.sa.sa_mask);
+		old_sa32.sa.sa_flags = old_sa.sa.sa_flags;
+		old_sa32.sa.sa_handler = (__sighandler_t32)(unsigned long)old_sa.sa.sa_handler;
+		if (copy_to_user(oact, &old_sa32.sa, sizeof old_sa32.sa))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+typedef struct {
+	unsigned int ss_sp;
+	int ss_flags;
+	__kernel_size_t32 ss_size;
+} stack_t32;
+
+int 
+do_sigaltstack32 (const stack_t32 *uss32, stack_t32 *uoss32, unsigned long sp)
+{
+	stack_t32 ss32, oss32;
+	stack_t ss, oss;
+	stack_t *ssp = NULL, *ossp = NULL;
+	int ret;
+
+	if (uss32) {
+		if (copy_from_user(&ss32, uss32, sizeof ss32))
+			return -EFAULT;
+
+		ss.ss_sp = (void *)ss32.ss_sp;
+		ss.ss_flags = ss32.ss_flags;
+		ss.ss_size = ss32.ss_size;
+
+		ssp = &ss;
+	}
+
+	if (uoss32)
+		ossp = &oss;
+
+	KERNEL_SYSCALL(ret, do_sigaltstack, ssp, ossp, sp);
+
+	if (!ret && uoss32) {
+		oss32.ss_sp = (unsigned int)(unsigned long)oss.ss_sp;
+		oss32.ss_flags = oss.ss_flags;
+		oss32.ss_size = oss.ss_size;
+		if (copy_to_user(uoss32, &oss32, sizeof *uoss32))
+			return -EFAULT;
+	}
+
+	return ret;
+}
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/smp.c linux-2.4.20-pre2/arch/parisc/kernel/smp.c
--- linux-2.4.20-pre1/arch/parisc/kernel/smp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/smp.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,794 @@
+/*
+** SMP Support
+**
+** Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+** Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+** Copyright (C) 2001 Grant Grundler <grundler@parisc-linux.org>
+** 
+** Lots of stuff stolen from arch/alpha/kernel/smp.c
+** ...and then parisc stole from arch/ia64/kernel/smp.c. Thanks David! :^)
+**
+** Thanks to John Curry and Ullas Ponnadi. I learned alot from their work.
+** -grant (1/12/2001)
+**
+**	This program is free software; you can redistribute it and/or modify
+**	it under the terms of the GNU General Public License as published by
+**      the Free Software Foundation; either version 2 of the License, or
+**      (at your option) any later version.
+*/
+#define __KERNEL_SYSCALLS__
+#undef ENTRY_SYS_CPUS	/* syscall support for iCOD-like functionality */
+
+#include <linux/autoconf.h>
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/current.h>
+#include <asm/delay.h>
+#include <asm/pgalloc.h>	/* for flush_tlb_all() proto/macro */
+
+#include <asm/io.h>
+#include <asm/irq.h>		/* for CPU_IRQ_REGION and friends */
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+#define kDEBUG 0
+
+spinlock_t pa_dbit_lock = SPIN_LOCK_UNLOCKED;
+
+spinlock_t smp_lock = SPIN_LOCK_UNLOCKED;
+
+volatile struct task_struct *smp_init_current_idle_task;
+spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+
+static volatile int smp_commenced = 0;   /* Set when the idlers are all forked */
+static volatile int cpu_now_booting = 0;      /* track which CPU is booting */
+volatile unsigned long cpu_online_map = 0;   /* Bitmap of online CPUs */
+#define IS_LOGGED_IN(cpunum) (test_bit(cpunum, (atomic_t *)&cpu_online_map))
+
+int smp_num_cpus = 1;
+int smp_threads_ready = 0;
+static int max_cpus = -1;			     /* Command line */
+struct smp_call_struct {
+	void (*func) (void *info);
+	void *info;
+	long wait;
+	atomic_t unstarted_count;
+	atomic_t unfinished_count;
+};
+static volatile struct smp_call_struct *smp_call_function_data;
+
+enum ipi_message_type {
+	IPI_NOP=0,
+	IPI_RESCHEDULE=1,
+	IPI_CALL_FUNC,
+	IPI_CPU_START,
+	IPI_CPU_STOP,
+	IPI_CPU_TEST
+};
+
+
+/********** SMP inter processor interrupt and communication routines */
+
+#undef PER_CPU_IRQ_REGION
+#ifdef PER_CPU_IRQ_REGION
+/* XXX REVISIT Ignore for now.
+**    *May* need this "hook" to register IPI handler
+**    once we have perCPU ExtIntr switch tables.
+*/
+static void
+ipi_init(int cpuid)
+{
+
+	/* If CPU is present ... */
+#ifdef ENTRY_SYS_CPUS
+	/* *and* running (not stopped) ... */
+#error iCOD support wants state checked here.
+#endif
+
+#error verify IRQ_OFFSET(IPI_IRQ) is ipi_interrupt() in new IRQ region
+
+	if(IS_LOGGED_IN(cpuid) )
+	{
+		switch_to_idle_task(current);
+	}
+
+	return;
+}
+#endif
+
+
+/*
+** Yoink this CPU from the runnable list... 
+**
+*/
+static void
+halt_processor(void) 
+{
+#ifdef ENTRY_SYS_CPUS
+#error halt_processor() needs rework
+/*
+** o migrate I/O interrupts off this CPU.
+** o leave IPI enabled - __cli() will disable IPI.
+** o leave CPU in online map - just change the state
+*/
+	cpu_data[this_cpu].state = STATE_STOPPED;
+	mark_bh(IPI_BH);
+#else
+	/* REVISIT : redirect I/O Interrupts to another CPU? */
+	/* REVISIT : does PM *know* this CPU isn't available? */
+	clear_bit(smp_processor_id(), (void *)&cpu_online_map);
+	__cli();
+	for (;;)
+		;
+#endif
+}
+
+
+void
+ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
+{
+	int this_cpu = smp_processor_id();
+	struct cpuinfo_parisc *p = &cpu_data[this_cpu];
+	unsigned long ops;
+	unsigned long flags;
+
+	/* Count this now; we may make a call that never returns. */
+	p->ipi_count++;
+
+	mb();	/* Order interrupt and bit testing. */
+
+	for (;;) {
+		spin_lock_irqsave(&(p->lock),flags);
+		ops = p->pending_ipi;
+		p->pending_ipi = 0;
+		spin_unlock_irqrestore(&(p->lock),flags);
+
+		mb(); /* Order bit clearing and data access. */
+
+		if (!ops)
+		    break;
+
+		while (ops) {
+			unsigned long which = ffz(~ops);
+
+			switch (which) {
+			case IPI_RESCHEDULE:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d IPI_RESCHEDULE\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_RESCHEDULE);
+				/*
+				 * Reschedule callback.  Everything to be
+				 * done is done by the interrupt return path.
+				 */
+				break;
+
+			case IPI_CALL_FUNC:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d IPI_CALL_FUNC\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_CALL_FUNC);
+				{
+					volatile struct smp_call_struct *data;
+					void (*func)(void *info);
+					void *info;
+					int wait;
+
+					data = smp_call_function_data;
+					func = data->func;
+					info = data->info;
+					wait = data->wait;
+
+					mb();
+					atomic_dec ((atomic_t *)&data->unstarted_count);
+
+					/* At this point, *data can't
+					 * be relied upon.
+					 */
+
+					(*func)(info);
+
+					/* Notify the sending CPU that the
+					 * task is done.
+					 */
+					mb();
+					if (wait)
+						atomic_dec ((atomic_t *)&data->unfinished_count);
+				}
+				break;
+
+			case IPI_CPU_START:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d IPI_CPU_START\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_CPU_START);
+#ifdef ENTRY_SYS_CPUS
+				p->state = STATE_RUNNING;
+#endif
+				break;
+
+			case IPI_CPU_STOP:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d IPI_CPU_STOP\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_CPU_STOP);
+#ifdef ENTRY_SYS_CPUS
+#else
+				halt_processor();
+#endif
+				break;
+
+			case IPI_CPU_TEST:
+#if (kDEBUG>=100)
+				printk(KERN_DEBUG "CPU%d is alive!\n",this_cpu);
+#endif /* kDEBUG */
+				ops &= ~(1 << IPI_CPU_TEST);
+				break;
+
+			default:
+				printk(KERN_CRIT "Unknown IPI num on CPU%d: %lu\n",
+					this_cpu, which);
+				ops &= ~(1 << which);
+				return;
+			} /* Switch */
+		} /* while (ops) */
+	}
+	return;
+}
+
+
+static inline void
+ipi_send(int cpu, enum ipi_message_type op)
+{
+	struct cpuinfo_parisc *p = &cpu_data[cpu];
+	unsigned long flags;
+
+	spin_lock_irqsave(&(p->lock),flags);
+	p->pending_ipi |= 1 << op;
+	__raw_writel(IRQ_OFFSET(IPI_IRQ), cpu_data[cpu].hpa);
+	spin_unlock_irqrestore(&(p->lock),flags);
+}
+
+
+static inline void
+send_IPI_single(int dest_cpu, enum ipi_message_type op)
+{
+	if (dest_cpu == NO_PROC_ID) {
+		BUG();
+		return;
+	}
+
+	ipi_send(dest_cpu, op);
+}
+
+static inline void
+send_IPI_allbutself(enum ipi_message_type op)
+{
+	int i;
+	
+	for (i = 0; i < smp_num_cpus; i++) {
+		if (i != smp_processor_id())
+			send_IPI_single(i, op);
+	}
+}
+
+inline void 
+smp_send_stop(void)	{ send_IPI_allbutself(IPI_CPU_STOP); }
+
+static inline void
+smp_send_start(void)	{ send_IPI_allbutself(IPI_CPU_START); }
+
+void 
+smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); }
+
+
+/**
+ * Run a function on all other CPUs.
+ *  <func>	The function to run. This must be fast and non-blocking.
+ *  <info>	An arbitrary pointer to pass to the function.
+ *  <retry>	If true, keep retrying until ready.
+ *  <wait>	If true, wait until function has completed on other CPUs.
+ *  [RETURNS]   0 on success, else a negative status code.
+ *
+ * Does not return until remote CPUs are nearly ready to execute <func>
+ * or have executed.
+ */
+
+int
+smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
+{
+	struct smp_call_struct data;
+	long timeout;
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+	
+	data.func = func;
+	data.info = info;
+	data.wait = wait;
+	atomic_set(&data.unstarted_count, smp_num_cpus - 1);
+	atomic_set(&data.unfinished_count, smp_num_cpus - 1);
+
+	if (retry) {
+		spin_lock (&lock);
+		while (smp_call_function_data != 0)
+			barrier();
+	}
+	else {
+		spin_lock (&lock);
+		if (smp_call_function_data) {
+			spin_unlock (&lock);
+			return -EBUSY;
+		}
+	}
+
+	smp_call_function_data = &data;
+	spin_unlock (&lock);
+	
+	/*  Send a message to all other CPUs and wait for them to respond  */
+	send_IPI_allbutself(IPI_CALL_FUNC);
+
+	/*  Wait for response  */
+	timeout = jiffies + HZ;
+	while ( (atomic_read (&data.unstarted_count) > 0) &&
+		time_before (jiffies, timeout) )
+		barrier ();
+
+	/* We either got one or timed out. Release the lock */
+
+	mb();
+	smp_call_function_data = NULL;
+	if (atomic_read (&data.unstarted_count) > 0) {
+		printk(KERN_CRIT "SMP CALL FUNCTION TIMED OUT! (cpu=%d)\n",
+		      smp_processor_id());
+		return -ETIMEDOUT;
+	}
+
+	while (wait && atomic_read (&data.unfinished_count) > 0)
+			barrier ();
+
+	return 0;
+}
+
+
+
+/*
+ *	Setup routine for controlling SMP activation
+ *
+ *	Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+ *	activation entirely (the MPS table probe still happens, though).
+ *
+ *	Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
+ *	greater than 0, limits the maximum number of CPUs activated in
+ *	SMP mode to <NUM>.
+ */
+
+static int __init nosmp(char *str)
+{
+	max_cpus = 0;
+	return 1;
+}
+
+__setup("nosmp", nosmp);
+
+static int __init maxcpus(char *str)
+{
+	get_option(&str, &max_cpus);
+	return 1;
+}
+
+__setup("maxcpus=", maxcpus);
+
+/*
+ * Flush all other CPU's tlb and then mine.  Do this with smp_call_function()
+ * as we want to ensure all TLB's flushed before proceeding.
+ */
+
+extern void flush_tlb_all_local(void);
+
+void
+smp_flush_tlb_all(void)
+{
+	smp_call_function((void (*)(void *))flush_tlb_all_local, NULL, 1, 1);
+	flush_tlb_all_local();
+}
+
+
+void 
+smp_do_timer(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	struct cpuinfo_parisc *data = &cpu_data[cpu];
+
+        if (!--data->prof_counter) {
+		data->prof_counter = data->prof_multiplier;
+		update_process_times(user_mode(regs));
+	}
+}
+
+/*
+ * Called by secondaries to update state and initialize CPU registers.
+ */
+static void __init
+smp_cpu_init(int cpunum)
+{
+	extern int init_per_cpu(int);  /* arch/parisc/kernel/setup.c */
+	extern void init_IRQ(void);    /* arch/parisc/kernel/irq.c */
+
+	/* Set modes and Enable floating point coprocessor */
+	(void) init_per_cpu(cpunum);
+
+	disable_sr_hashing();
+
+	mb();
+
+	/* Well, support 2.4 linux scheme as well. */
+	if (test_and_set_bit(cpunum, (unsigned long *) (&cpu_online_map)))
+	{
+		extern void machine_halt(void); /* arch/parisc.../process.c */
+
+		printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum);
+		machine_halt();
+	}  
+
+	/* Initialise the idle task for this CPU */
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+	if(current->mm)
+		BUG();
+	enter_lazy_tlb(&init_mm, current, cpunum);
+
+	init_IRQ();   /* make sure no IRQ's are enabled or pending */
+}
+
+
+/*
+ * Slaves start using C here. Indirectly called from smp_slave_stext.
+ * Do what start_kernel() and main() do for boot strap processor (aka monarch)
+ */
+void __init smp_callin(void)
+{
+	extern void cpu_idle(void);	/* arch/parisc/kernel/process.c */
+	int slave_id = cpu_now_booting;
+#if 0
+	void *istack;
+#endif
+
+	smp_cpu_init(slave_id);
+
+#if 0	/* NOT WORKING YET - see entry.S */
+	istack = (void *)__get_free_pages(GFP_KERNEL,ISTACK_ORDER);
+	if (istack == NULL) {
+	    printk(KERN_CRIT "Failed to allocate interrupt stack for cpu %d\n",slave_id);
+	    BUG();
+	}
+	mtctl(istack,31);
+#endif
+
+	flush_cache_all_local(); /* start with known state */
+	flush_tlb_all_local();
+
+	local_irq_enable();  /* Interrupts have been off until now */
+
+	/* Slaves wait here until Big Poppa daddy say "jump" */
+	mb();	/* PARANOID */
+	while (!smp_commenced) ;
+	mb();	/* PARANOID */
+
+	cpu_idle();      /* Wait for timer to schedule some work */
+
+	/* NOTREACHED */
+	panic("smp_callin() AAAAaaaaahhhh....\n");
+}
+
+/*
+ * Create the idle task for a new Slave CPU.  DO NOT use kernel_thread()
+ * because that could end up calling schedule(). If it did, the new idle
+ * task could get scheduled before we had a chance to remove it from the
+ * run-queue...
+ */
+static int fork_by_hand(void)
+{
+	struct pt_regs regs;  
+
+	/*
+	 * don't care about the regs settings since
+	 * we'll never reschedule the forked task.
+	 */
+	return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
+}
+
+
+/*
+ * Bring one cpu online.
+ */
+static int smp_boot_one_cpu(int cpuid, int cpunum)
+{
+	struct task_struct *idle;
+	long timeout;
+
+	/* 
+	 * Create an idle task for this CPU.  Note the address wed* give 
+	 * to kernel_thread is irrelevant -- it's going to start
+	 * where OS_BOOT_RENDEVZ vector in SAL says to start.  But
+	 * this gets all the other task-y sort of data structures set
+	 * up like we wish.   We need to pull the just created idle task 
+	 * off the run queue and stuff it into the init_tasks[] array.  
+	 * Sheesh . . .
+	 */
+
+	if (fork_by_hand() < 0) 
+		panic("SMP: fork failed for CPU:%d", cpuid);
+	
+	idle = init_task.prev_task;
+	if (!idle)
+		panic("SMP: No idle process for CPU:%d", cpuid);
+
+	task_set_cpu(idle, cpunum);	/* manually schedule idle task */
+	del_from_runqueue(idle);
+	unhash_process(idle);
+	init_tasks[cpunum] = idle;
+
+	/* Let _start know what logical CPU we're booting
+	** (offset into init_tasks[],cpu_data[])
+	*/
+	cpu_now_booting = cpunum;
+
+	/* 
+	** boot strap code needs to know the task address since
+	** it also contains the process stack.
+	*/
+	smp_init_current_idle_task = idle ;
+	mb();
+
+	/*
+	** This gets PDC to release the CPU from a very tight loop.
+	** See MEM_RENDEZ comments in head.S.
+	*/
+	__raw_writel(IRQ_OFFSET(TIMER_IRQ), cpu_data[cpunum].hpa);
+	mb();
+
+	/* 
+	 * OK, wait a bit for that CPU to finish staggering about. 
+	 * Slave will set a bit when it reaches smp_cpu_init() and then
+	 * wait for smp_commenced to be 1.
+	 * Once we see the bit change, we can move on.
+	 */
+	for (timeout = 0; timeout < 10000; timeout++) {
+		if(IS_LOGGED_IN(cpunum)) {
+			/* Which implies Slave has started up */
+			cpu_now_booting = 0;
+			smp_init_current_idle_task = NULL;
+			goto alive ;
+		}
+		udelay(100);
+		barrier();
+	}
+
+	init_tasks[cpunum] = NULL;
+	free_task_struct(idle);
+
+	printk(KERN_CRIT "SMP: CPU:%d is stuck.\n", cpuid);
+	return -1;
+
+alive:
+	/* Remember the Slave data */
+#if (kDEBUG>=100)
+	printk(KERN_DEBUG "SMP: CPU:%d (num %d) came alive after %ld _us\n",
+		cpuid,  cpunum, timeout * 100);
+#endif /* kDEBUG */
+#ifdef ENTRY_SYS_CPUS
+	cpu_data[cpunum].state = STATE_RUNNING;
+#endif
+	return 0;
+}
+
+
+
+
+/*
+** inventory.c:do_inventory() has already 'discovered' the additional CPU's.
+** We are ready to wrest them from PDC's control now.
+** Called by smp_init bring all the secondaries online and hold them.  
+**
+** o Setup of the IPI irq handler is done in irq.c.
+** o MEM_RENDEZ is initialzed in head.S:stext()
+**
+*/
+void __init smp_boot_cpus(void)
+{
+	int i, cpu_count = 1;
+	unsigned long bogosum = loops_per_jiffy; /* Count Monarch */
+
+	/* REVISIT - assumes first CPU reported by PAT PDC is BSP */
+	int bootstrap_processor=cpu_data[0].cpuid;	/* CPU ID of BSP */
+
+	/* Setup BSP mappings */
+	printk(KERN_DEBUG "SMP: bootstrap CPU ID is %d\n",bootstrap_processor);
+	init_task.processor = bootstrap_processor; 
+	current->processor = bootstrap_processor;
+	cpu_online_map = 1 << bootstrap_processor; /* Mark Boostrap processor as present */
+	current->active_mm = &init_mm;
+
+#ifdef ENTRY_SYS_CPUS
+	cpu_data[0].state = STATE_RUNNING;
+#endif
+
+	/* Nothing to do when told not to.  */
+	if (max_cpus == 0) {
+		printk(KERN_INFO "SMP mode deactivated.\n");
+		return;
+	}
+
+	if (max_cpus != -1) 
+		printk(KERN_INFO "Limiting CPUs to %d\n", max_cpus);
+
+	/* We found more than one CPU.... */
+	if (boot_cpu_data.cpu_count > 1) {
+
+		for (i = 0; i < NR_CPUS; i++) {
+			if (cpu_data[i].cpuid == NO_PROC_ID || 
+			    cpu_data[i].cpuid == bootstrap_processor)
+				continue;
+
+			if (smp_boot_one_cpu(cpu_data[i].cpuid, cpu_count) < 0)
+				continue;
+
+			bogosum += loops_per_jiffy;
+			cpu_count++; /* Count good CPUs only... */
+
+			/* Bail when we've started as many CPUS as told to */
+			if (cpu_count == max_cpus)
+				break;
+		}
+	}
+	if (cpu_count == 1) {
+		printk(KERN_INFO "SMP: Bootstrap processor only.\n");
+	}
+
+	printk(KERN_INFO "SMP: Total %d of %d processors activated "
+	       "(%lu.%02lu BogoMIPS noticed).\n",
+	       cpu_count, boot_cpu_data.cpu_count, (bogosum + 25) / 5000,
+	       ((bogosum + 25) / 50) % 100);
+
+	smp_num_cpus = cpu_count;
+#ifdef PER_CPU_IRQ_REGION
+	ipi_init();
+#endif
+	return;
+}
+
+/* 
+ * Called from main.c by Monarch Processor.
+ * After this, any CPU can schedule any task.
+ */
+void smp_commence(void)
+{
+	smp_commenced = 1;
+	mb();
+	return;
+}
+
+#ifdef ENTRY_SYS_CPUS
+/* Code goes along with:
+**    entry.s:        ENTRY_NAME(sys_cpus)   / * 215, for cpu stat * /
+*/
+int sys_cpus(int argc, char **argv)
+{
+	int i,j=0;
+	extern int current_pid(int cpu);
+
+	if( argc > 2 ) {
+		printk("sys_cpus:Only one argument supported\n");
+		return (-1);
+	}
+	if ( argc == 1 ){
+	
+#ifdef DUMP_MORE_STATE
+		for(i=0; i<NR_CPUS; i++) {
+			int cpus_per_line = 4;
+			if(IS_LOGGED_IN(i)) {
+				if (j++ % cpus_per_line)
+					printk(" %3d",i);
+				else
+					printk("\n %3d",i);
+			}
+		}
+		printk("\n"); 
+#else
+	    	printk("\n 0\n"); 
+#endif
+	} else if((argc==2) && !(strcmp(argv[1],"-l"))) {
+		printk("\nCPUSTATE  TASK CPUNUM CPUID HARDCPU(HPA)\n");
+#ifdef DUMP_MORE_STATE
+		for(i=0;i<NR_CPUS;i++) {
+			if (!IS_LOGGED_IN(i))
+				continue;
+			if (cpu_data[i].cpuid != NO_PROC_ID) {
+				switch(cpu_data[i].state) {
+					case STATE_RENDEZVOUS:
+						printk("RENDEZVS ");
+						break;
+					case STATE_RUNNING:
+						printk((current_pid(i)!=0) ? "RUNNING  " : "IDLING   ");
+						break;
+					case STATE_STOPPED:
+						printk("STOPPED  ");
+						break;
+					case STATE_HALTED:
+						printk("HALTED   ");
+						break;
+					default:
+						printk("%08x?", cpu_data[i].state);
+						break;
+				}
+				if(IS_LOGGED_IN(i)) {
+					printk(" %4d",current_pid(i));
+				}	
+				printk(" %6d",cpu_number_map(i));
+				printk(" %5d",i);
+				printk(" 0x%lx\n",cpu_data[i].hpa);
+			}	
+		}
+#else
+		printk("\n%s  %4d      0     0 --------",
+			(current->pid)?"RUNNING ": "IDLING  ",current->pid); 
+#endif
+	} else if ((argc==2) && !(strcmp(argv[1],"-s"))) { 
+#ifdef DUMP_MORE_STATE
+     		printk("\nCPUSTATE   CPUID\n");
+		for (i=0;i<NR_CPUS;i++) {
+			if (!IS_LOGGED_IN(i))
+				continue;
+			if (cpu_data[i].cpuid != NO_PROC_ID) {
+				switch(cpu_data[i].state) {
+					case STATE_RENDEZVOUS:
+						printk("RENDEZVS");break;
+					case STATE_RUNNING:
+						printk((current_pid(i)!=0) ? "RUNNING " : "IDLING");
+						break;
+					case STATE_STOPPED:
+						printk("STOPPED ");break;
+					case STATE_HALTED:
+						printk("HALTED  ");break;
+					default:
+				}
+				printk("  %5d\n",i);
+			}	
+		}
+#else
+		printk("\n%s    CPU0",(current->pid==0)?"RUNNING ":"IDLING  "); 
+#endif
+	} else {
+		printk("sys_cpus:Unknown request\n");
+		return (-1);
+	}
+	return 0;
+}
+#endif /* ENTRY_SYS_CPUS */
+
+#ifdef CONFIG_PROC_FS
+int __init
+setup_profiling_timer(unsigned int multiplier)
+{
+	return -EINVAL;
+}
+#endif
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/superio.c linux-2.4.20-pre2/arch/parisc/kernel/superio.c
--- linux-2.4.20-pre1/arch/parisc/kernel/superio.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/superio.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,543 @@
+/*      National Semiconductor NS87560UBD Super I/O controller used in
+ *      HP [BCJ]x000 workstations.
+ *
+ *      This chip is a horrid piece of engineering, and National
+ *      denies any knowledge of its existence. Thus no datasheet is
+ *      available off www.national.com. 
+ *
+ *	(C) Copyright 2000 Linuxcare, Inc.
+ * 	(C) Copyright 2000 Linuxcare Canada, Inc.
+ *	(C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com>
+ * 	(C) Copyright 2000 Alex deVries <alex@linuxcare.com>
+ *      (C) Copyright 2001 John Marvin <jsm@fc.hp.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.  
+ *
+ *	The initial version of this is by Martin Peterson.  Alex deVries
+ *	has spent a bit of time trying to coax it into working.
+ *
+ *      Major changes to get basic interrupt infrastructure working to
+ *      hopefully be able to support all SuperIO devices. Currently
+ *      works with serial. -- John Marvin <jsm@fc.hp.com>
+ */
+
+
+/* NOTES:
+ * 
+ * Function 0 is an IDE controller. It is identical to a PC87415 IDE
+ * controller (and identifies itself as such).
+ *
+ * Function 1 is a "Legacy I/O" controller. Under this function is a
+ * whole mess of legacy I/O peripherals. Of course, HP hasn't enabled
+ * all the functionality in hardware, but the following is available:
+ *
+ *      Two 16550A compatible serial controllers
+ *      An IEEE 1284 compatible parallel port
+ *      A floppy disk controller
+ *
+ * Function 2 is a USB controller.
+ *
+ * We must be incredibly careful during initialization.  Since all
+ * interrupts are routed through function 1 (which is not allowed by
+ * the PCI spec), we need to program the PICs on the legacy I/O port
+ * *before* we attempt to set up IDE and USB.  @#$!&
+ *
+ * According to HP, devices are only enabled by firmware if they have
+ * a physical device connected.
+ *
+ * Configuration register bits:
+ *     0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P92
+ *     0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/serial.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/parport.h>
+#include <linux/parport_pc.h>
+#include <linux/serial_reg.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/gsc.h>
+#include <asm/irq.h>
+#include <asm/superio.h>
+
+static struct superio_device sio_dev = {
+	iosapic_irq: -1
+};
+
+
+#undef DEBUG_INIT
+
+void
+superio_inform_irq(int irq)
+{
+    if (sio_dev.iosapic_irq != -1) {
+	printk(KERN_ERR "SuperIO: superio_inform_irq called twice! (more than one SuperIO?)\n");
+	BUG();
+	return;
+    }
+
+    sio_dev.iosapic_irq = irq;
+}
+
+static void
+superio_interrupt(int irq, void *devp, struct pt_regs *regs)
+{
+	struct superio_device *sio = (struct superio_device *)devp;
+	u8 results;
+	u8 local_irq;
+
+	/* Poll the 8259 to see if there's an interrupt. */
+	outb (OCW3_POLL,IC_PIC1+0);
+
+	results = inb(IC_PIC1+0);
+
+	if ((results & 0x80) == 0) {
+#ifndef CONFIG_SMP
+		/* HACK: need to investigate why this happens if SMP enabled */
+		BUG(); /* This shouldn't happen */
+#endif
+		return;
+	}
+
+	/* Check to see which device is interrupting */
+
+	local_irq = results & 0x0f;
+
+	if (local_irq == 2 || local_irq > 7) {
+		printk(KERN_ERR "SuperIO: slave interrupted!\n");
+		BUG();
+		return;
+	}
+
+	if (local_irq == 7) {
+
+		/* Could be spurious. Check in service bits */
+
+		outb(OCW3_ISR,IC_PIC1+0);
+		results = inb(IC_PIC1+0);
+		if ((results & 0x80) == 0) { /* if ISR7 not set: spurious */
+			printk(KERN_WARNING "SuperIO: spurious interrupt!\n");
+			return;
+		}
+	}
+
+	/* Call the appropriate device's interrupt */
+
+	do_irq(&sio->irq_region->action[local_irq],
+		sio->irq_region->data.irqbase + local_irq,
+		regs);
+
+	/* set EOI */
+
+	outb((OCW2_SEOI|local_irq),IC_PIC1 + 0);
+	return;
+}
+
+/* Initialize Super I/O device */
+
+static void __devinit
+superio_init(struct superio_device *sio)
+{
+	struct pci_dev *pdev = sio->lio_pdev;
+	u16 word;
+	u8  i;
+
+	if (!pdev || sio->iosapic_irq == -1) {
+		printk(KERN_ERR "All SuperIO functions not found!\n");
+		BUG();
+		return;
+	}
+
+	printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n",
+		pdev->slot_name,sio->iosapic_irq);
+
+	/* Find our I/O devices */
+	pci_read_config_word (pdev, SIO_SP1BAR, &sio->sp1_base);
+	sio->sp1_base &= ~1;
+	printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base);
+
+	pci_read_config_word (pdev, SIO_SP2BAR, &sio->sp2_base);
+	sio->sp2_base &= ~1;
+	printk (KERN_INFO "SuperIO: Serial port 2 at 0x%x\n", sio->sp2_base);
+
+	pci_read_config_word (pdev, SIO_PPBAR, &sio->pp_base);
+	sio->pp_base &= ~1;
+	printk (KERN_INFO "SuperIO: Parallel port at 0x%x\n", sio->pp_base);
+
+	pci_read_config_word (pdev, SIO_FDCBAR, &sio->fdc_base);
+	sio->fdc_base &= ~1;
+	printk (KERN_INFO "SuperIO: Floppy controller at 0x%x\n", sio->fdc_base);
+	pci_read_config_word (pdev, SIO_ACPIBAR, &sio->acpi_base);
+	sio->acpi_base &= ~1;
+	printk (KERN_INFO "SuperIO: ACPI at 0x%x\n", sio->acpi_base);
+
+	request_region (IC_PIC1, 0x1f, "pic1");
+	request_region (IC_PIC2, 0x1f, "pic2");
+	request_region (sio->acpi_base, 0x1f, "acpi");
+
+	/* Enable the legacy I/O function */
+        pci_read_config_word (pdev, PCI_COMMAND, &word);
+	word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
+	pci_write_config_word (pdev, PCI_COMMAND, word);
+	pci_set_master (pdev);
+
+	/* Next project is programming the onboard interrupt
+	 * controllers.  PDC hasn't done this for us, since it's using
+	 * polled I/O.
+	 */
+
+	/* Set PIC interrupts to edge triggered */
+	pci_write_config_byte (pdev, TRIGGER_1, 0x0);
+	pci_write_config_byte (pdev, TRIGGER_2, 0x0);
+
+	/* Disable all interrupt routing */
+	for (i = IR_LOW ; i < IR_HIGH ; i++)
+		pci_write_config_byte (pdev, i, 0x0);
+
+	/* PIC1 Initialization Command Word register programming */
+	outb (0x11,IC_PIC1+0);	/* ICW1: ICW4 write req | ICW1 */
+	outb (0x00,IC_PIC1+1);	/* ICW2: N/A */
+	outb (0x04,IC_PIC1+1);	/* ICW3: Cascade */
+	outb (0x01,IC_PIC1+1);	/* ICW4: x86 mode */
+
+	/* PIC1 Program Operational Control Words */
+	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */
+	outb (0xc2,IC_PIC1+0);  /* OCW2: priority (3-7,0-2) */
+
+	/* PIC2 Initialization Command Word register programming */
+	outb (0x11,IC_PIC2+0);	/* ICW1: ICW4 write req | ICW1 */
+	outb (0x00,IC_PIC2+1);	/* ICW2: N/A */
+	outb (0x02,IC_PIC2+1);	/* ICW3: Slave ID code */
+	outb (0x01,IC_PIC2+1);	/* ICW4: x86 mode */
+		
+	/* Program Operational Control Words */
+	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */
+	outb (0x68,IC_PIC1+0);	/* OCW3: OCW3 select | ESMM | SMM */
+
+	/* Write master mask reg */
+
+	outb (0xff,IC_PIC1+1);
+
+	/* Set up interrupt routing */
+
+	pci_write_config_byte (pdev, IR_USB, 0x10); /* USB on IRQ1 */
+	pci_write_config_byte (pdev, IR_SER, 0x43); /* SP1 on IRQ3, SP2 on IRQ4 */
+	pci_write_config_byte (pdev, IR_PFD, 0x65); /* PAR on IRQ5, FDC on IRQ6 */
+	pci_write_config_byte (pdev, IR_IDE, 0x07); /* IDE1 on IRQ7 */
+	
+	/* Set USB and IDE to level triggered interrupts, rest to edge */
+	pci_write_config_byte (pdev, TRIGGER_1, 0x82); /* IRQ 1 and 7 */
+
+	/* Setup USB power regulation */
+	outb(1, sio->acpi_base + USB_REG_CR);
+	if (inb(sio->acpi_base + USB_REG_CR) & 1)
+		printk(KERN_INFO "SuperIO: USB regulator enabled\n");
+	else
+		printk(KERN_ERR "USB regulator not initialized!\n");
+
+	pci_enable_device(pdev);
+
+	if (request_irq(sio->iosapic_irq,superio_interrupt,SA_INTERRUPT,
+			"SuperIO",(void *)sio)) {
+
+		printk(KERN_ERR "SuperIO: could not get irq\n");
+		BUG();
+		return;
+	}
+
+	sio->iosapic_irq_enabled = 1;
+	
+}
+
+static void
+superio_disable_irq(void *dev, int local_irq)
+{
+	u8 r8;
+
+	if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
+	    printk(KERN_ERR "SuperIO: Illegal irq number.\n");
+	    BUG();
+	    return;
+	}
+
+	/* Mask interrupt */
+
+	r8 = inb(IC_PIC1+1);
+	r8 |= (1 << local_irq);
+	outb (r8,IC_PIC1+1);
+}
+
+static void
+superio_enable_irq(void *dev, int local_irq)
+{
+	struct superio_device *sio = (struct superio_device *)dev;
+	u8 r8;
+
+	if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) {
+	    printk(KERN_ERR "SuperIO: Illegal irq number.\n");
+	    BUG();
+	    return;
+	}
+
+	/*
+	 * It's possible that we haven't initialized the legacy IO
+	 * function yet. If not, do it now.
+	 */
+
+	if (!sio->iosapic_irq_enabled)
+		superio_init(sio);
+
+	/* Unmask interrupt */
+
+	r8 = inb(IC_PIC1+1);
+	r8 &= ~(1 << local_irq);
+	outb (r8,IC_PIC1+1);
+}
+
+static void
+superio_mask_irq(void *dev, int local_irq)
+{
+	BUG();
+}
+
+static void
+superio_unmask_irq(void *dev, int local_irq)
+{
+	BUG();
+}
+
+static struct irq_region_ops superio_irq_ops = {
+	disable_irq:	superio_disable_irq,
+	enable_irq:	superio_enable_irq,
+	mask_irq:	superio_mask_irq,
+	unmask_irq:	superio_unmask_irq
+};
+
+#ifdef DEBUG_INIT
+static unsigned short expected_device[3] = {
+	PCI_DEVICE_ID_NS_87415,
+	PCI_DEVICE_ID_NS_87560_LIO,
+	PCI_DEVICE_ID_NS_87560_USB
+};
+#endif
+
+int superio_fixup_irq(struct pci_dev *pcidev)
+{
+	int local_irq;
+
+#ifdef DEBUG_INIT
+	int fn;
+	fn = PCI_FUNC(pcidev->devfn);
+
+	/* Verify the function number matches the expected device id. */
+	if (expected_device[fn] != pcidev->device) {
+		BUG();
+		return -1;
+	}
+	printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n",
+		pcidev->slot_name,
+		pcidev->vendor, pcidev->device,
+		__builtin_return_address(0));
+#endif
+
+	if (!sio_dev.irq_region) {
+		/* Allocate an irq region for SuperIO devices */
+		sio_dev.irq_region = alloc_irq_region(SUPERIO_NIRQS,
+						&superio_irq_ops,
+						"SuperIO", (void *) &sio_dev);
+		if (!sio_dev.irq_region) {
+			printk(KERN_WARNING "SuperIO: alloc_irq_region failed\n");
+			return -1;
+		}
+	}
+
+	/*
+	 * We don't allocate a SuperIO irq for the legacy IO function,
+	 * since it is a "bridge". Instead, we will allocate irq's for
+	 * each legacy device as they are initialized.
+	 */
+
+	switch(pcidev->device) {
+	case PCI_DEVICE_ID_NS_87415:		/* Function 0 */
+		local_irq = IDE_IRQ;
+		break;
+	case PCI_DEVICE_ID_NS_87560_LIO:	/* Function 1 */
+		sio_dev.lio_pdev = pcidev; /* save for later initialization */
+		return -1;
+	case PCI_DEVICE_ID_NS_87560_USB:	/* Function 2 */
+		local_irq = USB_IRQ;
+		break;
+	default:
+		local_irq = -1;
+		BUG();
+		break;
+	}
+
+	return(sio_dev.irq_region->data.irqbase + local_irq);
+}
+
+void __devinit
+superio_serial_init(void)
+{
+#ifdef CONFIG_SERIAL
+	struct serial_struct *serial;
+	int retval;
+	
+	if (!sio_dev.irq_region)
+		return; /* superio not present */
+
+	if (!sio_dev.iosapic_irq_enabled)
+		superio_init(&sio_dev);
+
+	serial = kmalloc(2 * sizeof (struct serial_struct), GFP_KERNEL);
+
+	if (!serial) {
+		printk(KERN_WARNING "SuperIO: Could not get memory for serial struct.\n");
+		return;
+	}
+
+	memset(serial, 0, 2 * sizeof (struct serial_struct));
+
+	serial->type = PORT_16550A;
+	serial->line = 0;
+	serial->port = sio_dev.sp1_base;
+	serial->port_high = 0;
+	serial->irq = sio_dev.irq_region->data.irqbase + SP1_IRQ;
+	serial->io_type = SERIAL_IO_PORT;
+	serial->flags = 0;
+	serial->xmit_fifo_size = 16;
+	serial->custom_divisor = 0;
+	serial->baud_base = 115200;
+
+	retval = register_serial(serial);
+	if (retval < 0) {
+		printk(KERN_WARNING "SuperIO: Register Serial #0 failed.\n");
+		kfree (serial);
+		return;
+	}
+
+	serial++;
+
+	serial->type = PORT_16550A;
+	serial->line = 1;
+	serial->port = sio_dev.sp2_base;
+	serial->port_high = 0;
+	serial->irq = sio_dev.irq_region->data.irqbase + SP2_IRQ;
+	serial->io_type = SERIAL_IO_PORT;
+	serial->flags = 0;
+	serial->xmit_fifo_size = 16;
+	serial->custom_divisor = 0;
+	serial->baud_base = 115200;
+
+	retval = register_serial(serial);
+	if (retval < 0)
+		printk(KERN_WARNING "SuperIO: Register Serial #1 failed.\n");
+#endif /* CONFIG_SERIAL */
+}
+
+EXPORT_SYMBOL(superio_serial_init);
+
+
+#ifdef CONFIG_PARPORT_PC
+void __devinit
+superio_parport_init(void)
+{
+	if (!sio_dev.irq_region)
+		return; /* superio not present */
+
+	if (!sio_dev.iosapic_irq_enabled)
+		superio_init(&sio_dev);
+
+	if (!parport_pc_probe_port(sio_dev.pp_base, 
+		0 /*base_hi*/,
+		sio_dev.irq_region->data.irqbase + PAR_IRQ, 
+		PARPORT_DMA_NONE /* dma */,
+		NULL /*struct pci_dev* */))
+
+		printk(KERN_WARNING "SuperIO: Probing parallel port failed.\n");
+}
+
+EXPORT_SYMBOL(superio_parport_init);
+#endif	/* CONFIG_PARPORT_PC */
+
+
+int
+superio_get_ide_irq(void)
+{
+	if (sio_dev.irq_region)
+		return sio_dev.irq_region->data.irqbase + IDE_IRQ;
+	else
+		return 0;
+}
+
+EXPORT_SYMBOL(superio_get_ide_irq);
+
+static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+#ifdef DEBUG_INIT
+	printk("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n",
+		dev->slot_name,
+		dev->vendor, dev->device,
+		dev->subsystem_vendor, dev->subsystem_device,
+		dev->class);
+/*
+** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a
+** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000
+** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310
+*/
+#endif
+
+	/* superio_fixup_irq(dev); */
+
+	if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) {
+#ifdef CONFIG_PARPORT_PC
+		superio_parport_init();
+#endif
+		/* Don't call superio_serial_init() - see rs_init() */
+		/* REVISIT : superio_fdc_init() ? */
+		return 0;
+	}
+	else
+	{
+		/* don't claim this device; let whatever either driver
+		 * do it 
+		 */ 
+		return -1;
+	}
+}
+
+static struct pci_device_id superio_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, }
+};
+
+static struct pci_driver superio_driver = {
+	name:		"SuperIO",
+	id_table:	superio_tbl,
+	probe:		superio_probe,
+};
+
+static int __init superio_modinit(void)
+{
+	return pci_module_init(&superio_driver);
+}
+
+static void __exit superio_exit(void)
+{
+	pci_unregister_driver(&superio_driver);
+}
+
+module_init(superio_modinit);
+module_exit(superio_exit);
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/sys32.h linux-2.4.20-pre2/arch/parisc/kernel/sys32.h
--- linux-2.4.20-pre1/arch/parisc/kernel/sys32.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/sys32.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,33 @@
+#ifndef _PARISC64_KERNEL_SYS32_H
+#define _PARISC64_KERNEL_SYS32_H
+
+/* Call a kernel syscall which will use kernel space instead of user
+ * space for its copy_to/from_user.
+ */
+#define KERNEL_SYSCALL(ret, syscall, args...) \
+{ \
+    mm_segment_t old_fs = get_fs(); \
+    set_fs(KERNEL_DS); \
+    ret = syscall(args); \
+    set_fs (old_fs); \
+}
+
+struct timeval32 {
+	int tv_sec;
+	int tv_usec;
+};
+
+typedef __u32 __sighandler_t32;
+
+#include <linux/signal.h>
+typedef struct {
+	unsigned int sig[_NSIG_WORDS * 2];
+} sigset_t32;
+
+struct sigaction32 {
+	__sighandler_t32 sa_handler;
+	unsigned int sa_flags;
+	sigset_t32 sa_mask;		/* mask last for extensibility */
+};
+
+#endif
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/sys_parisc.c linux-2.4.20-pre2/arch/parisc/kernel/sys_parisc.c
--- linux-2.4.20-pre1/arch/parisc/kernel/sys_parisc.c	Mon Mar 19 12:35:11 2001
+++ linux-2.4.20-pre2/arch/parisc/kernel/sys_parisc.c	Mon Aug 12 16:34:14 2002
@@ -1,7 +1,7 @@
 /*
  * linux/arch/parisc/kernel/sys_parisc.c
  *
- * this implements the missing syscalls.
+ * this implements syscalls which are handled per-arch.
  */
 
 #include <asm/uaccess.h>
@@ -10,26 +10,15 @@
 #include <linux/linkage.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/shm.h>
 #include <linux/smp_lock.h>
 
-/* for some reason, "old_readdir" is the only syscall which does not begin
- * with "sys_", which breaks the ENTRY_* macros in syscall.S so I "fixed"
- * it here.
- */
-
-int sys_old_readdir(unsigned int fd, void *dirent, unsigned int count)
-{
-    return old_readdir(fd, dirent, count);
-}
-
 int sys_pipe(int *fildes)
 {
 	int fd[2];
 	int error;
 
-	lock_kernel();
 	error = do_pipe(fd);
-	unlock_kernel();
 	if (!error) {
 		if (copy_to_user(fildes, fd, 2*sizeof(int)))
 			error = -EFAULT;
@@ -44,40 +33,117 @@
 	return -ERESTARTNOHAND;
 }
 
-int sys_mmap(unsigned long addr, unsigned long len,
-		unsigned long prot, unsigned long flags, unsigned long fd,
-		unsigned long offset)
+static unsigned long get_unshared_area(unsigned long addr, unsigned long len)
 {
-	struct file * file = NULL;
-	int error;
+	struct vm_area_struct *vma;
 
-	down_write(&current->mm->mmap_sem);
-	lock_kernel();
+	if (!addr)
+		addr = TASK_UNMAPPED_BASE;
+	addr = PAGE_ALIGN(addr);
+
+	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+		/* At this point:  (!vma || addr < vma->vm_end). */
+		if (TASK_SIZE - len < addr)
+			return -ENOMEM;
+		if (!vma || addr + len <= vma->vm_start)
+			return addr;
+		addr = vma->vm_end;
+	}
+}
+
+#define DCACHE_ALIGN(addr) (((addr) + (SHMLBA - 1)) &~ (SHMLBA - 1))
+
+static unsigned long get_shared_area(struct inode *inode, unsigned long addr,
+		unsigned long len, unsigned long pgoff)
+{
+	struct vm_area_struct *vma, *first_vma;
+	int offset;
+
+	first_vma = inode->i_mapping->i_mmap_shared;
+	offset = (first_vma->vm_start + ((pgoff - first_vma->vm_pgoff) << PAGE_SHIFT)) & (SHMLBA - 1);
+
+	if (!addr)
+		addr = TASK_UNMAPPED_BASE;
+	addr = DCACHE_ALIGN(addr - offset) + offset;
+
+	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+		/* At this point:  (!vma || addr < vma->vm_end). */
+		if (TASK_SIZE - len < addr)
+			return -ENOMEM;
+		if (!vma || addr + len <= vma->vm_start)
+			return addr;
+		addr = DCACHE_ALIGN(vma->vm_end - offset) + offset;
+		if (addr < vma->vm_end) /* handle wraparound */
+			return -ENOMEM;
+	}
+}
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+		unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	struct inode *inode = NULL;
+
+	if (len > TASK_SIZE)
+		return -ENOMEM;
+
+	if (filp) {
+		inode = filp->f_dentry->d_inode;
+	}
+
+	if (inode && (flags & MAP_SHARED) && (inode->i_mapping->i_mmap_shared)) {
+		addr = get_shared_area(inode, addr, len, pgoff);
+	} else {
+		addr = get_unshared_area(addr, len);
+	}
+	return addr;
+}
+
+static unsigned long do_mmap2(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags, unsigned long fd,
+	unsigned long pgoff)
+{
+	struct file * file = NULL;
+	unsigned long error = -EBADF;
 	if (!(flags & MAP_ANONYMOUS)) {
-		error = -EBADF;
 		file = fget(fd);
 		if (!file)
 			goto out;
 	}
+
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	error = do_mmap(file, addr, len, prot, flags, offset);
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
 	if (file != NULL)
 		fput(file);
 out:
-	unlock_kernel();
-	up_write(&current->mm->mmap_sem);
 	return error;
 }
 
-int sys_ioperm(unsigned long from, unsigned long num, int on)
+asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags, unsigned long fd,
+	unsigned long pgoff)
 {
-	return -ENOSYS;
+	/* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
+	   we have. */
+	return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
 }
 
-long sys_shmat_wrapper(int shmid, void *shmaddr, int shmflag)
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+		unsigned long prot, unsigned long flags, unsigned long fd,
+		unsigned long offset)
+{
+	if (!(offset & ~PAGE_MASK)) {
+		return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+	} else {
+		return -EINVAL;
+	}
+}
+
+long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag)
 {
-	extern int sys_shmat(int shmid, char *shmaddr, int shmflg,
-			     unsigned long * raddr);
 	unsigned long raddr;
 	int r;
 
@@ -86,3 +152,107 @@
 		return r;
 	return raddr;
 }
+
+
+/*
+ * FIXME, please remove this crap as soon as possible
+ *
+ * This is here to fix up broken glibc structures, 
+ * which are already fixed in newer glibcs
+ */
+#include <linux/msg.h>
+#include <linux/sem.h>
+#include <linux/shm.h>
+#include "sys32.h"
+
+struct broken_ipc_perm
+{
+    key_t key;			/* Key.  */
+    uid_t uid;			/* Owner's user ID.  */
+    gid_t gid;			/* Owner's group ID.  */
+    uid_t cuid;			/* Creator's user ID.  */
+    gid_t cgid;			/* Creator's group ID.  */
+    unsigned short int mode;		/* Read/write permission.  */
+    unsigned short int __pad1;
+    unsigned short int seq;		/* Sequence number.  */
+    unsigned short int __pad2;
+    unsigned long int __unused1;
+    unsigned long int __unused2;
+};
+		    
+struct broken_shmid64_ds {
+	struct broken_ipc_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+#ifndef __LP64__
+	unsigned int		__pad1;
+#endif
+	__kernel_time_t		shm_atime;	/* last attach time */
+#ifndef __LP64__
+	unsigned int		__pad2;
+#endif
+	__kernel_time_t		shm_dtime;	/* last detach time */
+#ifndef __LP64__
+	unsigned int		__pad3;
+#endif
+	__kernel_time_t		shm_ctime;	/* last change time */
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned int		shm_nattch;	/* no. of current attaches */
+	unsigned int		__unused1;
+	unsigned int		__unused2;
+};
+
+static void convert_broken_perm (struct broken_ipc_perm *out, struct ipc64_perm *in)
+{
+	out->key  = in->key;
+	out->uid  = in->uid;
+	out->gid  = in->gid;
+	out->cuid = in->cuid;
+	out->cgid = in->cgid;
+	out->mode = in->mode;
+	out->seq  = in->seq;
+}
+
+static int copyout_broken_shmid64(struct broken_shmid64_ds *buf, struct shmid64_ds *sbuf)
+{
+	struct broken_shmid64_ds tbuf;
+	
+	memset(&tbuf, 0, sizeof tbuf);
+	convert_broken_perm (&tbuf.shm_perm, &sbuf->shm_perm);
+	tbuf.shm_segsz = sbuf->shm_segsz;
+	tbuf.shm_atime = sbuf->shm_atime;
+	tbuf.shm_dtime = sbuf->shm_dtime;
+	tbuf.shm_ctime = sbuf->shm_ctime;
+	tbuf.shm_cpid = sbuf->shm_cpid;
+	tbuf.shm_lpid = sbuf->shm_lpid;
+	tbuf.shm_nattch = sbuf->shm_nattch;
+	return copy_to_user(buf, &tbuf, sizeof tbuf);
+}
+
+int sys_msgctl_broken(int msqid, int cmd, struct msqid_ds *buf)
+{
+	return sys_msgctl (msqid, cmd & ~IPC_64, buf);
+}
+
+int sys_semctl_broken(int semid, int semnum, int cmd, union semun arg)
+{
+	return sys_semctl (semid, semnum, cmd & ~IPC_64, arg);
+}
+
+int sys_shmctl_broken(int shmid, int cmd, struct shmid64_ds *buf)
+{
+	struct shmid64_ds sbuf;
+	int err;
+
+	if (cmd & IPC_64) {
+		cmd &= ~IPC_64;
+		if (cmd == IPC_STAT || cmd == SHM_STAT) {
+			KERNEL_SYSCALL(err, sys_shmctl, shmid, cmd, (struct shmid_ds *)&sbuf);
+			if (err == 0)
+				err = copyout_broken_shmid64((struct broken_shmid64_ds *)buf, &sbuf);
+			return err;
+		}
+	}
+	return sys_shmctl (shmid, cmd, (struct shmid_ds *)buf);
+}
+
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/sys_parisc32.c linux-2.4.20-pre2/arch/parisc/kernel/sys_parisc32.c
--- linux-2.4.20-pre1/arch/parisc/kernel/sys_parisc32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/sys_parisc32.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,3117 @@
+/*
+ * sys_parisc32.c: Conversion between 32bit and 64bit native syscalls.
+ *
+ * Copyright (C) 2000-2001 Hewlett Packard Company
+ * Copyright (C) 2000 John Marvin
+ * Copyright (C) 2001 Matthew Wilcox
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * environment. Based heavily on sys_ia32.c and sys_sparc32.c.
+ */
+
+#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>			/* for setsockopt() */
+#include <linux/icmpv6.h>			/* for setsockopt() */
+#include <linux/netfilter_ipv4/ip_queue.h>	/* for setsockopt() */
+#include <linux/netfilter_ipv4/ip_tables.h>	/* for setsockopt() */
+#include <linux/netfilter_ipv6/ip6_tables.h>	/* for setsockopt() */
+#include <linux/highmem.h>
+#include <linux/highuid.h>
+#include <linux/mman.h>
+
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include "sys32.h"
+
+#define A(__x) ((unsigned long)(__x))
+
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x)	printk x
+#else
+#define DBG(x)
+#endif
+
+
+/*
+ * count32() counts the number of arguments/envelopes. It is basically
+ *           a copy of count() from fs/exec.c, except that it works
+ *           with 32 bit argv and envp pointers.
+ */
+
+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_strings32() is basically a copy of copy_strings() from fs/exec.c
+ *                  except that it works with 32 bit argv and envp pointers.
+ */
+
+
+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 > 0) {
+			char *kaddr;
+			int i, new, err;
+			struct page *page;
+			int offset, bytes_to_copy;
+
+			offset = pos % PAGE_SIZE;
+			i = pos/PAGE_SIZE;
+			page = bprm->page[i];
+			new = 0;
+			if (!page) {
+				page = alloc_page(GFP_HIGHUSER);
+				bprm->page[i] = 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_dcache_page(page);
+			flush_page_to_ram(page);
+			kunmap(page);
+
+			if (err)
+				return -EFAULT; 
+
+			pos += bytes_to_copy;
+			str += bytes_to_copy;
+			len -= bytes_to_copy;
+		}
+	}
+	return 0;
+}
+
+/*
+ * do_execve32() is mostly a copy of do_execve(), with the exception
+ * that it processes 32 bit argv and envp pointers.
+ */
+
+static inline int 
+do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
+{
+	struct linux_binprm bprm;
+	struct file *file;
+	int retval;
+	int i;
+
+	file = open_exec(filename);
+
+	retval = PTR_ERR(file);
+	if (IS_ERR(file))
+		return retval;
+
+	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+	memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
+
+	DBG(("do_execve32(%s, %p, %p, %p)\n", filename, argv, envp, regs));
+
+	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.envc;
+	}
+
+	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++) {
+		struct page * page = bprm.page[i];
+		if (page)
+			__free_page(page);
+	}
+
+	return retval;
+}
+
+/*
+ * sys32_execve() executes a new program.
+ */
+
+asmlinkage int sys32_execve(struct pt_regs *regs)
+{
+	int error;
+	char *filename;
+
+	DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
+	filename = getname((char *) regs->gr[26]);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = do_execve32(filename, (u32 *) regs->gr[25],
+		(u32 *) regs->gr[24], regs);
+	if (error == 0)
+		current->ptrace &= ~PT_DTRACE;
+	putname(filename);
+out:
+
+	return error;
+}
+
+asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
+	int r22, int r21, int r20)
+{
+    printk(KERN_ERR "%s(%d): Unimplemented 32 on 64 syscall #%d!\n", 
+    	current->comm, current->pid, r20);
+    return -ENOSYS;
+}
+
+/* 32-bit user apps use struct statfs which uses 'long's */
+struct statfs32 {
+	__s32 f_type;
+	__s32 f_bsize;
+	__s32 f_blocks;
+	__s32 f_bfree;
+	__s32 f_bavail;
+	__s32 f_files;
+	__s32 f_ffree;
+	__kernel_fsid_t f_fsid;
+	__s32 f_namelen;
+	__s32 f_spare[6];
+};
+
+/* convert statfs struct to statfs32 struct and copy result to user */
+static unsigned long statfs32_to_user(struct statfs32 *ust32, struct statfs *st)
+{
+    struct statfs32 st32;
+#undef CP
+#define CP(a) st32.a = st->a
+    CP(f_type);
+    CP(f_bsize);
+    CP(f_blocks);
+    CP(f_bfree);
+    CP(f_bavail);
+    CP(f_files);
+    CP(f_ffree);
+    CP(f_fsid);
+    CP(f_namelen);
+    return copy_to_user(ust32, &st32, sizeof st32);
+}
+
+/* The following statfs calls are copies of code from linux/fs/open.c and
+ * should be checked against those from time to time */
+asmlinkage long sys32_statfs(const char * path, struct statfs32 * buf)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(path, &nd);
+	if (!error) {
+		struct statfs tmp;
+		error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
+		if (!error && statfs32_to_user(buf, &tmp))
+			error = -EFAULT;
+		path_release(&nd);
+	}
+	return error;
+}
+
+asmlinkage long sys32_fstatfs(unsigned int fd, struct statfs32 * buf)
+{
+	struct file * file;
+	struct statfs tmp;
+	int error;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+	error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
+	if (!error && statfs32_to_user(buf, &tmp))
+		error = -EFAULT;
+	fput(file);
+out:
+	return error;
+}
+
+/* These may not work without my local types changes, but I wanted the
+ * code available in case it's useful to others. -PB
+ */
+
+/* from utime.h */
+struct utimbuf32 {
+	__kernel_time_t32 actime;
+	__kernel_time_t32 modtime;
+};
+
+asmlinkage long sys32_utime(char *filename, struct utimbuf32 *times)
+{
+    struct utimbuf32 times32;
+    struct utimbuf times64;
+    extern long sys_utime(char *filename, struct utimbuf *times);
+    char *fname;
+    long ret;
+
+    if (!times)
+    	return sys_utime(filename, NULL);
+
+    /* get the 32-bit struct from user space */
+    if (copy_from_user(&times32, times, sizeof times32))
+    	return -EFAULT;
+
+    /* convert it into the 64-bit one */
+    times64.actime = times32.actime;
+    times64.modtime = times32.modtime;
+
+    /* grab the file name */
+    fname = getname(filename);
+
+    KERNEL_SYSCALL(ret, sys_utime, fname, &times64);
+
+    /* free the file name */
+    putname(fname);
+
+    return ret;
+}
+
+struct tms32 {
+	__kernel_clock_t32 tms_utime;
+	__kernel_clock_t32 tms_stime;
+	__kernel_clock_t32 tms_cutime;
+	__kernel_clock_t32 tms_cstime;
+};
+                                
+asmlinkage long sys32_times(struct tms32 *tbuf)
+{
+	struct tms t;
+	long ret;
+	extern asmlinkage long sys_times(struct tms * tbuf);
+int err;
+	
+	KERNEL_SYSCALL(ret, sys_times, tbuf ? &t : NULL);
+	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;
+	}
+	return ret;
+}
+
+struct flock32 {
+	short l_type;
+	short l_whence;
+	__kernel_off_t32 l_start;
+	__kernel_off_t32 l_len;
+	__kernel_pid_t32 l_pid;
+};
+
+
+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;
+			long ret;
+			
+			if(get_flock(&f, (struct flock32 *)arg))
+				return -EFAULT;
+			KERNEL_SYSCALL(ret, sys_fcntl, fd, cmd, (unsigned long)&f);
+			if (ret) return ret;
+			if (f.l_start >= 0x7fffffffUL ||
+			    f.l_len >= 0x7fffffffUL ||
+			    f.l_start + f.l_len >= 0x7fffffffUL)
+				return -EOVERFLOW;
+			if(put_flock(&f, (struct flock32 *)arg))
+				return -EFAULT;
+			return 0;
+		}
+	default:
+		return sys_fcntl(fd, cmd, (unsigned long)arg);
+	}
+}
+
+#ifdef CONFIG_SYSCTL
+
+struct __sysctl_args32 {
+	u32 name;
+	int nlen;
+	u32 oldval;
+	u32 oldlenp;
+	u32 newval;
+	u32 newlen;
+	u32 __unused[4];
+};
+
+asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
+{
+	struct __sysctl_args32 tmp;
+	int error;
+	unsigned int oldlen32;
+	size_t oldlen, *oldlenp = NULL;
+	unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+	extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
+	       void *newval, size_t newlen);
+
+	DBG(("sysctl32(%p)\n", args));
+
+	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.  */
+		/* a possibly better hack than this, which will avoid the
+		 * problem if the struct is read only, is to push the
+		 * 'oldlen' value out to the user's stack instead. -PB
+		 */
+		if (get_user(oldlen32, (u32 *)(u64)tmp.oldlenp))
+			return -EFAULT;
+		oldlen = oldlen32;
+		if (put_user(oldlen, (size_t *)addr))
+			return -EFAULT;
+		oldlenp = (size_t *)addr;
+	}
+
+	lock_kernel();
+	error = do_sysctl((int *)(u64)tmp.name, tmp.nlen, (void *)(u64)tmp.oldval,
+			  oldlenp, (void *)(u64)tmp.newval, tmp.newlen);
+	unlock_kernel();
+	if (oldlenp) {
+		if (!error) {
+			if (get_user(oldlen, (size_t *)addr)) {
+				error = -EFAULT;
+			} else {
+				oldlen32 = oldlen;
+				if (put_user(oldlen32, (u32 *)(u64)tmp.oldlenp))
+					error = -EFAULT;
+			}
+		}
+		if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+#else /* CONFIG_SYSCTL */
+
+asmlinkage long sys32_sysctl(struct __sysctl_args *args)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_SYSCTL */
+
+struct timespec32 {
+	s32    tv_sec;
+	s32    tv_nsec;
+};
+                
+static int
+put_timespec32(struct timespec32 *u, struct timespec *t)
+{
+	struct timespec32 t32;
+	t32.tv_sec = t->tv_sec;
+	t32.tv_nsec = t->tv_nsec;
+	return copy_to_user(u, &t32, sizeof t32);
+}
+
+asmlinkage int sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
+{
+	struct timespec t;
+	struct timespec32 t32;
+	int ret;
+	extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+	
+	if (copy_from_user(&t32, rqtp, sizeof t32))
+		return -EFAULT;
+	t.tv_sec = t32.tv_sec;
+	t.tv_nsec = t32.tv_nsec;
+
+	DBG(("sys32_nanosleep({%d, %d})\n", t32.tv_sec, t32.tv_nsec));
+
+	KERNEL_SYSCALL(ret, sys_nanosleep, &t, rmtp ? &t : NULL);
+	if (rmtp && ret == -EINTR) {
+		if (put_timespec32(rmtp, &t))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
+	struct timespec32 *interval)
+{
+	struct timespec t;
+	int ret;
+	extern asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
+	
+	KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, &t);
+	if (put_timespec32(interval, &t))
+		return -EFAULT;
+	return ret;
+}
+
+typedef __kernel_time_t32 time_t32;
+
+static int
+put_timeval32(struct timeval32 *u, struct timeval *t)
+{
+	struct timeval32 t32;
+	t32.tv_sec = t->tv_sec;
+	t32.tv_usec = t->tv_usec;
+	return copy_to_user(u, &t32, sizeof t32);
+}
+
+static int
+get_timeval32(struct timeval32 *u, struct timeval *t)
+{
+	int err;
+	struct timeval32 t32;
+
+	if ((err = copy_from_user(&t32, u, sizeof t32)) == 0)
+	{
+	    t->tv_sec = t32.tv_sec;
+	    t->tv_usec = t32.tv_usec;
+	}
+	return err;
+}
+
+asmlinkage long sys32_time(time_t32 *tloc)
+{
+    time_t now = CURRENT_TIME;
+    time_t32 now32 = now;
+
+    if (tloc)
+    	if (put_user(now32, tloc))
+		now32 = -EFAULT;
+
+    return now32;
+}
+
+asmlinkage int
+sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+    extern void do_gettimeofday(struct timeval *tv);
+
+    if (tv) {
+	    struct timeval ktv;
+	    do_gettimeofday(&ktv);
+	    if (put_timeval32(tv, &ktv))
+		    return -EFAULT;
+    }
+    if (tz) {
+	    extern struct timezone sys_tz;
+	    if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+		    return -EFAULT;
+    }
+    return 0;
+}
+
+asmlinkage int
+sys32_settimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+    struct timeval ktv;
+    struct timezone ktz;
+    extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
+    if (tv) {
+	    if (get_timeval32(tv, &ktv))
+		    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	itimerval32 {
+	struct	timeval32 it_interval;	/* timer interval */
+	struct	timeval32 it_value;	/* current value */
+};
+
+asmlinkage long sys32_getitimer(int which, struct itimerval32 *ov32)
+{
+	int error = -EFAULT;
+	struct itimerval get_buffer;
+	extern int do_getitimer(int which, struct itimerval *value);
+
+	if (ov32) {
+		error = do_getitimer(which, &get_buffer);
+		if (!error) {
+			struct itimerval32 gb32;
+			gb32.it_interval.tv_sec = get_buffer.it_interval.tv_sec;
+			gb32.it_interval.tv_usec = get_buffer.it_interval.tv_usec;
+			gb32.it_value.tv_sec = get_buffer.it_value.tv_sec;
+			gb32.it_value.tv_usec = get_buffer.it_value.tv_usec;
+			if (copy_to_user(ov32, &gb32, sizeof(gb32)))
+				error = -EFAULT; 
+		}
+	}
+	return error;
+}
+
+asmlinkage long sys32_setitimer(int which, struct itimerval32 *v32,
+			      struct itimerval32 *ov32)
+{
+	struct itimerval set_buffer, get_buffer;
+	struct itimerval32 sb32, gb32;
+	extern int do_setitimer(int which, struct itimerval *value, struct itimerval *ov32);
+	int error;
+
+	if (v32) {
+		if(copy_from_user(&sb32, v32, sizeof(sb32)))
+			return -EFAULT;
+
+		set_buffer.it_interval.tv_sec = sb32.it_interval.tv_sec;
+		set_buffer.it_interval.tv_usec = sb32.it_interval.tv_usec;
+		set_buffer.it_value.tv_sec = sb32.it_value.tv_sec;
+		set_buffer.it_value.tv_usec = sb32.it_value.tv_usec;
+	} else
+		memset((char *) &set_buffer, 0, sizeof(set_buffer));
+
+	error = do_setitimer(which, &set_buffer, ov32 ? &get_buffer : 0);
+	if (error || !ov32)
+		return error;
+
+	gb32.it_interval.tv_sec = get_buffer.it_interval.tv_sec;
+	gb32.it_interval.tv_usec = get_buffer.it_interval.tv_usec;
+	gb32.it_value.tv_sec = get_buffer.it_value.tv_sec;
+	gb32.it_value.tv_usec = get_buffer.it_value.tv_usec;
+	if (copy_to_user(ov32, &gb32, sizeof(gb32)))
+		return -EFAULT; 
+	return 0;
+}
+
+struct rusage32 {
+        struct timeval32 ru_utime;
+        struct timeval32 ru_stime;
+        int    ru_maxrss;
+        int    ru_ixrss;
+        int    ru_idrss;
+        int    ru_isrss;
+        int    ru_minflt;
+        int    ru_majflt;
+        int    ru_nswap;
+        int    ru_inblock;
+        int    ru_oublock;
+        int    ru_msgsnd; 
+        int    ru_msgrcv; 
+        int    ru_nsignals;
+        int    ru_nvcsw;
+        int    ru_nivcsw;
+};
+
+static int
+put_rusage32(struct rusage32 *ru32p, struct rusage *r)
+{
+	struct rusage32 r32;
+#undef CP
+#define CP(t) r32.t = r->t;
+	CP(ru_utime.tv_sec); CP(ru_utime.tv_usec);
+	CP(ru_stime.tv_sec); CP(ru_stime.tv_usec);
+	CP(ru_maxrss);
+	CP(ru_ixrss);
+	CP(ru_idrss);
+	CP(ru_isrss);
+	CP(ru_minflt);
+	CP(ru_majflt);
+	CP(ru_nswap);
+	CP(ru_inblock);
+	CP(ru_oublock);
+	CP(ru_msgsnd);
+	CP(ru_msgrcv);
+	CP(ru_nsignals);
+	CP(ru_nvcsw);
+	CP(ru_nivcsw);
+	return copy_to_user(ru32p, &r32, sizeof r32);
+}
+
+asmlinkage int
+sys32_getrusage(int who, struct rusage32 *ru)
+{
+	struct rusage r;
+	int ret;
+	extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
+		
+	KERNEL_SYSCALL(ret, sys_getrusage, who, &r);
+	if (put_rusage32(ru, &r)) return -EFAULT;
+	return ret;
+}
+
+asmlinkage int
+sys32_wait4(__kernel_pid_t32 pid, unsigned int * stat_addr, int options,
+	    struct rusage32 * ru)
+{
+	if (!ru)
+		return sys_wait4(pid, stat_addr, options, NULL);
+	else {
+		struct rusage r;
+		int ret;
+		unsigned int status;
+	
+		KERNEL_SYSCALL(ret, sys_wait4, pid, stat_addr ? &status : NULL, options, &r);
+		if (put_rusage32(ru, &r)) return -EFAULT;
+		if (stat_addr && put_user(status, stat_addr))
+			return -EFAULT;
+		return ret;
+	}
+}
+
+struct stat32 {
+	__kernel_dev_t32		st_dev;		/* dev_t is 32 bits on parisc */
+	__kernel_ino_t32		st_ino;		/* 32 bits */
+	__kernel_mode_t32	st_mode;	/* 16 bits */
+	__kernel_nlink_t32		st_nlink;	/* 16 bits */
+	unsigned short	st_reserved1;	/* old st_uid */
+	unsigned short	st_reserved2;	/* old st_gid */
+	__kernel_dev_t32		st_rdev;
+	__kernel_off_t32		st_size;
+	__kernel_time_t32	st_atime;
+	unsigned int	st_spare1;
+	__kernel_time_t32	st_mtime;
+	unsigned int	st_spare2;
+	__kernel_time_t32	st_ctime;
+	unsigned int	st_spare3;
+	int		st_blksize;
+	int		st_blocks;
+	unsigned int	__unused1;	/* ACL stuff */
+	__kernel_dev_t32		__unused2;	/* network */
+	__kernel_ino_t32		__unused3;	/* network */
+	unsigned int	__unused4;	/* cnodes */
+	unsigned short	__unused5;	/* netsite */
+	short		st_fstype;
+	__kernel_dev_t32		st_realdev;
+	unsigned short	st_basemode;
+	unsigned short	st_spareshort;
+	__kernel_uid_t32		st_uid;
+	__kernel_gid_t32		st_gid;
+	unsigned int	st_spare4[3];
+};
+
+/*
+ * Revalidate the inode. This is required for proper NFS attribute caching.
+ */
+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;
+}
+
+
+static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
+{
+	struct stat32 tmp;
+	unsigned int blocks, indirect;
+
+	memset(&tmp, 0, sizeof(tmp));
+	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_STAT_UID(tmp, inode->i_uid);
+	SET_STAT_GID(tmp, inode->i_gid);
+	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
+#if BITS_PER_LONG == 32
+	if (inode->i_size > 0x7fffffff)
+		return -EOVERFLOW;
+#endif	
+	tmp.st_size = inode->i_size;
+	tmp.st_atime = inode->i_atime;
+	tmp.st_mtime = inode->i_mtime;
+	tmp.st_ctime = inode->i_ctime;
+/*
+ * st_blocks and st_blksize are approximated with a simple algorithm if
+ * they aren't supported directly by the filesystem. The minix and msdos
+ * filesystems don't keep track of blocks, so they would either have to
+ * be counted explicitly (by delving into the file itself), or by using
+ * this simple algorithm to get a reasonable (although not 100% accurate)
+ * value.
+ */
+
+/*
+ * Use minix fs values for the number of direct and indirect blocks.  The
+ * count is now exact for the minix fs except that it counts zero blocks.
+ * Everything is in units of BLOCK_SIZE until the assignment to
+ * tmp.st_blksize.
+ */
+#define D_B   7
+#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
+
+	if (!inode->i_blksize) {
+		blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+		if (blocks > D_B) {
+			indirect = (blocks - D_B + I_B - 1) / I_B;
+			blocks += indirect;
+			if (indirect > 1) {
+				indirect = (indirect - 1 + I_B - 1) / I_B;
+				blocks += indirect;
+				if (indirect > 1)
+					blocks++;
+			}
+		}
+		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
+		tmp.st_blksize = BLOCK_SIZE;
+	} else {
+		tmp.st_blocks = inode->i_blocks;
+		tmp.st_blksize = inode->i_blksize;
+	}
+	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
+
+asmlinkage long sys32_newstat(char * filename, struct stat32 *statbuf)
+{
+	struct nameidata nd;
+	int error;
+
+	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;
+
+	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;
+
+	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;
+}
+
+struct linux32_dirent {
+	u32	d_ino;
+	__kernel_off_t32	d_off;
+	u16	d_reclen;
+	char	d_name[1];
+};
+
+struct old_linux32_dirent {
+	u32	d_ino;
+	u32	d_offset;
+	u16	d_namlen;
+	char	d_name[1];
+};
+
+struct getdents32_callback {
+	struct linux32_dirent * current_dir;
+	struct linux32_dirent * previous;
+	int count;
+	int error;
+};
+
+struct readdir32_callback {
+	struct old_linux32_dirent * dirent;
+	int count;
+};
+
+#define ROUND_UP(x,a)	((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+static int
+filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
+	   unsigned int d_type)
+{
+	struct linux32_dirent * dirent;
+	struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
+	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
+
+	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);
+	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, void * dirent, unsigned int count)
+{
+	struct file * file;
+	struct linux32_dirent * lastdirent;
+	struct getdents32_callback buf;
+	int error;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.current_dir = (struct linux32_dirent *) dirent;
+	buf.previous = NULL;
+	buf.count = count;
+	buf.error = 0;
+
+	error = vfs_readdir(file, filldir32, &buf);
+	if (error < 0)
+		goto out_putf;
+	error = buf.error;
+	lastdirent = buf.previous;
+	if (lastdirent) {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = count - buf.count;
+	}
+
+out_putf:
+	fput(file);
+out:
+	return error;
+}
+
+static int
+fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino,
+	      unsigned int d_type)
+{
+	struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
+	struct old_linux32_dirent * 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 long
+sys32_readdir (unsigned int fd, void * dirent, unsigned int count)
+{
+	int error;
+	struct file * file;
+	struct readdir32_callback buf;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.count = 0;
+	buf.dirent = dirent;
+
+	error = vfs_readdir(file, fillonedir32, &buf);
+	if (error >= 0)
+		error = buf.count;
+	fput(file);
+out:
+	return error;
+}
+
+struct rlimit32 {
+	__u32	rlim_cur;
+	__u32	rlim_max;
+};
+
+#define RLIM32_INFINITY 0xffffffff
+
+asmlinkage long sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit32 rlim32;
+	struct rlimit *rlimip;
+
+	if (resource >= RLIM_NLIMITS)
+		return -EINVAL;
+	rlimip = current->rlim + resource;
+	if (rlimip->rlim_cur >= RLIM32_INFINITY) {
+		rlim32.rlim_cur = RLIM32_INFINITY;
+	} else {
+		rlim32.rlim_cur = rlimip->rlim_cur;
+	}
+	if (rlimip->rlim_max >= RLIM32_INFINITY) {
+		rlim32.rlim_max = RLIM32_INFINITY;
+	} else {
+		rlim32.rlim_max = rlimip->rlim_max;
+	}
+	return copy_to_user(rlim, &rlim32, sizeof (struct rlimit32));
+}
+
+asmlinkage long sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit32 rlim32;
+	struct rlimit new_rlim, *old_rlim;
+
+	if (resource >= RLIM_NLIMITS)
+		return -EINVAL;
+	if (copy_from_user(&rlim32, rlim, sizeof(rlim)))
+		return -EFAULT;
+	if (rlim32.rlim_cur == RLIM32_INFINITY) {
+		new_rlim.rlim_cur = RLIM_INFINITY;
+	} else {
+		new_rlim.rlim_cur = rlim32.rlim_cur;
+	}
+	if (rlim32.rlim_max == RLIM32_INFINITY) {
+		new_rlim.rlim_max = RLIM_INFINITY;
+	} else {
+		new_rlim.rlim_max = rlim32.rlim_max;
+	}
+
+	old_rlim = current->rlim + resource;
+	if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
+	     (new_rlim.rlim_max > old_rlim->rlim_max)) &&
+	    !capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+	if (resource == RLIMIT_NOFILE) {
+		if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
+			return -EPERM;
+	}
+	if (resource == RLIMIT_STACK) {
+		if (new_rlim.rlim_max > 1024 * 1024 * 1024) {
+			new_rlim.rlim_max = 1024 * 1024 * 1024;
+		}
+		new_rlim.rlim_max = PAGE_ALIGN(new_rlim.rlim_max);
+	}
+	
+	*old_rlim = new_rlim;
+	return 0;
+}
+
+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 int 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;
+
+	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 *)(unsigned long)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)
+			panic("NCP mounts not yet supported 32/64 parisc");
+			/* do_ncp_super_data_conv((void *)data_page); */
+		else {
+			panic("SMB mounts not yet supported 32/64 parisc");
+			/* 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:
+	return err;
+}
+
+
+#ifdef CONFIG_MODULES
+
+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;
+}
+
+asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kernel_size_t32 bufsize, __kernel_size_t32 *ret)
+{
+	struct module *mod;
+	int err;
+
+	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 (which)
+	{
+	case 0:
+		err = 0;
+		break;
+	case QM_MODULES:
+		err = qm_modules(buf, bufsize, ret);
+		break;
+	case QM_DEPS:
+		err = qm_deps(mod, buf, bufsize, ret);
+		break;
+	case QM_REFS:
+		err = qm_refs(mod, buf, bufsize, ret);
+		break;
+	case QM_SYMBOLS:
+		err = qm_symbols(mod, buf, bufsize, ret);
+		break;
+	case QM_INFO:
+		err = qm_info(mod, buf, bufsize, ret);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+out:
+	unlock_kernel();
+	return err;
+}
+
+struct kernel_sym32 {
+	u32 value;
+	char name[60];
+};
+		 
+extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table);
+
+asmlinkage int sys32_get_kernel_syms(struct kernel_sym32 *table)
+{
+	int len, i;
+	struct kernel_sym *tbl;
+	mm_segment_t old_fs;
+	
+	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++) {
+		if (put_user (tbl[i].value, &table->value) ||
+		    copy_to_user (table->name, tbl[i].name, 60))
+			break;
+	}
+	kfree (tbl);
+	return i;
+}
+
+#else /* CONFIG_MODULES */
+
+asmlinkage int
+sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize,
+		 size_t *ret)
+{
+	/* Let the program know about the new interface.  Not that
+	   it'll do them much good.  */
+	if (which == 0)
+		return 0;
+
+	return -ENOSYS;
+}
+
+asmlinkage int
+sys32_get_kernel_syms(struct kernel_sym *table)
+{
+	return -ENOSYS;
+}
+
+#endif  /* CONFIG_MODULES */
+
+/* readv/writev stolen from mips64 */
+struct iovec32 { unsigned int iov_base; int 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(int fd, struct iovec32 *vector, u32 count)
+{
+	struct file *file;
+	ssize_t ret;
+
+	ret = -EBADF;
+	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:
+	return ret;
+}
+
+asmlinkage long
+sys32_writev(int fd, struct iovec32 *vector, u32 count)
+{
+	struct file *file;
+	ssize_t ret;
+
+	ret = -EBADF;
+	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:
+	return ret;
+}
+
+/********** Borrowed from sparc64 -- hardly reviewed, not tested *****/
+#include <net/scm.h>
+/* XXX This really belongs in some header file... -DaveM */
+#define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 
+					   16 for IP, 16 for IPX,
+					   24 for IPv6,
+					   about 80 for AX.25 */
+
+extern struct socket *sockfd_lookup(int fd, int *err);
+
+/* XXX This as well... */
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
+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;
+};
+
+/* Bleech... */
+#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)
+
+__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);
+}
+
+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;
+}
+
+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;
+}
+
+/* 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;
+}
+
+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;
+
+		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
+		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
+	}
+
+	/* 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 int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned 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;
+
+	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:
+	return err;
+}
+
+asmlinkage int 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;
+
+	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)
+		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;
+	return len;
+}
+
+
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+				     char *optval, int optlen);
+
+static int do_set_attach_filter(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	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;
+}
+
+static int do_set_icmpv6_filter(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct icmp6_filter kfilter;
+	mm_segment_t old_fs;
+	int ret, i;
+
+	if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
+		return -EFAULT;
+
+
+	for (i = 0; i < 8; i += 2) {
+		u32 tmp = kfilter.data[i];
+
+		kfilter.data[i] = kfilter.data[i + 1];
+		kfilter.data[i + 1] = tmp;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *) &kfilter, sizeof(kfilter));
+	set_fs(old_fs);
+
+	return ret;
+}
+
+
+static int do_ipv4_set_replace(int fd, int level, int optname,
+				char *optval, int optlen)
+#if 1
+/* Fields happen to be padded such that this works.
+** Don't need to change iptables.h:struct ipt_replace
+*/
+{
+	struct ipt_replace *repl = (struct ipt_replace *) optval;
+	unsigned long ptr64;
+	unsigned int ptr32;
+	int ret;
+
+	if (copy_from_user(&ptr32, &repl->counters, sizeof(ptr32)))
+		return -EFAULT;
+	ptr64 = (unsigned long) ptr32;
+	if (copy_to_user(&repl->counters, &ptr64, sizeof(ptr64)))
+		return -EFAULT;
+
+	ret = sys_setsockopt(fd, level, optname, (char *) optval, optlen);
+
+	/* Restore 32-bit ptr */
+	if (copy_to_user(&repl->counters, &ptr32, sizeof(ptr32)))
+		return -EFAULT;
+
+	return ret;
+}
+#else
+/* This version tries to "do it right". ie allocate kernel buffers for
+** everything and copy data in/out. Way too complicated.
+** NOT TESTED for correctness!
+*/
+{
+	struct ipt_replace  *kern_repl;
+	struct ipt_counters *kern_counters;
+	unsigned int user_counters;
+	mm_segment_t old_fs;
+	int ret = 0;
+
+	kern_repl = (struct ipt_replace *) kmalloc(optlen+8, GFP_KERNEL);
+	if (!kern_repl)
+		return -ENOMEM;
+
+	if (copy_from_user(kern_repl, optval, optlen)) {
+		ret = -EFAULT;
+		goto err02;
+	}
+
+	/* 32-bit ptr is in the MSB's */
+	user_counters = (unsigned int) (((unsigned long) kern_repl->counters) >> 32);
+	/*
+	** We are going to set_fs() to kernel space - and thus need
+	** "relocate" the counters buffer to the kernel space.
+	*/
+	kern_counters = (struct ipt_counters *) kmalloc(kern_repl->num_counters * sizeof(struct ipt_counters), GFP_KERNEL);
+	if (!user_counters) {
+		ret = -ENOMEM;
+		goto err02;
+	}
+
+	if (copy_from_user(kern_counters, (char *) user_counters, optlen)) {
+		ret = -EFAULT;
+		goto err01;
+	}
+
+	/* We can update the kernel ptr now that we have the data. */
+	kern_repl->counters = kern_counters;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	ret = sys_setsockopt(fd, level, optname, (char *) optval, optlen);
+
+	set_fs(old_fs);
+
+	/* Copy counters back out to user space */
+	if (copy_to_user((char *) user_counters, kern_counters,
+			kern_repl->num_counters * sizeof(struct ipt_counters)))
+	{
+		ret = -EFAULT;
+		goto err01;
+	}
+
+	/* restore counters so userspace can consume it */
+	kern_repl->counters = NULL;
+	(unsigned int) kern_repl->counters = user_counters;
+
+	/* Copy repl back out to user space */
+	if (copy_to_user(optval, kern_repl, optlen))
+	{
+		ret = -EFAULT;
+	}
+
+err01:
+	kfree(kern_counters);
+err02:
+	kfree(kern_repl);
+	return ret;
+}
+#endif
+
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	if (optname == SO_ATTACH_FILTER)
+		return do_set_attach_filter(fd, level, optname, optval, optlen);
+
+	if (level == SOL_ICMPV6   && optname == ICMPV6_FILTER)
+		return do_set_icmpv6_filter(fd, level, optname, optval, optlen);
+
+	/*
+	** Beware:    IPT_SO_SET_REPLACE == IP6T_SO_SET_REPLACE
+	*/
+	if (level == IPPROTO_IP   && optname == IPT_SO_SET_REPLACE)
+		return do_ipv4_set_replace(fd, level, optname, optval, optlen);
+
+	if (level == IPPROTO_IPV6 && optname == IP6T_SO_SET_REPLACE)
+#if 0
+		/* FIXME: I don't (yet) use IPV6. -ggg */
+		return do_ipv6_set_replace(fd, level, optname, optval, optlen);
+#else
+	{
+		BUG();
+		return -ENXIO;
+	}
+#endif
+
+	return sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
+
+/*** copied from mips64 ***/
+/*
+ * 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, u32 *ufdset, unsigned long *fdset)
+{
+	n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
+	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;
+	n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
+
+	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);
+}
+
+/*** This is a virtual copy of sys_select from fs/select.c and probably
+ *** should be compared to it from time to time
+ ***/
+static inline void *select_bits_alloc(int size)
+{
+	return kmalloc(6 * size, GFP_KERNEL);
+}
+
+static inline void select_bits_free(void *bits, int size)
+{
+	kfree(bits);
+}
+
+/*
+ * We can actually return ERESTARTSYS instead of EINTR, but I'd
+ * like to be certain this leads to no problems. So I return
+ * EINTR just for safety.
+ *
+ * Update: ERESTARTSYS breaks at least the xview clock binary, so
+ * I'm trying ERESTARTNOHAND which restart only when you want to.
+ */
+#define MAX_SELECT_SECONDS \
+	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+#define DIVIDE_ROUND_UP(x,y) (((x)+(y)-1)/(y))
+
+asmlinkage long
+sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, struct timeval32 *tvp)
+{
+	fd_set_bits fds;
+	char *bits;
+	long timeout;
+	int ret, size, err;
+
+	timeout = MAX_SCHEDULE_TIMEOUT;
+	if (tvp) {
+		struct timeval32 tv32;
+		time_t sec, usec;
+
+		if ((ret = copy_from_user(&tv32, tvp, sizeof tv32)))
+			goto out_nofds;
+
+		sec = tv32.tv_sec;
+		usec = tv32.tv_usec;
+
+		ret = -EINVAL;
+		if (sec < 0 || usec < 0)
+			goto out_nofds;
+
+		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+			timeout = DIVIDE_ROUND_UP(usec, 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 = select_bits_alloc(size);
+	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);
+
+	if ((ret = get_fd_set32(n, inp, fds.in)) ||
+	    (ret = get_fd_set32(n, outp, fds.out)) ||
+	    (ret = get_fd_set32(n, exp, fds.ex)))
+		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);
+		}
+		err = put_user(sec, &tvp->tv_sec);
+		err |= __put_user(usec, &tvp->tv_usec);
+		if (err)
+			ret = -EFAULT;
+	}
+
+	if (ret < 0)
+		goto out;
+	if (!ret) {
+		ret = -ERESTARTNOHAND;
+		if (signal_pending(current))
+			goto out;
+		ret = 0;
+	}
+
+	set_fd_set32(n, inp, fds.res_in);
+	set_fd_set32(n, outp, fds.res_out);
+	set_fd_set32(n, exp, fds.res_ex);
+
+out:
+	select_bits_free(bits, size);
+out_nofds:
+	return ret;
+}
+
+struct msgbuf32 {
+    int mtype;
+    char mtext[1];
+};
+
+asmlinkage long sys32_msgsnd(int msqid,
+				struct msgbuf32 *umsgp32,
+				size_t msgsz, int msgflg)
+{
+	struct msgbuf *mb;
+	struct msgbuf32 mb32;
+	int err;
+
+	if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	err = get_user(mb32.mtype, &umsgp32->mtype);
+	mb->mtype = mb32.mtype;
+	err |= copy_from_user(mb->mtext, &umsgp32->mtext, msgsz);
+
+	if (err)
+		err = -EFAULT;
+	else
+		KERNEL_SYSCALL(err, sys_msgsnd, msqid, mb, msgsz, msgflg);
+
+	kfree(mb);
+	return err;
+}
+
+asmlinkage long sys32_msgrcv(int msqid,
+				struct msgbuf32 *umsgp32,
+				size_t msgsz, long msgtyp, int msgflg)
+{
+	struct msgbuf *mb;
+	struct msgbuf32 mb32;
+	int err, len;
+
+	if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	KERNEL_SYSCALL(err, sys_msgrcv, msqid, mb, msgsz, msgtyp, msgflg);
+
+	if (err >= 0) {
+		len = err;
+		mb32.mtype = mb->mtype;
+		err = put_user(mb32.mtype, &umsgp32->mtype);
+		err |= copy_to_user(&umsgp32->mtext, mb->mtext, len);
+		if (err)
+			err = -EFAULT;
+		else
+			err = len;
+	}
+
+	kfree(mb);
+	return err;
+}
+
+/* LFS */
+
+extern asmlinkage long sys_truncate(const char *, loff_t);
+extern asmlinkage long sys_ftruncate(unsigned int, loff_t);
+extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long);
+extern asmlinkage ssize_t sys_pread(unsigned int, char *, size_t, loff_t);
+extern asmlinkage ssize_t sys_pwrite(unsigned int, char *, size_t, loff_t);
+
+asmlinkage long sys32_truncate64(const char * path, unsigned int high, unsigned int low)
+{
+	return sys_truncate(path, (loff_t)high << 32 | low);
+}
+
+asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned int high, unsigned int low)
+{
+	return sys_ftruncate(fd, (loff_t)high << 32 | low);
+}
+
+asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+		case F_GETLK64:
+			cmd = F_GETLK;
+			break;
+		case F_SETLK64:
+			cmd = F_SETLK;
+			break;
+		case F_SETLKW64:
+			cmd = F_SETLKW;
+			break;
+		default:
+			break;
+	}
+	return sys_fcntl(fd, cmd, arg);
+}
+
+asmlinkage int sys32_pread(int fd, void *buf, size_t count, unsigned int high, unsigned int low)
+{
+	return sys_pread(fd, buf, count, (loff_t)high << 32 | low);
+}
+
+asmlinkage int sys32_pwrite(int fd, void *buf, size_t count, unsigned int high, unsigned int low)
+{
+       return sys_pwrite(fd, buf, count, (loff_t)high << 32 | low);
+}
+
+/* EXPORT/UNEXPORT */
+struct nfsctl_export32 {
+	char			ex_client[NFSCLNT_IDMAX+1];
+	char			ex_path[NFS_MAXPATHLEN+1];
+	__kernel_dev_t		ex_dev;
+	__kernel_ino_t32	ex_ino;
+	int			ex_flags;
+	__kernel_uid_t		ex_anon_uid;
+	__kernel_gid_t		ex_anon_gid;
+};
+
+/* GETFH */
+struct nfsctl_fhparm32 {
+	struct sockaddr		gf_addr;
+	__kernel_dev_t		gf_dev;
+	__kernel_ino_t32	gf_ino;
+	int			gf_version;
+};
+
+/* UGIDUPDATE */
+struct nfsctl_uidmap32 {
+	__kernel_caddr_t32	ug_ident;
+	__kernel_uid_t		ug_uidbase;
+	int			ug_uidlen;
+	__kernel_caddr_t32	ug_udimap;
+	__kernel_gid_t		ug_gidbase;
+	int			ug_gidlen;
+	__kernel_caddr_t32	ug_gdimap;
+};
+
+struct nfsctl_arg32 {
+	int			ca_version;	/* safeguard */
+	/* wide kernel places this union on 8-byte boundary, narrow on 4 */
+	union {
+		struct nfsctl_svc	u_svc;
+		struct nfsctl_client	u_client;
+		struct nfsctl_export32	u_export;
+		struct nfsctl_uidmap32	u_umap;
+		struct nfsctl_fhparm32	u_getfh;
+		struct nfsctl_fdparm	u_getfd;
+		struct nfsctl_fsparm	u_getfs;
+	} u;
+};
+
+asmlinkage int sys32_nfsservctl(int cmd, void *argp, void *resp)
+{
+	int ret, tmp;
+	struct nfsctl_arg32 n32;
+	struct nfsctl_arg n;
+
+	ret = copy_from_user(&n, argp, sizeof n.ca_version);
+	if (ret != 0)
+		return ret;
+
+	/* adjust argp to point at the union inside the user's n32 struct */
+	tmp = (unsigned long)&n32.u - (unsigned long)&n32;
+	argp = (void *)((unsigned long)argp + tmp);
+	switch(cmd) {
+	case NFSCTL_SVC:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_svc);
+		break;
+
+	case NFSCTL_ADDCLIENT:
+	case NFSCTL_DELCLIENT:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_client);
+		break;
+
+	case NFSCTL_GETFD:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_getfd);
+		break;
+
+	case NFSCTL_GETFS:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_getfs);
+		break;
+
+	case NFSCTL_GETFH:		/* nfsctl_fhparm */
+		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_getfh);
+#undef CP
+#define CP(x)	n.u.u_getfh.gf_##x = n32.u.u_getfh.gf_##x
+		CP(addr);
+		CP(dev);
+		CP(ino);
+		CP(version);
+		break;
+
+	case NFSCTL_UGIDUPDATE:		/* nfsctl_uidmap */
+		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_umap);
+#undef CP
+#define CP(x)	n.u.u_umap.ug_##x = n32.u.u_umap.ug_##x
+		n.u.u_umap.ug_ident = (char *)(u_long)n32.u.u_umap.ug_ident;
+		CP(uidbase);
+		CP(uidlen);
+		n.u.u_umap.ug_udimap = (__kernel_uid_t *)(u_long)n32.u.u_umap.ug_udimap;
+		CP(gidbase);
+		CP(gidlen);
+		n.u.u_umap.ug_gdimap = (__kernel_gid_t *)(u_long)n32.u.u_umap.ug_gdimap;
+		break;
+
+	case NFSCTL_UNEXPORT:		/* nfsctl_export */
+	case NFSCTL_EXPORT:		/* nfsctl_export */
+		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_export);
+#undef CP
+#define CP(x)	n.u.u_export.ex_##x = n32.u.u_export.ex_##x
+		memcpy(n.u.u_export.ex_client, n32.u.u_export.ex_client, sizeof n32.u.u_export.ex_client);
+		memcpy(n.u.u_export.ex_path, n32.u.u_export.ex_path, sizeof n32.u.u_export.ex_path);
+		CP(dev);
+		CP(ino);
+		CP(flags);
+		CP(anon_uid);
+		CP(anon_gid);
+		break;
+
+	default:
+		BUG(); /* new cmd values to be translated... */
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret == 0) {
+		unsigned char rbuf[NFS_FHSIZE + sizeof (struct knfsd_fh)];
+		KERNEL_SYSCALL(ret, sys_nfsservctl, cmd, &n, &rbuf);
+		if (cmd == NFSCTL_GETFH || cmd == NFSCTL_GETFD) {
+			ret = copy_to_user(resp, rbuf, NFS_FHSIZE);
+		} else if (cmd == NFSCTL_GETFS) {
+			ret = copy_to_user(resp, rbuf, sizeof (struct knfsd_fh));
+		}
+	}
+
+	return ret;
+}
+
+#include <linux/quota.h>
+
+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;
+};
+                                
+
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
+{
+	extern int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+	int cmds = cmd >> SUBCMDSHIFT;
+	int err;
+	struct dqblk d;
+	char *spec;
+	
+	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 = getname (special);
+	err = PTR_ERR(spec);
+	if (IS_ERR(spec)) return err;
+	KERNEL_SYSCALL(err, sys_quotactl, cmd, (const char *)spec, id, (caddr_t)&d);
+	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;
+	}
+	return err;
+}
+
+struct timex32 {
+	unsigned int modes;	/* mode selector */
+	int offset;		/* time offset (usec) */
+	int freq;		/* frequency offset (scaled ppm) */
+	int maxerror;		/* maximum error (usec) */
+	int esterror;		/* estimated error (usec) */
+	int status;		/* clock command/status */
+	int constant;		/* pll time constant */
+	int precision;		/* clock precision (usec) (read only) */
+	int tolerance;		/* clock frequency tolerance (ppm)
+				 * (read only)
+				 */
+	struct timeval32 time;	/* (read only) */
+	int tick;		/* (modified) usecs between clock ticks */
+
+	int ppsfreq;           /* pps frequency (scaled ppm) (ro) */
+	int jitter;            /* pps jitter (us) (ro) */
+	int shift;              /* interval duration (s) (shift) (ro) */
+	int stabil;            /* pps stability (scaled ppm) (ro) */
+	int jitcnt;            /* jitter limit exceeded (ro) */
+	int calcnt;            /* calibration intervals (ro) */
+	int errcnt;            /* calibration errors (ro) */
+	int stbcnt;            /* stability limit exceeded (ro) */
+
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+};
+
+asmlinkage long sys32_adjtimex(struct timex32 *txc_p32)
+{
+	struct timex txc;
+	struct timex32 t32;
+	int ret;
+	extern int do_adjtimex(struct timex *txc);
+
+	if(copy_from_user(&t32, txc_p32, sizeof(struct timex32)))
+		return -EFAULT;
+#undef CP
+#define CP(x) txc.x = t32.x
+	CP(modes); CP(offset); CP(freq); CP(maxerror); CP(esterror);
+	CP(status); CP(constant); CP(precision); CP(tolerance);
+	CP(time.tv_sec); CP(time.tv_usec); CP(tick); CP(ppsfreq); CP(jitter);
+	CP(shift); CP(stabil); CP(jitcnt); CP(calcnt); CP(errcnt);
+	CP(stbcnt);
+	ret = do_adjtimex(&txc);
+#define CP(x) t32.x = txc.x
+	CP(modes); CP(offset); CP(freq); CP(maxerror); CP(esterror);
+	CP(status); CP(constant); CP(precision); CP(tolerance);
+	CP(time.tv_sec); CP(time.tv_usec); CP(tick); CP(ppsfreq); CP(jitter);
+	CP(shift); CP(stabil); CP(jitcnt); CP(calcnt); CP(errcnt);
+	CP(stbcnt);
+	return copy_to_user(txc_p32, &t32, sizeof(struct timex32)) ? -EFAULT : ret;
+}
+
+
+struct sysinfo32 {
+	s32 uptime;
+	u32 loads[3];
+	u32 totalram;
+	u32 freeram;
+	u32 sharedram;
+	u32 bufferram;
+	u32 totalswap;
+	u32 freeswap;
+	unsigned short procs;
+	u32 totalhigh;
+	u32 freehigh;
+	u32 mem_unit;
+	char _f[12];
+};
+
+/* We used to call sys_sysinfo and translate the result.  But sys_sysinfo
+ * undoes the good work done elsewhere, and rather than undoing the
+ * damage, I decided to just duplicate the code from sys_sysinfo here.
+ */
+
+asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
+{
+	struct sysinfo val;
+	int err;
+
+	/* We don't need a memset here because we copy the
+	 * struct to userspace once element at a time.
+	 */
+
+	cli();
+	val.uptime = jiffies / HZ;
+
+	val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
+	val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
+	val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
+
+	val.procs = nr_threads-1;
+	sti();
+
+	si_meminfo(&val);
+	si_swapinfo(&val);
+	
+	err = put_user (val.uptime, &info->uptime);
+	err |= __put_user (val.loads[0], &info->loads[0]);
+	err |= __put_user (val.loads[1], &info->loads[1]);
+	err |= __put_user (val.loads[2], &info->loads[2]);
+	err |= __put_user (val.totalram, &info->totalram);
+	err |= __put_user (val.freeram, &info->freeram);
+	err |= __put_user (val.sharedram, &info->sharedram);
+	err |= __put_user (val.bufferram, &info->bufferram);
+	err |= __put_user (val.totalswap, &info->totalswap);
+	err |= __put_user (val.freeswap, &info->freeswap);
+	err |= __put_user (val.procs, &info->procs);
+	err |= __put_user (val.totalhigh, &info->totalhigh);
+	err |= __put_user (val.freehigh, &info->freehigh);
+	err |= __put_user (val.mem_unit, &info->mem_unit);
+	return err ? -EFAULT : 0;
+}
+
+
+/* lseek() needs a wrapper because 'offset' can be negative, but the top
+ * half of the argument has been zeroed by syscall.S.
+ */
+
+extern asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
+
+asmlinkage int sys32_lseek(unsigned int fd, int offset, unsigned int origin)
+{
+	return sys_lseek(fd, offset, origin);
+}
+
+asmlinkage long sys32_semctl_broken(int semid, int semnum, int cmd, union semun arg)
+{
+        union semun u;
+	
+	cmd &= ~IPC_64; /* should be removed together with the _broken suffix */
+
+        if (cmd == SETVAL) {
+                /* Ugh.  arg is a union of int,ptr,ptr,ptr, so is 8 bytes.
+                 * The int should be in the first 4, but our argument
+                 * frobbing has left it in the last 4.
+                 */
+                u.val = *((int *)&arg + 1);
+                return sys_semctl (semid, semnum, cmd, u);
+	}
+	return sys_semctl (semid, semnum, cmd, arg);
+}
+
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/syscall.S linux-2.4.20-pre2/arch/parisc/kernel/syscall.S
--- linux-2.4.20-pre1/arch/parisc/kernel/syscall.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/parisc/kernel/syscall.S	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /* 
- * Linux/PARISC Project (http://www.thepuffingroup.com/parisc)
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
  * 
  * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>
  * Licensed under the GNU GPL.
@@ -12,7 +12,6 @@
 #include <asm/errno.h>
 #include <asm/psw.h>
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/processor.h>
 #include <linux/version.h>
@@ -23,7 +22,13 @@
 	.level		1.1
 #endif
 	.text
-	
+
+#ifdef __LP64__
+#define FRAME_SIZE	128
+#else
+#define FRAME_SIZE	64
+#endif
+
 	.import syscall_exit,code
 	.import syscall_exit_rfi,code
 	.export linux_gateway_page
@@ -39,17 +44,30 @@
 	.align 4096
 linux_gateway_page:
 
+	.rept 56
 	break   0,0
+	.endr
 
+set_thread_pointer:
+	gate	.+8, %r0		/* increase privilege */
+	depi	3, 31, 2, %r31		/* Ensure we return into user mode. */
+	be	0(%sr7,%r31)		/* return to user space */
+	mtctl	%r26, %cr27		/* move arg0 to the control register */
+
+	.rept 4
+	break   0,0
+	.endr
+
+/* This address must remain fixed, or user binaries go splat. */
 	.align 256
 linux_gateway_entry:
-	mfsp	%sr7,%r1			/* we must set sr3 to the space */
-	mtsp	%r1,%sr3			/* of the user before the gate */
 	gate	.+8, %r0			/* become privileged */
 	mtsp	%r0,%sr4			/* get kernel space into sr4 */
 	mtsp	%r0,%sr5			/* get kernel space into sr5 */
 	mtsp	%r0,%sr6			/* get kernel space into sr6 */
-	mtsp	%r0,%sr7			/* get kernel space into sr7 */
+	mfsp    %sr7,%r1                        /* save user sr7 */
+	mtsp    %r1,%sr3                        /* and store it in sr3 */
+
 #ifdef __LP64__
 	/* for now we can *always* set the W bit on entry to the syscall
 	 * since we don't support wide userland processes.  We could
@@ -58,15 +76,38 @@
 	 * whether to do narrow or wide syscalls. -PB
 	 */
 	ssm	PSW_SM_W, %r0
+	/* The top halves of argument registers must be cleared on syscall
+	 * entry.
+	 */
+	depdi	0, 31, 32, %r26
+	depdi	0, 31, 32, %r25
+	depdi	0, 31, 32, %r24
+	depdi	0, 31, 32, %r23
+	depdi	0, 31, 32, %r22
+	depdi	0, 31, 32, %r21
 #endif
-	mtctl	%r28,%cr27
-	rsm	PSW_I, %r28			/* no ints for a bit  */
-	mfctl	%cr30,%r1			/* get the kernel task ptr */
-	mtctl	%r0,%cr30			/* zero it (flag) */
+	mfctl   %cr30,%r1
+	xor     %r1,%r30,%r30                   /* ye olde xor trick */
+	xor     %r1,%r30,%r1
+	xor     %r1,%r30,%r30
+	ldo     TASK_SZ_ALGN+FRAME_SIZE(%r30),%r30  /* set up kernel stack */
+
+	/* N.B.: It is critical that we don't set sr7 to 0 until r30
+	 *       contains a valid kernel stack pointer. It is also
+	 *       critical that we don't start using the kernel stack
+	 *       until after sr7 has been set to 0.
+	 */
+
+	mtsp	%r0,%sr7			/* get kernel space into sr7 */
+	STREG   %r1,TASK_PT_GR30-TASK_SZ_ALGN-FRAME_SIZE(%r30) /* save usp */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1   /* get task ptr in %r1 */
 
 	/* Save some registers for sigcontext and potential task
 	   switch (see entry.S for the details of which ones are
-	   saved/restored) */
+	   saved/restored).  TASK_PT_PSW is zeroed so we can see whether
+	   a process is on a syscall or not.  For an interrupt the real
+	   PSW value is stored.  This is needed for gdb and sys_ptrace. */
+	STREG	%r0,  TASK_PT_PSW(%r1)
 	STREG	%r2,  TASK_PT_GR2(%r1)		/* preserve rp */
 	STREG	%r19, TASK_PT_GR19(%r1)
 	STREG	%r20, TASK_PT_GR20(%r1)
@@ -77,11 +118,9 @@
 	STREG	%r25, TASK_PT_GR25(%r1)		/* 2nd argument */
 	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */
 	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */
-	mfctl	%cr27,%r19
-	STREG	%r19, TASK_PT_GR28(%r1)		/* return value 0 */
-	STREG	%r19, TASK_PT_ORIG_R28(%r1)	/* return value 0 (saved for signals) */
+	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
+	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
 	STREG	%r29, TASK_PT_GR29(%r1)		/* return value 1 */
-	STREG	%r30, TASK_PT_GR30(%r1)		/* preserve userspace sp */
 	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */
 	
 	ldo	TASK_PT_FR0(%r1), %r27		/* save fpregs from the kernel */
@@ -92,10 +131,10 @@
 
 	loadgp
 
-	ldo	TASK_SZ_ALGN+64(%r1),%r30	/* set up kernel stack */
-
-#ifndef __LP64__
-	/* no need to save these on stack because in wide mode the first 8
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#else
+	/* no need to save these on stack in wide mode because the first 8
 	 * args are passed in registers */
 	stw     %r22, -52(%r30)                 /* 5th argument */
 	stw     %r21, -56(%r30)                 /* 6th argument */
@@ -103,7 +142,6 @@
 
 	/* for some unknown reason, task_struct.ptrace is an unsigned long so use LDREG */
 	LDREG	TASK_PTRACE(%r1), %r19		/* Are we being ptraced? */
-	mtsm	%r28				/* irqs back  */
 
 	bb,<,n	%r19, 31, .Ltracesys		/* must match PT_PTRACE bit */
 	
@@ -112,7 +150,6 @@
 
 	ldil	L%sys_call_table, %r1
 	ldo     R%sys_call_table(%r1), %r19
-	LDIL_FIXUP(%r19)
 	
 	comiclr,>>=	__NR_Linux_syscalls, %r20, %r0
 	b,n	.Lsyscall_nosys
@@ -131,13 +168,11 @@
 	comb,=	%r2,%r20,.Lrt_sigreturn
 .Lin_syscall:
 	ldil	L%syscall_exit,%r2
-	LDIL_FIXUP(%r2)
 	be      0(%sr7,%r19)
 	ldo	R%syscall_exit(%r2),%r2
 .Lrt_sigreturn:
 	comib,<> 0,%r25,.Lin_syscall
 	ldil	L%syscall_exit_rfi,%r2
-	LDIL_FIXUP(%r2)
 	be      0(%sr7,%r19)
 	ldo	R%syscall_exit_rfi(%r2),%r2
 
@@ -149,7 +184,6 @@
 .Lsyscall_nosys:
 syscall_nosys:
 	ldil	L%syscall_exit,%r1
-	LDIL_FIXUP(%r1)
 	be	R%syscall_exit(%sr7,%r1)
 	ldo	-ENOSYS(%r0),%r28		   /* set errno */
 
@@ -159,12 +193,17 @@
 .Ltracesys:
 tracesys:
 	/* Need to save more registers so the debugger can see where we
-	 * are.
+	 * are.  This saves only the lower 8 bits of PSW, so that the C
+	 * bit is still clear on syscalls, and the D bit is set if this
+	 * full register save path has been executed.  We check the D
+	 * bit on syscall_return_rfi to determine which registers to
+	 * restore.  An interrupt results in a full PSW saved with the
+	 * C bit set, a non-straced syscall entry results in C and D clear
+	 * in the saved PSW.
 	 */
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
-	ssm	0,%r2				/* Lower 8 bits only!! */
-	STREG	%r2,TASK_PT_PSW(%r1)
-	STREG	%r1,TASK_PT_CR30(%r1)
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+	ssm	0,%r2
+	STREG	%r2,TASK_PT_PSW(%r1)		/* Lower 8 bits only!! */
 	mfsp	%sr0,%r2
 	STREG	%r2,TASK_PT_SR0(%r1)
 	mfsp	%sr1,%r2
@@ -204,18 +243,15 @@
 	/* Finished saving things for the debugger */
 
 	ldil	L%syscall_trace,%r1
-	LDIL_FIXUP(%r1)
 	ldil	L%tracesys_next,%r2
-	LDIL_FIXUP(%r2)
 	be	R%syscall_trace(%sr7,%r1)
 	ldo	R%tracesys_next(%r2),%r2
 	
 tracesys_next:	
 	ldil	L%sys_call_table,%r1
-	LDIL_FIXUP(%r1)
 	ldo     R%sys_call_table(%r1), %r19
 
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
 	LDREG   TASK_PT_GR20(%r1), %r20
 	LDREG   TASK_PT_GR26(%r1), %r26		/* Restore the users args */
 	LDREG   TASK_PT_GR25(%r1), %r25
@@ -224,6 +260,7 @@
 #ifdef __LP64__
 	LDREG   TASK_PT_GR22(%r1), %r22
 	LDREG   TASK_PT_GR21(%r1), %r21
+	ldo	-16(%r30),%r29			/* Reference param save area */
 #endif
 
 	comiclr,>>=	__NR_Linux_syscalls, %r20, %r0
@@ -243,7 +280,6 @@
 	comb,=	%r2,%r20,.Ltrace_rt_sigreturn
 .Ltrace_in_syscall:
 	ldil	L%tracesys_exit,%r2
-	LDIL_FIXUP(%r2)
 	be      0(%sr7,%r19)
 	ldo	R%tracesys_exit(%r2),%r2
 
@@ -251,30 +287,33 @@
 	makes a direct call to syscall_trace. */
 	
 tracesys_exit:
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#endif
 	bl	syscall_trace, %r2
 	STREG   %r28,TASK_PT_GR28(%r1)          /* save return value now */
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
 	LDREG   TASK_PT_GR28(%r1), %r28		/* Restore return val. */
 
 	ldil	L%syscall_exit,%r1
-	LDIL_FIXUP(%r1)
 	be,n	R%syscall_exit(%sr7,%r1)
 
 .Ltrace_rt_sigreturn:
 	comib,<> 0,%r25,.Ltrace_in_syscall
 	ldil	L%tracesys_sigexit,%r2
-	LDIL_FIXUP(%r2)
 	be      0(%sr7,%r19)
 	ldo	R%tracesys_sigexit(%r2),%r2
 
 tracesys_sigexit:
-	ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+#ifdef __LP64__
+	ldo	-16(%r30),%r29			/* Reference param save area */
+#endif
 	bl	syscall_trace, %r2
 	nop
 
 	ldil	L%syscall_exit_rfi,%r1
-	LDIL_FIXUP(%r1)
 	be,n	R%syscall_exit_rfi(%sr7,%r1)
 
 #ifdef __LP64__
@@ -282,13 +321,13 @@
  * narrow palinux.  Use ENTRY_DIFF for those where a 32-bit specific
  * implementation is required on wide palinux.
  */
-#define ENTRY_SAME(_name_) .dword sys_##_name_
-#define ENTRY_DIFF(_name_) .dword sys32_##_name_
-#define ENTRY_UHOH(_name_) .dword sys32_unimplemented
+#define ENTRY_SAME(_name_) .dword sys_/**/_name_
+#define ENTRY_DIFF(_name_) .dword sys32_/**/_name_
+#define ENTRY_UHOH(_name_) .dword sys32_/**/unimplemented
 #else
-#define ENTRY_SAME(_name_) .word sys_##_name_
-#define ENTRY_DIFF(_name_) .word sys_##_name_
-#define ENTRY_UHOH(_name_) .word sys_##_name_
+#define ENTRY_SAME(_name_) .word sys_/**/_name_
+#define ENTRY_DIFF(_name_) .word sys_/**/_name_
+#define ENTRY_UHOH(_name_) .word sys_/**/_name_
 #endif
 
 	.align 8
@@ -316,7 +355,7 @@
 	ENTRY_SAME(socket)
 	/* struct stat is MAYBE identical wide and narrow ?? */
 	ENTRY_DIFF(newstat)
-	ENTRY_SAME(lseek)
+	ENTRY_DIFF(lseek)
 	ENTRY_SAME(getpid)		/* 20 */
 	/* the 'void * data' parameter may need re-packing in wide */
 	ENTRY_DIFF(mount)
@@ -391,8 +430,8 @@
 	ENTRY_DIFF(getrlimit)
 	ENTRY_DIFF(getrusage)
 	/* struct timeval and timezone are maybe?? consistent wide and narrow */
-	ENTRY_SAME(gettimeofday)
-	ENTRY_SAME(settimeofday)
+	ENTRY_DIFF(gettimeofday)
+	ENTRY_DIFF(settimeofday)
 	ENTRY_SAME(getgroups)	/* 80 */
 	ENTRY_SAME(setgroups)
 	/* struct socketaddr... */
@@ -402,12 +441,12 @@
 	ENTRY_DIFF(newlstat)
 	ENTRY_SAME(readlink)	/* 85 */
 	/* suspect we'll need some work for narrow shlibs on wide kernel */
+	/* NOTE this doesn't get used when I boot 32-bit userspace */
+	/* containing working shlib apps -- can this be nuked? */
 	ENTRY_UHOH(uselib)
 	ENTRY_SAME(swapon)
 	ENTRY_SAME(reboot)
-	/* argh! struct dirent contains a long */
-	ENTRY_UHOH(old_readdir)
-	/* I'm not certain about off_t... */
+	ENTRY_SAME(mmap2)
 	ENTRY_SAME(mmap)		/* 90 */
 	ENTRY_SAME(munmap)
 	ENTRY_SAME(truncate)
@@ -419,28 +458,27 @@
 	ENTRY_SAME(recv)
 	ENTRY_DIFF(statfs)
 	ENTRY_DIFF(fstatfs)		/* 100 */
-	ENTRY_SAME(ni_syscall)
+	ENTRY_SAME(stat64)
 	/* don't think hppa glibc even provides an entry pt for this
 	 * so disable for now */
 	ENTRY_UHOH(socketcall)
 	ENTRY_SAME(syslog)
 	/* even though manpage says struct timeval contains longs, ours has
 	 * time_t and suseconds_t -- both of which are safe wide/narrow */
-	ENTRY_SAME(setitimer)
-	ENTRY_SAME(getitimer)	/* 105 */
+	ENTRY_DIFF(setitimer)
+	ENTRY_DIFF(getitimer)	/* 105 */
 	ENTRY_SAME(capget)
 	ENTRY_SAME(capset)
-	ENTRY_SAME(pread)
-	ENTRY_SAME(pwrite)
+	ENTRY_DIFF(pread)
+	ENTRY_DIFF(pwrite)
 	ENTRY_SAME(getcwd)		/* 110 */
 	ENTRY_SAME(vhangup)
-	ENTRY_SAME(ni_syscall)
+	ENTRY_SAME(fstat64)
 	ENTRY_SAME(vfork_wrapper)
 	/* struct rusage contains longs... */
 	ENTRY_DIFF(wait4)
 	ENTRY_SAME(swapoff)		/* 115 */
-	/* struct sysinfo contains longs */
-	ENTRY_SAME(sysinfo)
+	ENTRY_DIFF(sysinfo)
 	ENTRY_SAME(shutdown)
 	ENTRY_SAME(fsync)
 	ENTRY_SAME(madvise)
@@ -450,7 +488,7 @@
 	/* struct sockaddr... */
 	ENTRY_SAME(recvfrom)
 	/* struct timex contains longs */
-	ENTRY_UHOH(adjtimex)
+	ENTRY_DIFF(adjtimex)
 	ENTRY_SAME(mprotect)	/* 125 */
 	/* old_sigset_t forced to 32 bits.  Beware glibc sigset_t */
 	ENTRY_DIFF(sigprocmask)
@@ -461,12 +499,11 @@
 	ENTRY_SAME(delete_module)
 	/* struct kernel_sym contains a long. Linus never heard of size_t? */
 	ENTRY_DIFF(get_kernel_syms)	/* 130 */
-	ENTRY_SAME(quotactl)
+	/* time_t inside struct dqblk */
+	ENTRY_DIFF(quotactl)
 	ENTRY_SAME(getpgid)
 	ENTRY_SAME(fchdir)
-	/* bdflush(func, addr) where func has least-significant-bit set means
-	 * addr is a pointer to long :-( */
-	ENTRY_UHOH(bdflush)
+	ENTRY_SAME(bdflush)
 	ENTRY_SAME(sysfs)		/* 135 */
 	ENTRY_SAME(personality)
 	ENTRY_SAME(ni_syscall)	/* for afs_syscall */
@@ -479,12 +516,12 @@
 	ENTRY_DIFF(getdents)
 	/* it is POSSIBLE that select will be OK because even though fd_set
 	 * contains longs, the macros and sizes are clever. */
-	ENTRY_SAME(select)
+	ENTRY_DIFF(select)
 	ENTRY_SAME(flock)
 	ENTRY_SAME(msync)
 	/* struct iovec contains pointers */
-	ENTRY_UHOH(readv)		/* 145 */
-	ENTRY_UHOH(writev)
+	ENTRY_DIFF(readv)		/* 145 */
+	ENTRY_DIFF(writev)
 	ENTRY_SAME(getsid)
 	ENTRY_SAME(fdatasync)
 	/* struct __sysctl_args is a mess */
@@ -509,13 +546,12 @@
 	ENTRY_SAME(mremap)
 	ENTRY_SAME(setresuid)
 	ENTRY_SAME(getresuid)	/* 165 */
-	/* might work, but in general signals need a thorough review */
-	ENTRY_UHOH(sigaltstack_wrapper)
+	ENTRY_DIFF(sigaltstack_wrapper)
 	/* struct passed back to user can contain long symbol values */
 	ENTRY_DIFF(query_module)
 	ENTRY_SAME(poll)
 	/* structs contain pointers and an in_addr... */
-	ENTRY_UHOH(nfsservctl)
+	ENTRY_DIFF(nfsservctl)
 	ENTRY_SAME(setresgid)	/* 170 */
 	ENTRY_SAME(getresgid)
 	ENTRY_SAME(prctl)
@@ -525,35 +561,43 @@
 	ENTRY_DIFF(rt_sigprocmask)	/* 175 */
 	ENTRY_DIFF(rt_sigpending)
 	ENTRY_UHOH(rt_sigtimedwait)
-	ENTRY_UHOH(rt_sigqueueinfo)
+	/* even though the struct siginfo_t is different, it appears like
+	 * all the paths use values which should be same wide and narrow.
+	 * Also the struct is padded to 128 bytes which means we don't have
+	 * to worry about faulting trying to copy in a larger 64-bit
+	 * struct from a 32-bit user-space app.
+	 */
+	ENTRY_SAME(rt_sigqueueinfo)
 	ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
 	ENTRY_SAME(chown)		/* 180 */
-	/* *sockopt() might work... */
-	ENTRY_SAME(setsockopt)
+	/* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
+	ENTRY_DIFF(setsockopt)
 	ENTRY_SAME(getsockopt)
-	/* struct msghdr contains pointers... */
-	ENTRY_UHOH(sendmsg)
-	ENTRY_UHOH(recvmsg)
+	ENTRY_DIFF(sendmsg)
+	ENTRY_DIFF(recvmsg)
 	ENTRY_SAME(semop)		/* 185 */
 	ENTRY_SAME(semget)
-	/* needs a more careful review */
-	ENTRY_UHOH(semctl)
-	/* struct msgbuf contains a long */
-	ENTRY_UHOH(msgsnd)
-	ENTRY_UHOH(msgrcv)
+	ENTRY_DIFF(semctl_broken)
+	ENTRY_DIFF(msgsnd)
+	ENTRY_DIFF(msgrcv)
 	ENTRY_SAME(msgget)		/* 190 */
-	/* struct msqid_ds contains pointers */
-	ENTRY_UHOH(msgctl)
+	ENTRY_SAME(msgctl_broken)
 	ENTRY_SAME(shmat_wrapper)
 	ENTRY_SAME(shmdt)
 	ENTRY_SAME(shmget)
-	/***************/
-	/* struct shmid_ds contains pointers */
-	ENTRY_UHOH(shmctl)		/* 195 */
+	ENTRY_SAME(shmctl_broken)		/* 195 */
 	ENTRY_SAME(ni_syscall)		/* streams1 */
 	ENTRY_SAME(ni_syscall)		/* streams2 */
+	ENTRY_SAME(lstat64)
+	ENTRY_DIFF(truncate64)
+	ENTRY_DIFF(ftruncate64)	/* 200 */
+	ENTRY_SAME(getdents64)
+	ENTRY_DIFF(fcntl64)
+	ENTRY_SAME(ni_syscall)		/* attrctl */
+	ENTRY_SAME(ni_syscall)		/* acl_get */
+	ENTRY_SAME(ni_syscall)		/* acl_set */
 	ENTRY_SAME(gettid)
-	ENTRY_SAME(tkill)
+	ENTRY_SAME(readahead)          
 
 .end
 
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/time.c linux-2.4.20-pre2/arch/parisc/kernel/time.c
--- linux-2.4.20-pre1/arch/parisc/kernel/time.c	Wed Dec  6 11:46:39 2000
+++ linux-2.4.20-pre2/arch/parisc/kernel/time.c	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/kernel/time.c
+ *  linux/arch/parisc/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
  *  Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King
@@ -10,6 +10,7 @@
  * 1998-12-20  Updated NTP code according to technical memorandum Jan '96
  *             "A Kernel Model for Precision Timekeeping" by Dave Mills
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -30,69 +31,208 @@
 
 #include <linux/timex.h>
 
+/* xtime and wall_jiffies keep wall-clock time */
+extern unsigned long wall_jiffies;
 extern rwlock_t xtime_lock;
 
-static int timer_value;
-static int timer_delta;
-static struct pdc_tod tod_data __attribute__((aligned(8)));
+static long clocktick;	/* timer cycles per tick */
+static long halftick;
 
-void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#ifdef CONFIG_SMP
+extern void smp_do_timer(struct pt_regs *regs);
+#endif
+
+static inline void
+parisc_do_profile(unsigned long pc)
 {
-	int old;
-	int lost = 0;
-	int cr16;
-	
-	old = timer_value;
+	extern char _stext;
 
-	cr16 = mfctl(16);
-	while((timer_value - cr16) < (timer_delta / 2)) {
-		timer_value += timer_delta;
-		lost++;
-	}
+	if (!prof_buffer)
+		return;
 
-	mtctl(timer_value ,16);
+	pc -= (unsigned long) &_stext;
+	pc >>= prof_shift;
+	/*
+	 * Don't ignore out-of-bounds PC values silently,
+	 * put them into the last histogram slot, so if
+	 * present, they will show up as a sharp peak.
+	 */
+	if (pc > prof_len - 1)
+		pc = prof_len - 1;
+	atomic_inc((atomic_t *)&prof_buffer[pc]);
+}
+
+void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	long now = mfctl(16);
+	long next_tick;
+	int nticks;
+	int cpu = smp_processor_id();
+
+	/* initialize next_tick to time at last clocktick */
+
+	next_tick = cpu_data[cpu].it_value;
+
+	/* since time passes between the interrupt and the mfctl()
+	 * above, it is never true that last_tick + clocktick == now.  If we
+	 * never miss a clocktick, we could set next_tick = last_tick + clocktick
+	 * but maybe we'll miss ticks, hence the loop.
+	 *
+	 * Variables are *signed*.
+	 */
+
+	nticks = 0;
+	while((next_tick - now) < halftick) {
+		next_tick += clocktick;
+		nticks++;
+	}
+	mtctl(next_tick, 16);
+	cpu_data[cpu].it_value = next_tick;
 
-	do_timer(regs);
+	while (nticks--) {
+#ifdef CONFIG_SMP
+		smp_do_timer(regs);
+#endif
+		if (cpu == 0) {
+			extern int pc_in_user_space;
+			write_lock(&xtime_lock);
+#ifndef CONFIG_SMP
+			if (!user_mode(regs))
+				parisc_do_profile(regs->iaoq[0]);
+			else
+				parisc_do_profile(&pc_in_user_space);
+#endif
+			do_timer(regs);
+			write_unlock(&xtime_lock);
+		}
+	}
     
-	led_interrupt_func();
+#ifdef CONFIG_CHASSIS_LCD_LED
+	/* Only schedule the led tasklet on cpu 0, and only if it
+	 * is enabled.
+	 */
+	if (cpu == 0 && !atomic_read(&led_tasklet.count))
+		tasklet_schedule(&led_tasklet);
+#endif
+
+	/* check soft power switch status */
+	if (cpu == 0 && !atomic_read(&power_tasklet.count))
+		tasklet_schedule(&power_tasklet);
 }
 
-void do_gettimeofday(struct timeval *tv)
+/*** converted from ia64 ***/
+/*
+ * Return the number of micro-seconds that elapsed since the last
+ * update to wall time (aka xtime aka wall_jiffies).  The xtime_lock
+ * must be at least read-locked when calling this routine.
+ */
+static inline unsigned long
+gettimeoffset (void)
 {
-	unsigned long flags;
-	
+#ifndef CONFIG_SMP
+	/*
+	 * FIXME: This won't work on smp because jiffies are updated by cpu 0.
+	 *    Once parisc-linux learns the cr16 difference between processors,
+	 *    this could be made to work.
+	 */
+	long last_tick;
+	long elapsed_cycles;
+
+	/* it_value is the intended time of the next tick */
+	last_tick = cpu_data[smp_processor_id()].it_value;
+
+	/* Subtract one tick and account for possible difference between
+	 * when we expected the tick and when it actually arrived.
+	 * (aka wall vs real)
+	 */
+	last_tick -= clocktick * (jiffies - wall_jiffies + 1);
+	elapsed_cycles = mfctl(16) - last_tick;
+
+	/* the precision of this math could be improved */
+	return elapsed_cycles / (PAGE0->mem_10msec / 10000);
+#else
+	return 0;
+#endif
+}
+
+void
+do_gettimeofday (struct timeval *tv)
+{
+	unsigned long flags, usec, sec;
+
 	read_lock_irqsave(&xtime_lock, flags);
-	tv->tv_sec = xtime.tv_sec;
-	tv->tv_usec = xtime.tv_usec;
+	{
+		usec = gettimeoffset();
+	
+		sec = xtime.tv_sec;
+		usec += xtime.tv_usec;
+	}
 	read_unlock_irqrestore(&xtime_lock, flags);
 
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		++sec;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
-void do_settimeofday(struct timeval *tv)
+void
+do_settimeofday (struct timeval *tv)
 {
 	write_lock_irq(&xtime_lock);
-	xtime.tv_sec = tv->tv_sec;
-	xtime.tv_usec = tv->tv_usec;
+	{
+		/*
+		 * This is revolting. We need to set "xtime"
+		 * correctly. However, the value in this location is
+		 * the value at the most recent update of wall time.
+		 * Discover what correction gettimeofday would have
+		 * done, and then undo it!
+		 */
+		tv->tv_usec -= gettimeoffset();
+		tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+
+		while (tv->tv_usec < 0) {
+			tv->tv_usec += 1000000;
+			tv->tv_sec--;
+		}
+
+		xtime = *tv;
+		time_adjust = 0;		/* stop active adjtime() */
+		time_status |= STA_UNSYNC;
+		time_maxerror = NTP_PHASE_LIMIT;
+		time_esterror = NTP_PHASE_LIMIT;
+	}
 	write_unlock_irq(&xtime_lock);
 }
 
+
 void __init time_init(void)
 {
-	timer_delta = (100 * PAGE0->mem_10msec) / HZ;
+	unsigned long next_tick;
+	static struct pdc_tod tod_data;
+
+	clocktick = (100 * PAGE0->mem_10msec) / HZ;
+	halftick = clocktick / 2;
 
-	/* make the first timer interrupt go off in one second */
-	timer_value = mfctl(16) + (HZ * timer_delta);
-	mtctl(timer_value, 16);
+	/* Setup clock interrupt timing */
 
+	next_tick = mfctl(16);
+	next_tick += clocktick;
+	cpu_data[smp_processor_id()].it_value = next_tick;
+
+	/* kick off Itimer (CR16) */
+	mtctl(next_tick, 16);
 
 	if(pdc_tod_read(&tod_data) == 0) {
+		write_lock_irq(&xtime_lock);
 		xtime.tv_sec = tod_data.tod_sec;
 		xtime.tv_usec = tod_data.tod_usec;
+		write_unlock_irq(&xtime_lock);
 	} else {
 		printk(KERN_ERR "Error reading tod clock\n");
 	        xtime.tv_sec = 0;
 		xtime.tv_usec = 0;
 	}
-
 }
-
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/traps.c linux-2.4.20-pre2/arch/parisc/kernel/traps.c
--- linux-2.4.20-pre1/arch/parisc/kernel/traps.c	Mon Feb 25 11:37:53 2002
+++ linux-2.4.20-pre2/arch/parisc/kernel/traps.c	Mon Aug 12 16:34:14 2002
@@ -23,15 +23,20 @@
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/console.h>
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/unaligned.h>
 #include <asm/atomic.h>
-
 #include <asm/smp.h>
 #include <asm/pdc.h>
 
+#include "../math-emu/math-emu.h"	/* for handle_fpe() */
+
 #ifdef CONFIG_KWDB
 #include <kdb/break.h>		/* for BI2_KGDB_GDB */
 #include <kdb/kgdb_types.h>	/* for __() */
@@ -40,150 +45,205 @@
 #include <kdb/trap.h>		/* for I_BRK_INST */
 #endif /* CONFIG_KWDB */
 
+#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
+			  /*  dumped to the console via printk)          */
 
-static inline void console_verbose(void)
-{
-	console_loglevel = 15;
-}
-
-
-void page_exception(void);
-
-/*
- * 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)
-
-int kstack_depth_to_print = 24;
-
-static void printbinary(unsigned long x, int nbits)
+static int printbinary(char *buf, unsigned long x, int nbits)
 {
 	unsigned long mask = 1UL << (nbits - 1);
 	while (mask != 0) {
-		printk(mask & x ? "1" : "0");
+		*buf++ = (mask & x ? '1' : '0');
 		mask >>= 1;
 	}
+	*buf = '\0';
+
+	return nbits;
 }
 
-void show_regs(struct pt_regs *regs)
-{
-	int i;
 #ifdef __LP64__
-#define RFMT " %016lx"
+#define RFMT "%016lx"
 #else
-#define RFMT " %08lx"
+#define RFMT "%08lx"
 #endif
 
-	printk("\n"); /* don't want to have that pretty register dump messed up */
-
-	printk("     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\nPSW: ");
-	printbinary(regs->gr[0], 32);
-	printk("    %s\n", print_tainted());
+void show_regs(struct pt_regs *regs)
+{
+	int i;
+	char buf[128], *p;
+	char *level;
+	unsigned long cr30;
+	unsigned long cr31;
+
+	level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
+
+	printk("%s\n", level); /* don't want to have that pretty register dump messed up */
+
+	printk("%s     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);
+	printbinary(buf, regs->gr[0], 32);
+	printk("%sPSW: %s %s\n", level, buf, print_tainted());
 
 	for (i = 0; i < 32; i += 4) {
 		int j;
-		printk("r%d-%d\t", i, i + 3);
+		p = buf;
+		p += sprintf(p, "%sr%02d-%02d ", level, i, i + 3);
 		for (j = 0; j < 4; j++) {
-			printk(RFMT, i + j == 0 ? 0 : regs->gr[i + j]);
+			p += sprintf(p, " " RFMT, (i+j) == 0 ? 0 : regs->gr[i + j]);
 		}
-		printk("\n");
+		printk("%s\n", buf);
 	}
 
 	for (i = 0; i < 8; i += 4) {
 		int j;
-		printk("sr%d-%d\t", i, i + 4);
+		p = buf;
+		p += sprintf(p, "%ssr%d-%d  ", level, i, i + 3);
 		for (j = 0; j < 4; j++) {
-			printk(RFMT, regs->sr[i + j]);
+			p += sprintf(p, " " RFMT, regs->sr[i + j]);
 		}
-		printk("\n");
+		printk("%s\n", buf);
 	}
 
-#if REDICULOUSLY_VERBOSE
-	for (i = 0; i < 32; i++) {
-		printk("FR%2d : %016lx  ", i, regs->fr[i]);
-		if ((i & 1) == 1)
-			printk("\n");
-	}
+#if RIDICULOUSLY_VERBOSE
+	for (i = 0; i < 32; i += 2)
+		printk("%sFR%02d : %016lx  FR%2d : %016lx", level, i,
+				regs->fr[i], i+1, regs->fr[i+1]);
 #endif
 
-	printk("\nIASQ:" RFMT RFMT " IAOQ:" RFMT RFMT "\n",
-	       regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);
-	printk(" IIR: %08lx    ISR:" RFMT "  IOR:" RFMT "\nORIG_R28:" RFMT
-	       "\n", regs->iir, regs->isr, regs->ior, regs->orig_r28);
+	cr30 = mfctl(30);
+	cr31 = mfctl(31);
+	printk("%s\n", level);
+	printk("%sIASQ: " RFMT " " RFMT " IAOQ: " RFMT " " RFMT "\n",
+	       level, regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);
+	printk("%s IIR: %08lx    ISR: " RFMT "  IOR: " RFMT "\n",
+	       level, regs->iir, regs->isr, regs->ior);
+	printk("%s CPU: %8d   CR30: " RFMT " CR31: " RFMT "\n",
+	       level, ((struct task_struct *)cr30)->processor, cr30, cr31);
+	printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);
 }
 
-void
-die_if_kernel (char *str, struct pt_regs *regs, long err)
+
+static void dump_stack(unsigned long from, unsigned long to, int istackflag)
+{
+	unsigned int *fromptr;
+	unsigned int *toptr;
+
+	fromptr = (unsigned int *)from;
+	toptr = (unsigned int *)to;
+
+	printk("\n");
+	printk(KERN_CRIT "Dumping %sStack from 0x%p to 0x%p:\n",
+			istackflag ? "Interrupt " : "",
+			fromptr, toptr);
+
+	while (fromptr < toptr) {
+		printk(KERN_CRIT "%04lx %08x %08x %08x %08x %08x %08x %08x %08x\n",
+		    ((unsigned long)fromptr) & 0xffff,
+		    fromptr[0], fromptr[1], fromptr[2], fromptr[3],
+		    fromptr[4], fromptr[5], fromptr[6], fromptr[7]);
+		fromptr += 8;
+	}
+}
+
+
+void show_stack(struct pt_regs *regs)
 {
-	if (user_mode(regs)) {
 #if 1
+	/* If regs->sr[7] == 0, we are on a kernel stack */
+	if (regs->sr[7] == 0) {
+
+		unsigned long sp = regs->gr[30];
+		unsigned long cr30;
+		unsigned long cr31;
+		unsigned long stack_start;
+		struct pt_regs *int_regs;
+
+		cr30 = mfctl(30);
+		cr31 = mfctl(31);
+		stack_start = sp & ~(ISTACK_SIZE - 1);
+		if (stack_start == cr31) {
+		    /*
+		     * We are on the interrupt stack, get the stack
+		     * pointer from the first pt_regs structure on
+		     * the interrupt stack, so we can dump the task
+		     * stack first.
+		     */
+
+		    int_regs = (struct pt_regs *)cr31;
+		    sp = int_regs->gr[30];
+		    stack_start = sp & ~(INIT_TASK_SIZE - 1);
+		    if (stack_start != cr30) {
+			printk(KERN_CRIT "WARNING! Interrupt-Stack pointer and cr30 do not correspond!\n");
+			printk(KERN_CRIT "Dumping virtual address stack instead\n");
+			dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
+		    } else {
+			dump_stack(stack_start, sp, 0);
+		    };
+
+		    printk("\n\n" KERN_DEBUG "Registers at Interrupt:\n");
+		    show_regs(int_regs);
+
+		    /* Now dump the interrupt stack */
+
+		    sp = regs->gr[30];
+		    stack_start = sp & ~(ISTACK_SIZE - 1);
+		    dump_stack(stack_start,sp,1);
+		}
+		else
+		{
+		    /* Stack Dump! */
+		    printk(KERN_CRIT "WARNING! Stack pointer and cr30 do not correspond!\n");
+		    printk(KERN_CRIT "Dumping virtual address stack instead\n");
+		    dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
+		}
+	}
+#endif
+}
+
+
+void die_if_kernel(char *str, struct pt_regs *regs, long err)
+{
+	if (user_mode(regs)) {
+#ifdef PRINT_USER_FAULTS
 		if (err == 0)
 			return; /* STFU */
 
 		/* XXX for debugging only */
-		printk ("!!die_if_kernel: %s(%d): %s %ld\n",
+		printk(KERN_DEBUG "%s (pid %d): %s (code %ld)\n",
 			current->comm, current->pid, str, err);
 		show_regs(regs);
 #endif
 		return;
 	}
+	
+	/* unlock the pdc lock if necessary */
+	pdc_emergency_unlock();
 
-	printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
-
+	/* maybe the kernel hasn't booted very far yet and hasn't been able 
+	 * to initialize the serial or STI console. In that case we should 
+	 * re-enable the pdc console, so that the user will be able to 
+	 * identify the problem. */
+	if (!console_drivers)
+		pdc_console_restart();
+	
+	printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
+		current->comm, current->pid, str, err);
 	show_regs(regs);
 
 	/* Wot's wrong wif bein' racy? */
 	if (current->thread.flags & PARISC_KERNEL_DEATH) {
-		printk("die_if_kernel recursion detected.\n");
+		printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
 		sti();
 		while (1);
 	}
+
 	current->thread.flags |= PARISC_KERNEL_DEATH;
 	do_exit(SIGSEGV);
 }
 
-asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code)
-{
-}
-
-asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
-{
-}
-
-#ifndef CONFIG_MATH_EMULATION
-
-asmlinkage void math_emulate(long arg)
-{
-}
-
-#endif /* CONFIG_MATH_EMULATION */
-
 int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs)
 {
 	return syscall(regs);
 }
 
-struct {
-	int retval;
-
-	int (*func) (void *, struct pt_regs *);
-	void * data;
-} ipi_action[NR_CPUS];
-
-void ipi_interrupt(int irq, void *unused, struct pt_regs *regs)
-{
-	int cpu = smp_processor_id();
-
-	if(!ipi_action[cpu].func)
-		BUG();
-
-	ipi_action[cpu].retval =
-		ipi_action[cpu].func(ipi_action[cpu].data, regs);
-}
-
 /* gdb uses break 4,8 */
 #define GDB_BREAK_INSN 0x10004
 void handle_gdb_break(struct pt_regs *regs, int wot)
@@ -204,15 +264,16 @@
 	struct save_state ssp;
 #endif /* CONFIG_KWDB */   
 
-	flush_all_caches();
 	switch(iir) {
 	case 0x00:
-		/* show registers, halt */
-		cli();
-		printk("break 0,0: pid=%d command='%s'\n",
+#ifdef PRINT_USER_FAULTS
+		printk(KERN_DEBUG "break 0,0: pid=%d command='%s'\n",
 		       current->pid, current->comm);
+#endif
 		die_if_kernel("Breakpoint", regs, 0);
+#ifdef PRINT_USER_FAULTS
 		show_regs(regs);
+#endif
 		si.si_code = TRAP_BRKPT;
 		si.si_addr = (void *) (regs->iaoq[0] & ~3);
 		si.si_signo = SIGTRAP;
@@ -225,7 +286,6 @@
 		break;
 
 #ifdef CONFIG_KWDB
-
 	case KGDB_BREAK_INSN:
 		mtctl(0, 15);
 		pt_regs_to_ssp(regs, &ssp);
@@ -243,14 +303,14 @@
 		regs->iaoq[0] = regs->iaoq[1];
 		regs->iaoq[1] += 4;
 		break;
-
 #endif /* CONFIG_KWDB */
 
 	default:
-		set_eiem(0);
-		printk("break %#08x: pid=%d command='%s'\n",
+#ifdef PRINT_USER_FAULTS
+		printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n",
 		       iir, current->pid, current->comm);
 		show_regs(regs);
+#endif
 		si.si_signo = SIGTRAP;
 		si.si_code = TRAP_BRKPT;
 		si.si_addr = (void *) (regs->iaoq[0] & ~3);
@@ -259,252 +319,151 @@
 	}
 }
 
-/* Format of the floating-point exception registers. */
-struct exc_reg {
-	unsigned int exception : 6;
-	unsigned int ei : 26;
-};
-
-/* Macros for grabbing bits of the instruction format from the 'ei'
-   field above. */
-/* Major opcode 0c and 0e */
-#define FP0CE_UID(i) (((i) >> 6) & 3)
-#define FP0CE_CLASS(i) (((i) >> 9) & 3)
-#define FP0CE_SUBOP(i) (((i) >> 13) & 7)
-#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
-#define FP0C_FORMAT(i) (((i) >> 11) & 3)
-#define FP0E_FORMAT(i) (((i) >> 11) & 1)
-
-/* Major opcode 0c, uid 2 (performance monitoring) */
-#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
-
-/* Major opcode 2e (fused operations).   */
-#define FP2E_SUBOP(i)  (((i) >> 5) & 1)
-#define FP2E_FORMAT(i) (((i) >> 11) & 1)
-
-/* Major opcode 26 (FMPYSUB) */
-/* Major opcode 06 (FMPYADD) */
-#define FPx6_FORMAT(i) ((i) & 0x1f)
-
-/* Flags and enable bits of the status word. */
-#define FPSW_FLAGS(w) ((w) >> 27)
-#define FPSW_ENABLE(w) ((w) & 0x1f)
-#define FPSW_V (1<<4)
-#define FPSW_Z (1<<3)
-#define FPSW_O (1<<2)
-#define FPSW_U (1<<1)
-#define FPSW_I (1<<0)
-
-/* Emulate a floating point instruction if necessary and possible
-   (this will be moved elsewhere eventually).  Return zero if
-   successful or if emulation was not required, -1 if the instruction
-   is actually illegal or unimplemented.  The status word passed as
-   the first parameter will be modified to signal exceptions, if
-   any. */
-
-/* FIXME!!!  This is really incomplete and, at the moment, most
-   illegal FP instructions will simply act as no-ops.  Obviously that
-   is *not* what we want.  Also we don't even try to handle exception
-   types other than the 'unimplemented' ones. */
-int
-fp_emul_insn(u32 *sw, struct exc_reg exc, struct pt_regs *regs)
-{
-	switch (exc.exception) {
-	case 0x3:  /* Unimplemented, opcode 06 */
-		break;
-	case 0x9:  /* Unimplemented, opcode 0c */
-		/* We do not support quadword operations, end of
-                   story.  There's no support for them in GCC. */
-		if (FP0C_FORMAT(exc.ei) == 3)
-			return -1; /* SIGILL */
-		/* Fall through. */
-	case 0xa:  /* Unimplemented, opcode 0e */
-		if (FP0CE_CLASS(exc.ei) == 1) {
-			/* FCNV instructions of various sorts. */
-		} else {
-			if (FP0CE_CLASS(exc.ei == 0)
-			    && FP0CE_SUBOP(exc.ei == 5)) {
-				/* FRND instructions should be
-                                   emulated, at some point, I
-                                   guess. */
-				return -1; /* SIGILL */
-			}
-		}
-		break;
-	case 0x23: /* Unimplemented, opcode 26 */
-		break;
-	case 0x2b: /* Unimplemented, opcode 2e */
-		break;
-	case 0x1:  /* Unimplemented, opcode 0e/0c */
-		/* FIXME: How the hell are we supposed to tell which
-                   opcode it is? */
-		break;
-	default:
-		return -1; /* Punt */
-	}
 
+int handle_toc(void)
+{
+	printk(KERN_CRIT "TOC call.\n");
 	return 0;
 }
 
-/* Handle a floating point exception.  Return zero if the faulting
-   instruction can be completed successfully. */
-int
-handle_fpe(struct pt_regs *regs)
+static void default_trap(int code, struct pt_regs *regs)
 {
-	struct siginfo si;
-	union {
-		struct fpsw {
-			/* flag bits */
-			unsigned int fv : 1;
-			unsigned int fz : 1;
-			unsigned int fo : 1;
-			unsigned int fu : 1;
-			unsigned int fi : 1;
-
-			unsigned int c : 1;
-			unsigned int pad1 : 4;
-			unsigned int cq : 11;
-			unsigned int rm : 2;
-			unsigned int pad2 : 2;
-			unsigned int t : 1;
-			unsigned int d : 1;
-
-			/* enable bits */
-			unsigned int ev : 1;
-			unsigned int ez : 1;
-			unsigned int eo : 1;
-			unsigned int eu : 1;
-			unsigned int ei : 1;
-		} status;
-		u32 word;
-	} sw;
-	struct exc_reg excepts[7];
-	unsigned int code = 0;
-	unsigned int throw;
-
-	/* Status word = FR0L. */
-	memcpy(&sw, regs->fr, sizeof(sw));
-	/* Exception words = FR0R-FR3R. */
-	memcpy(excepts, ((char *) regs->fr) + 4, sizeof(excepts));
-
-	/* This is all CPU dependent.  Since there is no public
-           documentation on the PA2.0 processors we will just assume
-           everything is like the 7100/7100LC/7300LC for now.
-
-	   Specifically: All exceptions are marked as "unimplemented"
-	   in the exception word, and the only exception word used is
-	   excepts[1]. */
-
-	/* Try to emulate the instruction.  Also determine if it is
-           really an illegal instruction in the process.
-
-	   FIXME: fp_emul_insn() only checks for the "unimplemented"
-	   exceptions at the moment.  So this may break horribly on
-	   PA2.0, where we may want to also check to see if we should
-	   just send SIGFPE (or maybe not, let's see the documentation
-	   first...) */
-	if (fp_emul_insn(&sw.word, excepts[1], regs) == -1)
-		goto send_sigill;
-
-	/* Take the intersection of the flag bits in the FPSW and the
-           enable bits in the FPSW. */
-	throw = FPSW_FLAGS(sw.word) & FPSW_ENABLE(sw.word);
-
-	/* Concoct an appropriate si_code.  Of course we don't know
-           what to do if multiple exceptions were enabled and multiple
-           flags were set.  Maybe that's why HP/UX doesn't implement
-           feenableexcept(). */
-
-	if (throw == 0)
-		goto success; /* Duh. */
-	else if (throw & FPSW_V)
-		code = FPE_FLTINV;
-	else if (throw & FPSW_Z)
-		code = FPE_FLTDIV;
-	else if (throw & FPSW_O)
-		code = FPE_FLTOVF;
-	else if (throw & FPSW_U)
-		code = FPE_FLTUND;
-	else if (throw & FPSW_I)
-		code = FPE_FLTRES;
-
-#if 1 /* Debugging... */
-	printk("Unemulated floating point exception, pid=%d (%s)\n",
-	       current->pid, current->comm);
+	printk(KERN_ERR "Trap %d on CPU %d\n", code, smp_processor_id());
 	show_regs(regs);
-	{
-		int i;
-		printk("FP Status: %08x\n", sw.word);
-		printk("FP Exceptions:\n");
-		for (i = 0; i < 7; i++) {
-			printk("\tExcept%d: exception %03x insn %06x\n",
-			       i, excepts[i].exception, excepts[i].ei);
-		}
-	}
-#endif
+}
 
-	/* FIXME: Should we clear the flag bits, T bit, and exception
-           registers here? */
+void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
 
-	si.si_signo = SIGFPE;
-	si.si_errno = 0;
-	si.si_code = code;
-	si.si_addr = (void *) regs->iaoq[0];
-	force_sig_info(SIGFPE, &si, current);
-	return -1;
 
- send_sigill:
-	si.si_signo = SIGILL;
-	si.si_errno = 0;
-	si.si_code = ILL_COPROC;
-	si.si_addr = (void *) regs->iaoq[0];
-	force_sig_info(SIGILL, &si, current);
-	return -1;
-
- success:
-	/* We absolutely have to clear the T bit and exception
-           registers to allow the process to recover.  Otherwise every
-           subsequent floating point instruction will trap. */
-	sw.status.t = 0;
-	memset(excepts, 0, sizeof(excepts));
-
-	memcpy(regs->fr, &sw, sizeof(sw));
-	memcpy(((char *) regs->fr) + 4,excepts , sizeof(excepts));
-	return 0;
+#ifdef CONFIG_KWDB
+int debug_call (void)
+{
+    printk (KERN_DEBUG "Debug call.\n");
+    return 0;
 }
 
-int handle_toc(void)
+int debug_call_leaf (void)
 {
-	return 0;
+    return 0;
 }
+#endif /* CONFIG_KWDB */
+
 
-void default_trap(int code, struct pt_regs *regs)
+void transfer_pim_to_trap_frame(struct pt_regs *regs)
 {
-	printk("Trap %d on CPU %d\n", code, smp_processor_id());
+    register int i;
+    extern unsigned int hpmc_pim_data[];
+    struct pdc_hpmc_pim_11 *pim_narrow;
+    struct pdc_hpmc_pim_20 *pim_wide;
 
-	show_regs(regs);
-}
+    if (boot_cpu_data.cpu_type >= pcxu) {
 
-void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
+	pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;
 
+	/*
+	 * Note: The following code will probably generate a
+	 * bunch of truncation error warnings from the compiler.
+	 * Could be handled with an ifdef, but perhaps there
+	 * is a better way.
+	 */
 
-#ifdef CONFIG_KWDB
-int
-debug_call (void) {
-    printk ("Debug call.\n");
-    return 0;
-}
+	regs->gr[0] = pim_wide->cr[22];
 
-int
-debug_call_leaf (void) {
-    return 0;
+	for (i = 1; i < 32; i++)
+	    regs->gr[i] = pim_wide->gr[i];
+
+	for (i = 0; i < 32; i++)
+	    regs->fr[i] = pim_wide->fr[i];
+
+	for (i = 0; i < 8; i++)
+	    regs->sr[i] = pim_wide->sr[i];
+
+	regs->iasq[0] = pim_wide->cr[17];
+	regs->iasq[1] = pim_wide->iasq_back;
+	regs->iaoq[0] = pim_wide->cr[18];
+	regs->iaoq[1] = pim_wide->iaoq_back;
+
+	regs->sar  = pim_wide->cr[11];
+	regs->iir  = pim_wide->cr[19];
+	regs->isr  = pim_wide->cr[20];
+	regs->ior  = pim_wide->cr[21];
+    }
+    else {
+	pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;
+
+	regs->gr[0] = pim_narrow->cr[22];
+
+	for (i = 1; i < 32; i++)
+	    regs->gr[i] = pim_narrow->gr[i];
+
+	for (i = 0; i < 32; i++)
+	    regs->fr[i] = pim_narrow->fr[i];
+
+	for (i = 0; i < 8; i++)
+	    regs->sr[i] = pim_narrow->sr[i];
+
+	regs->iasq[0] = pim_narrow->cr[17];
+	regs->iasq[1] = pim_narrow->iasq_back;
+	regs->iaoq[0] = pim_narrow->cr[18];
+	regs->iaoq[1] = pim_narrow->iaoq_back;
+
+	regs->sar  = pim_narrow->cr[11];
+	regs->iir  = pim_narrow->cr[19];
+	regs->isr  = pim_narrow->cr[20];
+	regs->ior  = pim_narrow->cr[21];
+    }
+
+    /*
+     * The following fields only have meaning if we came through
+     * another path. So just zero them here.
+     */
+
+    regs->ksp = 0;
+    regs->kpc = 0;
+    regs->orig_r28 = 0;
 }
-#endif /* CONFIG_KWDB */
 
-extern void do_page_fault(struct pt_regs *, int, unsigned long);
-extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long);
-extern void transfer_pim_to_trap_frame(struct pt_regs *);
-extern void pdc_console_restart(void);
+
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset)
+{
+	static spinlock_t terminate_lock = SPIN_LOCK_UNLOCKED;
+
+	set_eiem(0);
+	__cli();
+	spin_lock(&terminate_lock);
+
+	/* unlock the pdc lock if necessary */
+	pdc_emergency_unlock();
+
+	/* restart pdc console if necessary */
+	if (!console_drivers)
+		pdc_console_restart();
+
+	if (code == 1)
+	    transfer_pim_to_trap_frame(regs);
+
+	show_stack(regs);
+
+	printk("\n");
+	printk(KERN_CRIT "%s: Code=%d regs=%p (Addr=" RFMT ")\n",
+			msg, code, regs, offset);
+	show_regs(regs);
+
+	spin_unlock(&terminate_lock);
+
+	/* put soft power button back under hardware control;
+	 * if the user had pressed it once at any time, the 
+	 * system will shut down immediately right here. */
+	pdc_soft_power_button(0);
+	
+	for(;;)
+	    ;
+}
 
 void handle_interruption(int code, struct pt_regs *regs)
 {
@@ -520,75 +479,127 @@
 	else
 	    sti();
 
-#ifdef __LP64__
-
-	/*
-	 * FIXME:
-	 * For 32 bit processes we don't want the b bits (bits 0 & 1)
-	 * in the ior. This is more appropriately handled in the tlb
-	 * miss handlers. Changes need to be made to support addresses
-	 * >32 bits for 64 bit processes.
-	 */
-
-	regs->ior &= 0x3FFFFFFFFFFFFFFFUL;
-#endif
-
 #if 0
-	printk("interrupted with code %d, regs %p\n", code, regs);
-	show_regs(regs);
+	printk(KERN_CRIT "Interruption # %d\n", code);
 #endif
 
 	switch(code) {
+
 	case  1:
-		parisc_terminate("High Priority Machine Check (HPMC)",regs,code,0);
+		/* High-priority machine check (HPMC) */
+		parisc_terminate("High Priority Machine Check (HPMC)",
+				regs, code, 0);
 		/* NOT REACHED */
-	case  3: /* Recovery counter trap */
+		
+	case  2:
+		/* Power failure interrupt */
+		printk(KERN_CRIT "Power failure interrupt !\n");
+		return;
+
+	case  3:
+		/* Recovery counter trap */
 		regs->gr[0] &= ~PSW_R;
 		if (regs->iasq[0])
 			handle_gdb_break(regs, TRAP_TRACE);
-		/* else this must be the start of a syscall - just let it
-		 * run.
-		 */
+		/* else this must be the start of a syscall - just let it run */
 		return;
 
 	case  5:
+		/* Low-priority machine check */
 		flush_all_caches();
 		cpu_lpmc(5, regs);
 		return;
 
 	case  6:
+		/* Instruction TLB miss fault/Instruction page fault */
 		fault_address = regs->iaoq[0];
 		fault_space   = regs->iasq[0];
 		break;
 
-	case  9: /* Break Instruction */
+	case  8:
+		/* Illegal instruction trap */
+		die_if_kernel("Illegal instruction", regs, code);
+		si.si_code = ILL_ILLOPC;
+		goto give_sigill;
+
+	case  9:
+		/* Break instruction trap */
 		handle_break(regs->iir,regs);
 		return;
+	
+	case 10:
+		/* Privileged operation trap */
+		die_if_kernel("Privileged operation", regs, code);
+		si.si_code = ILL_PRVOPC;
+		goto give_sigill;
+	
+	case 11:
+		/* Privileged register trap */
+		if ((regs->iir & 0xffdfffe0) == 0x034008a0) {
+
+			/* This is a MFCTL cr26/cr27 to gr instruction.
+			 * PCXS traps on this, so we need to emulate it.
+			 */
+
+			if (regs->iir & 0x00200000)
+				regs->gr[regs->iir & 0x1f] = mfctl(27);
+			else
+				regs->gr[regs->iir & 0x1f] = mfctl(26);
+
+			regs->iaoq[0] = regs->iaoq[1];
+			regs->iaoq[1] += 4;
+			regs->iasq[0] = regs->iasq[1];
+			return;
+		}
+
+		die_if_kernel("Privileged register usage", regs, code);
+		si.si_code = ILL_PRVREG;
+	give_sigill:
+		si.si_signo = SIGILL;
+		si.si_errno = 0;
+		si.si_addr = (void *) regs->iaoq[0];
+		force_sig_info(SIGILL, &si, current);
+		return;
 
 	case 14:
 		/* Assist Exception Trap, i.e. floating point exception. */
 		die_if_kernel("Floating point exception", regs, 0); /* quiet */
 		handle_fpe(regs);
 		return;
-	case 15:
-	case 16:  /* Non-Access TLB miss faulting address is in IOR */
+
 	case 17:
-	case 26:
+		/* Non-access data TLB miss fault/Non-access data page fault */
+		/* TODO: Still need to add slow path emulation code here */
 		fault_address = regs->ior;
-		fault_space   = regs->isr;
+		parisc_terminate("Non access data tlb fault!",regs,code,fault_address);
 
-		if (code == 26 && fault_space == 0)
-		    parisc_terminate("Data access rights fault in kernel",regs,code,fault_address);
+	case 18:
+		/* PCXS only -- later cpu's split this into types 26,27 & 28 */
+		/* Check for unaligned access */
+		if (check_unaligned(regs)) {
+			handle_unaligned(regs);
+			return;
+		}
+		/* Fall Through */
+
+	case 15: /* Data TLB miss fault/Data page fault */
+	case 26: /* PCXL: Data memory access rights trap */
+		fault_address = regs->ior;
+		fault_space   = regs->isr;
 		break;
 
 	case 19:
+		/* Data memory break trap */
 		regs->gr[0] |= PSW_X; /* So we can single-step over the trap */
 		/* fall thru */
 	case 21:
+		/* Page reference trap */
 		handle_gdb_break(regs, TRAP_HWBKPT);
 		return;
 
-	case 25: /* Taken branch trap */
+	case 25:
+		/* Taken branch trap */
+#ifndef CONFIG_KWDB
 		regs->gr[0] &= ~PSW_T;
 		if (regs->iasq[0])
 			handle_gdb_break(regs, TRAP_BRANCH);
@@ -596,9 +607,8 @@
 		 * run.
 		 */
 		return;
-
-#if 0 /* def CONFIG_KWDB */
-	case I_TAKEN_BR:	/* 25 */
+#else
+		/* Kernel debugger: */
 		mtctl(0, 15);
 		pt_regs_to_ssp(regs, &ssp);
 		kgdb_trap(I_TAKEN_BR, &ssp, 1);
@@ -606,39 +616,64 @@
 		break;
 #endif /* CONFIG_KWDB */
 
-	case  8:
-		die_if_kernel("Illegal instruction", regs, code);
-		si.si_code = ILL_ILLOPC;
-		goto give_sigill;
+	case  7:  
+		/* Instruction access rights */
+		/* PCXL: Instruction memory protection trap */
+
+		/*
+		 * This could be caused by either: 1) a process attempting
+		 * to execute within a vma that does not have execute
+		 * permission, or 2) an access rights violation caused by a
+		 * flush only translation set up by ptep_get_and_clear().
+		 * So we check the vma permissions to differentiate the two.
+		 * If the vma indicates we have execute permission, then
+		 * the cause is the latter one. In this case, we need to
+		 * call do_page_fault() to fix the problem.
+		 */
 
-	case 10:
-		die_if_kernel("Priviledged operation - shouldn't happen!", regs, code);
-		si.si_code = ILL_PRVOPC;
-		goto give_sigill;
-	case 11:
-		die_if_kernel("Priviledged register - shouldn't happen!", regs, code);
-		si.si_code = ILL_PRVREG;
-	give_sigill:
-		si.si_signo = SIGILL;
+		if (user_mode(regs)) {
+			struct vm_area_struct *vma;
+
+			down_read(&current->mm->mmap_sem);
+			vma = find_vma(current->mm,regs->iaoq[0]);
+			if (vma && (regs->iaoq[0] >= vma->vm_start)
+				&& (vma->vm_flags & VM_EXEC)) {
+
+				fault_address = regs->iaoq[0];
+				fault_space = regs->iasq[0];
+
+				up_read(&current->mm->mmap_sem);
+				break; /* call do_page_fault() */
+			}
+			up_read(&current->mm->mmap_sem);
+		}
+		/* Fall Through */
+
+	case 27: 
+		/* Data memory protection ID trap */
+		die_if_kernel("Protection id trap", regs, code);
+		si.si_code = SEGV_MAPERR;
+		si.si_signo = SIGSEGV;
 		si.si_errno = 0;
-		si.si_addr = (void *) regs->iaoq[0];
-		force_sig_info(SIGILL, &si, current);
+		if (code == 7)
+		    si.si_addr = (void *) regs->iaoq[0];
+		else
+		    si.si_addr = (void *) regs->ior;
+		force_sig_info(SIGSEGV, &si, current);
 		return;
 
-	case 28:  /* Unaligned just causes SIGBUS for now */
-		die_if_kernel("Unaligned data reference", regs, code);
-		si.si_code = BUS_ADRALN;
-		si.si_signo = SIGBUS;
-		si.si_errno = 0;
-		si.si_addr = (void *) regs->ior;
-		force_sig_info(SIGBUS, &si, current);
+	case 28: 
+		/* Unaligned data reference trap */
+		handle_unaligned(regs);
 		return;
 
 	default:
 		if (user_mode(regs)) {
-			printk("\nhandle_interruption() pid=%d command='%s'\n",
+#ifdef PRINT_USER_FAULTS
+			printk(KERN_DEBUG "\nhandle_interruption() pid=%d command='%s'\n",
 			    current->pid, current->comm);
 			show_regs(regs);
+#endif
 			/* SIGBUS, for lack of a better one. */
 			si.si_signo = SIGBUS;
 			si.si_code = BUS_OBJERR;
@@ -647,18 +682,20 @@
 			force_sig_info(SIGBUS, &si, current);
 			return;
 		}
-		parisc_terminate("Unexpected Interruption!",regs,code,0);
+		parisc_terminate("Unexpected interruption", regs, code, 0);
 		/* NOT REACHED */
 	}
 
 	if (user_mode(regs)) {
 	    if (fault_space != regs->sr[7]) {
+#ifdef PRINT_USER_FAULTS
 		if (fault_space == 0)
-			printk("User Fault on Kernel Space ");
-		else /* this case should never happen, but whatever... */
-			printk("User Fault (long pointer) ");
+			printk(KERN_DEBUG "User Fault on Kernel Space ");
+		else
+			printk(KERN_DEBUG "User Fault (long pointer) ");
 		printk("pid=%d command='%s'\n", current->pid, current->comm);
 		show_regs(regs);
+#endif
 		si.si_signo = SIGSEGV;
 		si.si_errno = 0;
 		si.si_code = SEGV_MAPERR;
@@ -674,7 +711,7 @@
 	     */
 
 	    if (fault_space == 0)
-		    parisc_terminate("Kernel Fault",regs,code,fault_address);
+		    parisc_terminate("Kernel Fault", regs, code, fault_address);
 	}
 
 #ifdef CONFIG_KWDB
@@ -682,149 +719,15 @@
 #endif /* CONFIG_KWDB */
 
 	do_page_fault(regs, code, fault_address);
-
-	/*
-	 * This should not be necessary.
-	 * However, we do not currently
-	 * implement flush_page_to_ram.
-	 *
-	 * The problem is that if we just
-	 * brought in some code through the
-	 * D-cache, the I-cache may not see
-	 * it since it hasn't been flushed
-	 * to ram.
-	 */
-
-/* 	flush_all_caches(); */
-
-#if 0
-	printk("returning %p\n", regs);
-/*	show_regs(regs); */
-#endif
-
-	return;
-
-}
-
-void show_stack(unsigned long sp)
-{
-#if 1
-	if ((sp & 0xc0000000UL) == 0xc0000000UL) {
-
-	    __u32 *stackptr;
-	    __u32 *dumpptr;
-
-	    /* Stack Dump! */
-
-	    stackptr = (__u32 *)sp;
-	    dumpptr  = (__u32 *)(sp & ~(INIT_TASK_SIZE - 1));
-	    printk("\nDumping Stack from %p to %p:\n",dumpptr,stackptr);
-	    while (dumpptr < stackptr) {
-		printk("%04x %08x %08x %08x %08x %08x %08x %08x %08x\n",
-		    ((__u32)dumpptr) & 0xffff,
-		    dumpptr[0], dumpptr[1], dumpptr[2], dumpptr[3],
-		    dumpptr[4], dumpptr[5], dumpptr[6], dumpptr[7]);
-		dumpptr += 8;
-	    }
-	}
-#endif
 }
 
 
-void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset)
+void show_trace_task(struct task_struct *tsk)
 {
-	set_eiem(0);
-	cli();
-
-	if (code == 1)
-	    transfer_pim_to_trap_frame(regs);
-
-#if 1
-	show_stack(regs->gr[30]);
-#endif
-
-	printk("\n%s: Code=%d regs=%p (Addr=%08lx)\n",msg,code,regs,offset);
-	show_regs(regs);
-
-	for(;;)
-	    ;
+    	BUG();
 }
 
-void transfer_pim_to_trap_frame(struct pt_regs *regs)
-{
-    register int i;
-    extern unsigned int hpmc_pim_data[];
-    struct pdc_hpmc_pim_11 *pim_narrow;
-    struct pdc_hpmc_pim_20 *pim_wide;
-
-    if (boot_cpu_data.cpu_type >= pcxu) {
 
-	pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;
-
-	/*
-	 * Note: The following code will probably generate a
-	 * bunch of truncation error warnings from the compiler.
-	 * Could be handled with an ifdef, but perhaps there
-	 * is a better way.
-	 */
-
-	regs->gr[0] = pim_wide->cr[22];
-
-	for (i = 1; i < 32; i++)
-	    regs->gr[i] = pim_wide->gr[i];
-
-	for (i = 0; i < 32; i++)
-	    regs->fr[i] = pim_wide->fr[i];
-
-	for (i = 0; i < 8; i++)
-	    regs->sr[i] = pim_wide->sr[i];
-
-	regs->iasq[0] = pim_wide->cr[17];
-	regs->iasq[1] = pim_wide->iasq_back;
-	regs->iaoq[0] = pim_wide->cr[18];
-	regs->iaoq[1] = pim_wide->iaoq_back;
-
-	regs->cr30 = pim_wide->cr[30];
-	regs->sar  = pim_wide->cr[11];
-	regs->iir  = pim_wide->cr[19];
-	regs->isr  = pim_wide->cr[20];
-	regs->ior  = pim_wide->cr[21];
-    }
-    else {
-	pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;
-
-	regs->gr[0] = pim_narrow->cr[22];
-
-	for (i = 1; i < 32; i++)
-	    regs->gr[i] = pim_narrow->gr[i];
-
-	for (i = 0; i < 32; i++)
-	    regs->fr[i] = pim_narrow->fr[i];
-
-	for (i = 0; i < 8; i++)
-	    regs->sr[i] = pim_narrow->sr[i];
-
-	regs->iasq[0] = pim_narrow->cr[17];
-	regs->iasq[1] = pim_narrow->iasq_back;
-	regs->iaoq[0] = pim_narrow->cr[18];
-	regs->iaoq[1] = pim_narrow->iaoq_back;
-
-	regs->cr30 = pim_narrow->cr[30];
-	regs->sar  = pim_narrow->cr[11];
-	regs->iir  = pim_narrow->cr[19];
-	regs->isr  = pim_narrow->cr[20];
-	regs->ior  = pim_narrow->cr[21];
-    }
-
-    /*
-     * The following fields only have meaning if we came through
-     * another path. So just zero them here.
-     */
-
-    regs->ksp = 0;
-    regs->kpc = 0;
-    regs->orig_r28 = 0;
-}
 
 int __init check_ivt(void *iva)
 {
@@ -836,7 +739,7 @@
 	extern void os_hpmc(void);
 	extern void os_hpmc_end(void);
 
-	if(strcmp((char *)iva, "cows can fly"))
+	if (strcmp((char *)iva, "cows can fly"))
 		return -1;
 
 	ivap = (u32 *)iva;
@@ -851,10 +754,10 @@
 
 	hpmcp = (u32 *)os_hpmc;
 
-	for(i=0; i<length/4; i++)
+	for (i=0; i<length/4; i++)
 	    check += *hpmcp++;
 
-	for(i=0; i<8; i++)
+	for (i=0; i<8; i++)
 	    check += ivap[i];
 
 	ivap[5] = -check;
@@ -869,11 +772,8 @@
 
 void __init trap_init(void)
 {
-	volatile long eiem;
 	void *iva;
 
-	printk("trap_init\n");
-	
 	if (boot_cpu_data.cpu_type >= pcxu)
 		iva = (void *) &fault_vector_20;
 	else
@@ -883,12 +783,6 @@
 		iva = (void *) &fault_vector_11;
 #endif
 
-	if(check_ivt(iva))
+	if (check_ivt(iva))
 		panic("IVT invalid");
-
-	mtctl(0, 30);
-	mtctl(90000000, 16);
-	set_eiem(-1L);
-	mtctl(-1L, 23);
-	asm volatile ("rsm 0,%0" : "=r" (eiem));
 }
diff -urN linux-2.4.20-pre1/arch/parisc/kernel/unaligned.c linux-2.4.20-pre2/arch/parisc/kernel/unaligned.c
--- linux-2.4.20-pre1/arch/parisc/kernel/unaligned.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/kernel/unaligned.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,434 @@
+/*    $Id: unaligned.c,v 1.9 2001/10/04 03:31:08 tausq Exp $
+ *
+ *    Unaligned memory access handler
+ *
+ *    Copyright (C) 2001 Randolph Chung <tausq@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#include <asm/smp.h>
+#include <asm/pdc.h>
+
+/* #define DEBUG_UNALIGNED 1 */
+
+#ifdef DEBUG_UNALIGNED
+#define DPRINTF(fmt, args...) do { printk(KERN_DEBUG "%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__ ); printk(KERN_DEBUG fmt, ##args ); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+#ifdef __LP64__
+#define RFMT "%016lx"
+#else
+#define RFMT "%08lx"
+#endif
+
+/* 1111 1100 0000 0000 0001 0011 1100 0000 */
+#define OPCODE1(a,b,c)	((a)<<26|(b)<<12|(c)<<6) 
+#define OPCODE2(a,b)	((a)<<26|(b)<<1)
+#define OPCODE3(a,b)	((a)<<26|(b)<<2)
+#define OPCODE4(a)	((a)<<26)
+#define OPCODE1_MASK	OPCODE1(0x3f,1,0xf)
+#define OPCODE2_MASK 	OPCODE2(0x3f,1)
+#define OPCODE3_MASK	OPCODE3(0x3f,1)
+#define OPCODE4_MASK    OPCODE4(0x3f)
+
+/* skip LDB (index) */
+#define OPCODE_LDH_I	OPCODE1(0x03,0,0x1)
+#define OPCODE_LDW_I	OPCODE1(0x03,0,0x2)
+#define OPCODE_LDD_I	OPCODE1(0x03,0,0x3)
+#define OPCODE_LDDA_I	OPCODE1(0x03,0,0x4)
+/* skip LDCD (index) */
+#define OPCODE_LDWA_I	OPCODE1(0x03,0,0x6)
+/* skip LDCW (index) */
+/* skip LDB (short) */
+#define OPCODE_LDH_S	OPCODE1(0x03,1,0x1)
+#define OPCODE_LDW_S	OPCODE1(0x03,1,0x2)
+#define OPCODE_LDD_S	OPCODE1(0x03,1,0x3)
+#define OPCODE_LDDA_S	OPCODE1(0x03,1,0x4)
+/* skip LDCD (short) */
+#define OPCODE_LDWA_S	OPCODE1(0x03,1,0x6)
+/* skip LDCW (short) */
+/* skip STB */
+#define OPCODE_STH	OPCODE1(0x03,1,0x9)
+#define OPCODE_STW	OPCODE1(0x03,1,0xa)
+#define OPCODE_STD	OPCODE1(0x03,1,0xb)
+/* skip STBY */
+/* skip STDBY */
+#define OPCODE_STWA	OPCODE1(0x03,1,0xe)
+#define OPCODE_STDA	OPCODE1(0x03,1,0xf)
+
+#define OPCODE_LDD_L	OPCODE2(0x14,0)
+#define OPCODE_FLDD_L	OPCODE2(0x14,1)
+#define OPCODE_STD_L	OPCODE2(0x1c,0)
+#define OPCODE_FSTD_L	OPCODE2(0x1c,1)
+
+#define OPCODE_LDW_M	OPCODE3(0x17,1)
+#define OPCODE_FLDW_L	OPCODE3(0x17,0)
+#define OPCODE_FSTW_L	OPCODE3(0x1f,0)
+#define OPCODE_STW_M	OPCODE3(0x1f,1)
+
+#define OPCODE_LDH_L    OPCODE4(0x11)
+#define OPCODE_LDW_L    OPCODE4(0x12)
+#define OPCODE_LDW_L2   OPCODE4(0x13)
+#define OPCODE_STH_L    OPCODE4(0x19)
+#define OPCODE_STW_L    OPCODE4(0x1A)
+#define OPCODE_STW_L2   OPCODE4(0x1B)
+
+
+
+void die_if_kernel (char *str, struct pt_regs *regs, long err);
+
+static int emulate_load(struct pt_regs *regs, int len, int toreg)
+{
+	unsigned long saddr = regs->ior;
+	unsigned long val = 0;
+	int ret = 0;
+
+	if (regs->isr != regs->sr[7])
+	{
+		printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
+			regs->isr, regs->sr[7]);
+		return 1;
+	}
+
+	DPRINTF("load " RFMT ":" RFMT " to r%d for %d bytes\n", 
+		regs->isr, regs->ior, toreg, len);
+
+	__asm__ __volatile__  (
+"       mfsp %%sr1, %%r20\n"
+"       mtsp %6, %%sr1\n"
+"	copy %%r0, %0\n"
+"0:	ldbs,ma	1(%%sr1,%4), %%r19\n"
+"	addi -1, %5, %5\n"
+"	cmpib,>= 0, %5, 2f\n"
+"	or %%r19, %0, %0\n"
+"	b 0b\n"
+	
+#ifdef __LP64__
+	"depd,z %0, 55, 56, %0\n"
+#else
+	"depw,z %0, 23, 24, %0\n"
+#endif
+	
+"1:	ldi	10, %1\n"
+"2:     mtsp %%r20, %%sr1\n"
+"	.section __ex_table,\"a\"\n"
+#ifdef __LP64__
+	".dword 0b, (1b-0b)\n"
+#else
+	".word 0b, (1b-0b)\n"
+#endif
+	".previous\n" 
+	: "=r" (val), "=r" (ret)
+	: "0" (val), "1" (ret), "r" (saddr), "r" (len), "r" (regs->isr)
+	: "r19", "r20" );
+
+	DPRINTF("val = 0x" RFMT "\n", val);
+
+	regs->gr[toreg] = val;
+
+	return ret;
+}
+
+static int emulate_store(struct pt_regs *regs, int len, int frreg)
+{
+	int ret = 0;
+#ifdef __LP64__
+	unsigned long val = regs->gr[frreg] << (64 - (len << 3));
+#else
+	unsigned long val = regs->gr[frreg] << (32 - (len << 3));
+#endif
+
+	if (regs->isr != regs->sr[7])
+	{
+		printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
+			regs->isr, regs->sr[7]);
+		return 1;
+	}
+
+	DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for %d bytes\n", frreg, 
+		regs->gr[frreg], regs->isr, regs->ior, len);
+
+
+	__asm__ __volatile__ (
+"       mfsp %%sr1, %%r20\n"		/* save sr1 */
+"       mtsp %5, %%sr1\n"
+#ifdef __LP64__
+"0:	extrd,u %2, 7, 8, %%r19\n"
+#else
+"0:	extrw,u %2, 7, 8, %%r19\n"
+#endif
+"1:	stb,ma %%r19, 1(%%sr1, %3)\n"
+"	addi -1, %4, %4\n"
+"	cmpib,>= 0, %4, 3f\n"
+	
+#ifdef __LP64__
+	"depd,z %2, 55, 56, %2\n"
+#else
+	"depw,z %2, 23, 24, %2\n"
+#endif
+
+"	b 0b\n"
+"	nop\n"
+
+"2:	ldi 11, %0\n"
+"3:     mtsp %%r20, %%sr1\n"
+"	.section __ex_table,\"a\"\n"
+#ifdef __LP64__
+	".dword 1b, (2b-1b)\n"
+#else
+	".word 1b, (2b-1b)\n"
+#endif
+	".previous\n" 
+	: "=r" (ret)
+	: "0" (ret), "r" (val), "r" (regs->ior), "r" (len), "r" (regs->isr)
+	: "r19", "r20" );
+
+	return ret;
+}
+
+
+void handle_unaligned(struct pt_regs *regs)
+{
+	unsigned long unaligned_count = 0;
+	unsigned long last_time = 0;
+	int ret = -1;
+	struct siginfo si;
+
+	/* if the unaligned access is inside the kernel:
+	 *   if the access is caused by a syscall, then we fault the calling
+	 *     user process
+	 *   otherwise we halt the kernel
+	 */
+	if (!user_mode(regs))
+	{
+		const struct exception_table_entry *fix;
+
+		/* see if the offending code have its own
+		 * exception handler 
+		 */ 
+
+		fix = search_exception_table(regs->iaoq[0]);
+		if (fix)
+		{
+			/* lower bits of fix->skip are flags
+			 * upper bits are the handler addr
+			 */
+			if (fix->skip & 1)
+				regs->gr[8] = -EFAULT;
+			if (fix->skip & 2)
+				regs->gr[9] = 0;
+
+			regs->iaoq[0] += ((fix->skip) & ~3);
+			regs->iaoq[1] = regs->iaoq[0] + 4;
+			regs->gr[0] &= ~PSW_B;
+
+			return;
+		}
+	}
+
+	/* log a message with pacing */
+	if (user_mode(regs))
+	{
+		if (unaligned_count > 5 && jiffies - last_time > 5*HZ)
+		{
+			unaligned_count = 0;
+			last_time = jiffies;
+		}
+		if (++unaligned_count < 5)
+		{
+			char buf[256];
+			sprintf(buf, "%s(%d): unaligned access to 0x" RFMT " at ip=0x" RFMT "\n",
+				current->comm, current->pid, regs->ior, regs->iaoq[0]);
+			printk(KERN_WARNING "%s", buf);
+#ifdef DEBUG_UNALIGNED
+			show_regs(regs);
+#endif		
+		}
+	}
+
+	/* TODO: make this cleaner... */
+	switch (regs->iir & OPCODE1_MASK)
+	{
+	case OPCODE_LDH_I:
+	case OPCODE_LDH_S:
+		ret = emulate_load(regs, 2, regs->iir & 0x1f);
+		break;
+
+	case OPCODE_LDW_I:
+	case OPCODE_LDWA_I:
+	case OPCODE_LDW_S:
+	case OPCODE_LDWA_S:
+		ret = emulate_load(regs, 4, regs->iir&0x1f);
+		break;
+
+	case OPCODE_LDD_I:
+	case OPCODE_LDDA_I:
+	case OPCODE_LDD_S:
+	case OPCODE_LDDA_S:
+		ret = emulate_load(regs, 8, regs->iir&0x1f);
+		break;
+
+	case OPCODE_STH:
+		ret = emulate_store(regs, 2, (regs->iir>>16)&0x1f);
+		break;
+
+	case OPCODE_STW:
+	case OPCODE_STWA:
+		ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+
+	case OPCODE_STD:
+	case OPCODE_STDA:
+		ret = emulate_store(regs, 8, (regs->iir>>16)&0x1f);
+		break;
+	}
+	switch (regs->iir & OPCODE2_MASK)
+	{
+	case OPCODE_LDD_L:
+	case OPCODE_FLDD_L:
+		ret = emulate_load(regs, 8, (regs->iir>>16)&0x1f);
+		break;
+
+	case OPCODE_STD_L:
+	case OPCODE_FSTD_L:
+		ret = emulate_store(regs, 8, (regs->iir>>16)&0x1f);
+		break;
+	}
+	switch (regs->iir & OPCODE3_MASK)
+	{
+	case OPCODE_LDW_M:
+	case OPCODE_FLDW_L:
+		ret = emulate_load(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+
+	case OPCODE_FSTW_L:
+	case OPCODE_STW_M:
+		ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+	}
+	switch (regs->iir & OPCODE4_MASK)
+	{
+	case OPCODE_LDH_L:
+		ret = emulate_load(regs, 2, (regs->iir>>16)&0x1f);
+		break;
+	case OPCODE_LDW_L:
+	case OPCODE_LDW_L2:
+		ret = emulate_load(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+	case OPCODE_STH_L:
+		ret = emulate_store(regs, 2, (regs->iir>>16)&0x1f);
+		break;
+	case OPCODE_STW_L:
+	case OPCODE_STW_L2:
+		ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+		break;
+	}
+
+	if (ret < 0)
+		printk(KERN_CRIT "Not-handled unaligned insn 0x%08lx\n", regs->iir);
+
+	DPRINTF("ret = %d\n", ret);
+
+	if (ret)
+	{
+		printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
+		die_if_kernel("Unaligned data reference", regs, 28);
+
+		/* couldn't handle it ... */
+		si.si_signo = SIGBUS;
+		si.si_errno = 0;
+		si.si_code = BUS_ADRALN;
+		si.si_addr = (void *)regs->ior;
+		force_sig_info(SIGBUS, &si, current);
+		
+		return;
+	}
+
+	/* else we handled it, advance the PC.... */
+	regs->iaoq[0] = regs->iaoq[1];
+	regs->iaoq[1] = regs->iaoq[0] + 4;
+}
+
+/*
+ * NB: check_unaligned() is only used for PCXS processors right
+ * now, so we only check for PA1.1 encodings at this point.
+ */
+
+int
+check_unaligned(struct pt_regs *regs)
+{
+	unsigned long align_mask;
+
+	/* Get alignment mask */
+
+	align_mask = 0UL;
+	switch (regs->iir & OPCODE1_MASK) {
+
+	case OPCODE_LDH_I:
+	case OPCODE_LDH_S:
+	case OPCODE_STH:
+		align_mask = 1UL;
+		break;
+
+	case OPCODE_LDW_I:
+	case OPCODE_LDWA_I:
+	case OPCODE_LDW_S:
+	case OPCODE_LDWA_S:
+	case OPCODE_STW:
+	case OPCODE_STWA:
+		align_mask = 3UL;
+		break;
+
+	default:
+		switch (regs->iir & OPCODE4_MASK) {
+		case OPCODE_LDH_L:
+		case OPCODE_STH_L:
+			align_mask = 1UL;
+			break;
+		case OPCODE_LDW_L:
+		case OPCODE_LDW_L2:
+		case OPCODE_STW_L:
+		case OPCODE_STW_L2:
+			align_mask = 3UL;
+			break;
+		}
+		break;
+	}
+
+	return (int)(regs->ior & align_mask);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/lib/Makefile linux-2.4.20-pre2/arch/parisc/lib/Makefile
--- linux-2.4.20-pre1/arch/parisc/lib/Makefile	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/lib/Makefile	Mon Aug 12 16:34:14 2002
@@ -4,10 +4,6 @@
 
 
 L_TARGET = lib.a
-L_OBJS	= lusercopy.o bitops.o checksum.o
-
-
-.S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+obj-y	:= lusercopy.o bitops.o checksum.o io.o memset.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/arch/parisc/lib/bitops.c linux-2.4.20-pre2/arch/parisc/lib/bitops.c
--- linux-2.4.20-pre1/arch/parisc/lib/bitops.c	Wed Dec  6 11:46:39 2000
+++ linux-2.4.20-pre2/arch/parisc/lib/bitops.c	Mon Aug 12 16:34:14 2002
@@ -1,7 +1,10 @@
-/* atomic.c: atomic operations which got too long to be inlined all over
- * the place.
+/*
+ * bitops.c: atomic operations which got too long to be inlined all over
+ *      the place.
  * 
- * Copyright 1999 Philipp Rumpf (prumpf@tux.org */
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ * Copyright 2000 Grant Grundler (grundler@cup.hp.com)
+ */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -17,44 +20,67 @@
 
 spinlock_t __atomic_lock = SPIN_LOCK_UNLOCKED;
 
-#ifndef __LP64__
-unsigned long __xchg(unsigned long x, unsigned long *ptr, int size)
+#ifdef __LP64__
+unsigned long __xchg64(unsigned long x, unsigned long *ptr)
 {
 	unsigned long temp, flags;
 
-	if (size != sizeof x) {
-		printk("__xchg called with bad pointer\n");
-	}
-	spin_lock_irqsave(&__atomic_lock, flags);
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
 	temp = *ptr;
 	*ptr = x;
-	spin_unlock_irqrestore(&__atomic_lock, flags);
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
 	return temp;
 }
-#else
-unsigned long __xchg(unsigned long x, unsigned long *ptr, int size)
+#endif
+
+unsigned long __xchg32(int x, int *ptr)
 {
-	unsigned long temp, flags;
-	unsigned int *ptr32;
+	unsigned long flags;
+	unsigned long temp;
+
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
+	(long) temp = (long) *ptr;	/* XXX - sign extension wanted? */
+	*ptr = x;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
+	return temp;
+}
+
+
+unsigned long __xchg8(char x, char *ptr)
+{
+	unsigned long flags;
+	unsigned long temp;
 
-	if (size == 8) {
-try_long:
-		spin_lock_irqsave(&__atomic_lock, flags);
-		temp = *ptr;
-		*ptr = x;
-		spin_unlock_irqrestore(&__atomic_lock, flags);
-		return temp;
-	}
-	if (size == 4) {
-		ptr32 = (unsigned int *)ptr;
-		spin_lock_irqsave(&__atomic_lock, flags);
-		temp = (unsigned long)*ptr32;
-		*ptr32 = (unsigned int)x;
-		spin_unlock_irqrestore(&__atomic_lock, flags);
-		return temp;
-	}
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
+	(long) temp = (long) *ptr;	/* XXX - sign extension wanted? */
+	*ptr = x;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
+	return temp;
+}
+
+
+#ifdef __LP64__
+unsigned long __cmpxchg_u64(volatile unsigned long *ptr, unsigned long old, unsigned long new)
+{
+	unsigned long flags;
+	unsigned long prev;
 
-	printk("__xchg called with bad pointer\n");
-	goto try_long;
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
+	if ((prev = *ptr) == old)
+		*ptr = new;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
+	return prev;
 }
 #endif
+
+unsigned long __cmpxchg_u32(volatile unsigned int *ptr, unsigned int old, unsigned int new)
+{
+	unsigned long flags;
+	unsigned int prev;
+
+	SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
+	if ((prev = *ptr) == old)
+		*ptr = new;
+	SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
+	return (unsigned long)prev;
+}
diff -urN linux-2.4.20-pre1/arch/parisc/lib/io.c linux-2.4.20-pre2/arch/parisc/lib/io.c
--- linux-2.4.20-pre1/arch/parisc/lib/io.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/lib/io.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,459 @@
+/*
+ * arch/parisc/lib/io.c
+ *
+ * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
+ * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
+ *
+ * IO accessing functions which shouldn't be inlined because they're too big
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+/* Copies a block of memory to a device in an efficient manner.
+ * Assumes the device can cope with 32-bit transfers.  If it can't,
+ * don't use this function.
+ */
+void memcpy_toio(unsigned long dest, const void *src, int count)
+{
+	if ((dest & 3) != ((unsigned long)src & 3))
+		goto bytecopy;
+	while (dest & 3) {
+		writeb(*(char *)src, dest++);
+		((char *)src)++;
+		count--;
+	}
+	while (count > 3) {
+		__raw_writel(*(u32 *)src, dest);
+		(unsigned long) src += 4;
+		dest += 4;
+		count -= 4;
+	}
+ bytecopy:
+	while (count--) {
+		writeb(*(char *)src, dest++);
+		((char *)src)++;
+	}
+}
+
+/*
+** Copies a block of memory from a device in an efficient manner.
+** Assumes the device can cope with 32-bit transfers.  If it can't,
+** don't use this function.
+**
+** CR16 counts on C3000 reading 256 bytes from Symbios 896 RAM:
+**	27341/64    = 427 cyc per int
+**	61311/128   = 478 cyc per short
+**	122637/256  = 479 cyc per byte
+** Ergo bus latencies dominant (not transfer size).
+**      Minimize total number of transfers at cost of CPU cycles.
+**	TODO: only look at src alignment and adjust the stores to dest.
+*/
+void memcpy_fromio(void *dest, unsigned long src, int count)
+{
+	/* first compare alignment of src/dst */ 
+	if ( (((unsigned long)dest ^ src) & 1) || (count < 2) )
+		goto bytecopy;
+
+	if ( (((unsigned long)dest ^ src) & 2) || (count < 4) )
+		goto shortcopy;
+
+	/* Then check for misaligned start address */
+	if (src & 1) {
+		*(u8 *)dest = readb(src);
+		((u8 *)src)++;
+		((u8 *)dest)++;
+		count--;
+		if (count < 2) goto bytecopy;
+	}
+
+	if (src & 2) {
+		*(u16 *)dest = __raw_readw(src);
+		((u16 *)src)++;
+		((u16 *)dest)++;
+		count-=2;
+	}
+
+	while (count > 3) {
+		*(u32 *)dest = __raw_readl(src);
+		dest += 4;
+		src += 4;
+		count -= 4;
+	}
+
+ shortcopy:
+	while (count > 1) {
+		*(u16 *)dest = __raw_readw(src);
+		((u16 *)src)++;
+		((u16 *)dest)++;
+		count-=2;
+	}
+
+ bytecopy:
+	while (count--) {
+		*(char *)dest = readb(src);
+		((char *)src)++;
+		((char *)dest)++;
+	}
+}
+
+/* Sets a block of memory on a device to a given value.
+ * Assumes the device can cope with 32-bit transfers.  If it can't,
+ * don't use this function.
+ */
+void memset_io(unsigned long dest, char fill, int count)
+{
+	u32 fill32 = (fill << 24) | (fill << 16) | (fill << 8) | fill;
+	while (dest & 3) {
+		writeb(fill, dest++);
+		count--;
+	}
+	while (count > 3) {
+		__raw_writel(fill32, dest);
+		dest += 4;
+		count -= 4;
+	}
+	while (count--) {
+		writeb(fill, dest++);
+	}
+}
+
+/*
+ * Read COUNT 8-bit bytes from port PORT into memory starting at
+ * SRC.
+ */
+void insb (unsigned long port, void *dst, unsigned long count)
+{
+	while (((unsigned long)dst) & 0x3) {
+		if (!count)
+			return;
+		count--;
+		*(unsigned char *) dst = inb(port);
+		((unsigned char *) dst)++;
+	}
+
+	while (count >= 4) {
+		unsigned int w;
+		count -= 4;
+		w = inb(port) << 24;
+		w |= inb(port) << 16;
+		w |= inb(port) << 8;
+		w |= inb(port);
+		*(unsigned int *) dst = w;
+		((unsigned int *) dst)++;
+	}
+
+	while (count) {
+		--count;
+		*(unsigned char *) dst = inb(port);
+		((unsigned char *) dst)++;
+	}
+}
+
+
+/*
+ * Read COUNT 16-bit words from port PORT into memory starting at
+ * SRC.  SRC must be at least short aligned.  This is used by the
+ * IDE driver to read disk sectors.  Performance is important, but
+ * the interfaces seems to be slow: just using the inlined version
+ * of the inw() breaks things.
+ */
+void insw (unsigned long port, void *dst, unsigned long count)
+{
+	unsigned int l = 0, l2;
+	
+	if (!count)
+		return;
+	
+	switch (((unsigned long) dst) & 0x3)
+	{
+	 case 0x00:			/* Buffer 32-bit aligned */
+		while (count>=2) {
+			
+			count -= 2;
+			l = cpu_to_le16(inw(port)) << 16;
+			l |= cpu_to_le16(inw(port));
+			*(unsigned int *) dst = l;
+			((unsigned int *) dst)++;
+		}
+		if (count) {
+			*(unsigned short *) dst = cpu_to_le16(inw(port));
+		}
+		break;
+	
+	 case 0x02:			/* Buffer 16-bit aligned */
+		*(unsigned short *) dst = cpu_to_le16(inw(port));
+		((unsigned short *) dst)++;
+		count--;
+		while (count>=2) {
+			
+			count -= 2;
+			l = cpu_to_le16(inw(port)) << 16;
+			l |= cpu_to_le16(inw(port));
+			*(unsigned int *) dst = l;
+			((unsigned int *) dst)++;
+		}
+		if (count) {
+			*(unsigned short *) dst = cpu_to_le16(inw(port));
+		}
+		break;
+		
+	 case 0x01:			/* Buffer 8-bit aligned */
+	 case 0x03:
+		/* I don't bother with 32bit transfers
+		 * in this case, 16bit will have to do -- DE */
+		--count;
+		
+		l = cpu_to_le16(inw(port));
+		*(unsigned char *) dst = l >> 8;
+		((unsigned char *) dst)++;
+		while (count--)
+		{
+			l2 = cpu_to_le16(inw(port));
+			*(unsigned short *) dst = (l & 0xff) << 8 | (l2 >> 8);
+			((unsigned short *) dst)++;
+			l = l2;
+		}
+		*(unsigned char *) dst = l & 0xff;
+		break;
+	}
+}
+
+
+
+/*
+ * Read COUNT 32-bit words from port PORT into memory starting at
+ * SRC. Now works with any alignment in SRC. Performance is important,
+ * but the interfaces seems to be slow: just using the inlined version
+ * of the inl() breaks things.
+ */
+void insl (unsigned long port, void *dst, unsigned long count)
+{
+	unsigned int l = 0, l2;
+	
+	if (!count)
+		return;
+	
+	switch (((unsigned long) dst) & 0x3)
+	{
+	 case 0x00:			/* Buffer 32-bit aligned */
+		while (count--)
+		{
+			*(unsigned int *) dst = cpu_to_le32(inl(port));
+			((unsigned int *) dst)++;
+		}
+		break;
+	
+	 case 0x02:			/* Buffer 16-bit aligned */
+		--count;
+		
+		l = cpu_to_le32(inl(port));
+		*(unsigned short *) dst = l >> 16;
+		((unsigned short *) dst)++;
+		
+		while (count--)
+		{
+			l2 = cpu_to_le32(inl(port));
+			*(unsigned int *) dst = (l & 0xffff) << 16 | (l2 >> 16);
+			((unsigned int *) dst)++;
+			l = l2;
+		}
+		*(unsigned short *) dst = l & 0xffff;
+		break;
+	 case 0x01:			/* Buffer 8-bit aligned */
+		--count;
+		
+		l = cpu_to_le32(inl(port));
+		*(unsigned char *) dst = l >> 24;
+		((unsigned char *) dst)++;
+		*(unsigned short *) dst = (l >> 8) & 0xffff;
+		((unsigned short *) dst)++;
+		while (count--)
+		{
+			l2 = cpu_to_le32(inl(port));
+			*(unsigned int *) dst = (l & 0xff) << 24 | (l2 >> 8);
+			((unsigned int *) dst)++;
+			l = l2;
+		}
+		*(unsigned char *) dst = l & 0xff;
+		break;
+	 case 0x03:			/* Buffer 8-bit aligned */
+		--count;
+		
+		l = cpu_to_le32(inl(port));
+		*(unsigned char *) dst = l >> 24;
+		((unsigned char *) dst)++;
+		while (count--)
+		{
+			l2 = cpu_to_le32(inl(port));
+			*(unsigned int *) dst = (l & 0xffffff) << 8 | l2 >> 24;
+			((unsigned int *) dst)++;
+			l = l2;
+		}
+		*(unsigned short *) dst = (l >> 8) & 0xffff;
+		((unsigned short *) dst)++;
+		*(unsigned char *) dst = l & 0xff;
+		break;
+	}
+}
+
+
+/*
+ * Like insb but in the opposite direction.
+ * Don't worry as much about doing aligned memory transfers:
+ * doing byte reads the "slow" way isn't nearly as slow as
+ * doing byte writes the slow way (no r-m-w cycle).
+ */
+void outsb(unsigned long port, const void * src, unsigned long count)
+{
+	while (count) {
+		count--;
+		outb(*(char *)src, port);
+		((char *) src)++;
+	}
+}
+
+/*
+ * Like insw but in the opposite direction.  This is used by the IDE
+ * driver to write disk sectors.  Performance is important, but the
+ * interfaces seems to be slow: just using the inlined version of the
+ * outw() breaks things.
+ */
+void outsw (unsigned long port, const void *src, unsigned long count)
+{
+	unsigned int l = 0, l2;
+	
+	if (!count)
+		return;
+	
+	switch (((unsigned long) src) & 0x3)
+	{
+	 case 0x00:			/* Buffer 32-bit aligned */
+		while (count>=2) {
+			count -= 2;
+			l = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outw(le16_to_cpu(l >> 16), port);
+			outw(le16_to_cpu(l & 0xffff), port);
+		}
+		if (count) {
+			outw(le16_to_cpu(*(unsigned short*)src), port);
+		}
+		break;
+	
+	 case 0x02:			/* Buffer 16-bit aligned */
+		
+		outw(le16_to_cpu(*(unsigned short*)src), port);
+		((unsigned short *) src)++;
+		count--;
+		
+		while (count>=2) {
+			count -= 2;
+			l = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outw(le16_to_cpu(l >> 16), port);
+			outw(le16_to_cpu(l & 0xffff), port);
+		}
+		if (count) {
+			outw(le16_to_cpu(*(unsigned short*)src), port);
+		}
+		break;
+		
+	 case 0x01:			/* Buffer 8-bit aligned */	
+		/* I don't bother with 32bit transfers
+		 * in this case, 16bit will have to do -- DE */
+		
+		l  = *(unsigned char *) src << 8;
+		((unsigned char *) src)++;
+		count--;
+		while (count)
+		{
+			count--;
+			l2 = *(unsigned short *) src;
+			((unsigned short *) src)++;
+			outw(le16_to_cpu(l | l2 >> 8), port);
+		        l = l2 << 8;
+		}
+		l2 = *(unsigned char *) src;
+		outw (le16_to_cpu(l | l2>>8), port);
+		break;
+	
+	}
+}
+
+
+/*
+ * Like insl but in the opposite direction.  This is used by the IDE
+ * driver to write disk sectors.  Works with any alignment in SRC.
+ *  Performance is important, but the interfaces seems to be slow:
+ * just using the inlined version of the outl() breaks things.
+ */
+void outsl (unsigned long port, const void *src, unsigned long count)
+{
+	unsigned int l = 0, l2;
+	
+	if (!count)
+		return;
+	
+	switch (((unsigned long) src) & 0x3)
+	{
+	 case 0x00:			/* Buffer 32-bit aligned */
+		while (count--)
+		{
+			outl(le32_to_cpu(*(unsigned int *) src), port);
+			((unsigned int *) src)++;
+		}
+		break;
+	
+	 case 0x02:			/* Buffer 16-bit aligned */
+		--count;
+		
+		l = *(unsigned short *) src;
+		((unsigned short *) src)++;
+		
+		while (count--)
+		{
+			l2 = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outl (le32_to_cpu(l << 16 | l2 >> 16), port);
+			l = l2;
+		}
+		l2 = *(unsigned short *) src;
+		outl (le32_to_cpu(l << 16 | l2), port);
+		break;
+	 case 0x01:			/* Buffer 8-bit aligned */
+		--count;
+		
+		l  = *(unsigned char *) src << 24;
+		((unsigned char *) src)++;
+		l |= *(unsigned short *) src << 8;
+		((unsigned short *) src)++;
+		while (count--)
+		{
+			l2 = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outl (le32_to_cpu(l | l2 >> 24), port);
+			l = l2 << 8;
+		}
+		l2 = *(unsigned char *) src;
+		      outl (le32_to_cpu(l | l2), port);
+		break;
+	 case 0x03:			/* Buffer 8-bit aligned */
+		--count;
+		
+		l  = *(unsigned char *) src << 24;
+		((unsigned char *) src)++;
+		while (count--)
+		{
+			l2 = *(unsigned int *) src;
+			((unsigned int *) src)++;
+			outl (le32_to_cpu(l | l2 >> 8), port);
+			l = l2 << 24;
+		}
+		l2  = *(unsigned short *) src << 16;
+		((unsigned short *) src)++;
+		l2 |= *(unsigned char *) src;
+		outl (le32_to_cpu(l | l2), port);
+		break;
+	}
+}
diff -urN linux-2.4.20-pre1/arch/parisc/lib/lusercopy.S linux-2.4.20-pre2/arch/parisc/lib/lusercopy.S
--- linux-2.4.20-pre1/arch/parisc/lib/lusercopy.S	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/lib/lusercopy.S	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
-/*------------------------------------------------------------------------------
- * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
  *
  * Assembly Language User Access Routines
  *  Copyright (C) 2000 Hewlett-Packard (John Marvin)
@@ -30,7 +30,6 @@
  */
 
 
-	.level		1.1
 	.text
 	
 #include <asm/assembly.h>
@@ -42,11 +41,8 @@
 	 * on the flag stored in the task structure.
 	 */
 
-	/* FIXME! depi below has hardcoded idea of kernel stack size */
-
 	.macro  get_sr
-	copy        %r30,%r1        ;! Get task structure
-	depi        0,31,14,%r1     ;! into r1
+	mfctl       %cr30,%r1
 	ldw         TASK_SEGMENT(%r1),%r22
 	mfsp        %sr3,%r1
 	or,<>       %r22,%r0,%r0
@@ -82,7 +78,11 @@
 	ldo         1(%r24),%r24
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(2b-1b)
+#else
 	.word       1b,(2b-1b)
+#endif
 	.previous
 
 	.procend
@@ -123,7 +123,11 @@
 	nop
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(2b-1b)
+#else
 	.word       1b,(2b-1b)
+#endif
 	.previous
 
 	.procend
@@ -133,7 +137,7 @@
 	 *
 	 * Returns -EFAULT if exception before terminator,
 	 *         N if the entire buffer filled,
-	 *         otherwise strlen + 1 (i.e. includes zero byte)
+	 *         otherwise strlen (i.e. excludes zero byte)
 	 */
 
 	.export lstrncpy_from_user,code
@@ -142,7 +146,7 @@
 	.callinfo NO_CALLS
 	.entry
 	comib,=     0,%r24,$lsfu_done
-	copy        %r26,%r23
+	copy        %r24,%r23
 	get_sr
 1:      ldbs,ma     1(%sr1,%r25),%r1
 $lsfu_loop:
@@ -151,7 +155,7 @@
 	addib,<>,n  -1,%r24,$lsfu_loop
 2:      ldbs,ma     1(%sr1,%r25),%r1
 $lsfu_done:
-	sub         %r26,%r23,%r28
+	sub         %r23,%r24,%r28
 $lsfu_exit:
 	bv          %r0(%r2)
 	nop
@@ -161,8 +165,13 @@
 	ldi         -EFAULT,%r28
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(3b-1b)
+	.dword      2b,(3b-2b)
+#else
 	.word       1b,(3b-1b)
-	.word       2b,(2b-1b)
+	.word       2b,(3b-2b)
+#endif
 	.previous
 
 	.procend
@@ -194,7 +203,11 @@
 	ldo        1(%r25),%r25
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(2b-1b)
+#else
 	.word       1b,(2b-1b)
+#endif
 	.previous
 
 	.procend
@@ -233,8 +246,13 @@
 	copy        %r24,%r26    /* reset r26 so 0 is returned on fault */
 
 	.section __ex_table,"a"
+#ifdef __LP64__
+	.dword      1b,(3b-1b)
+	.dword      2b,(3b-2b)
+#else
 	.word       1b,(3b-1b)
-	.word       2b,(2b-1b)
+	.word       2b,(3b-2b)
+#endif
 	.previous
 
 	.procend
diff -urN linux-2.4.20-pre1/arch/parisc/lib/memset.c linux-2.4.20-pre2/arch/parisc/lib/memset.c
--- linux-2.4.20-pre1/arch/parisc/lib/memset.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/lib/memset.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,91 @@
+/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Slight modifications for pa-risc linux - Paul Bame <bame@debian.org> */
+
+#include <linux/types.h>
+#include <asm/string.h>
+
+#define OPSIZ (BITS_PER_LONG/8)
+typedef unsigned long op_t;
+
+void *
+memset (void *dstpp, int sc, size_t len)
+{
+  unsigned int c = sc;
+  long int dstp = (long int) dstpp;
+
+  if (len >= 8)
+    {
+      size_t xlen;
+      op_t cccc;
+
+      cccc = (unsigned char) c;
+      cccc |= cccc << 8;
+      cccc |= cccc << 16;
+      if (OPSIZ > 4)
+	/* Do the shift in two steps to avoid warning if long has 32 bits.  */
+	cccc |= (cccc << 16) << 16;
+
+      /* There are at least some bytes to set.
+	 No need to test for LEN == 0 in this alignment loop.  */
+      while (dstp % OPSIZ != 0)
+	{
+	  ((unsigned char *) dstp)[0] = c;
+	  dstp += 1;
+	  len -= 1;
+	}
+
+      /* Write 8 `op_t' per iteration until less than 8 `op_t' remain.  */
+      xlen = len / (OPSIZ * 8);
+      while (xlen > 0)
+	{
+	  ((op_t *) dstp)[0] = cccc;
+	  ((op_t *) dstp)[1] = cccc;
+	  ((op_t *) dstp)[2] = cccc;
+	  ((op_t *) dstp)[3] = cccc;
+	  ((op_t *) dstp)[4] = cccc;
+	  ((op_t *) dstp)[5] = cccc;
+	  ((op_t *) dstp)[6] = cccc;
+	  ((op_t *) dstp)[7] = cccc;
+	  dstp += 8 * OPSIZ;
+	  xlen -= 1;
+	}
+      len %= OPSIZ * 8;
+
+      /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain.  */
+      xlen = len / OPSIZ;
+      while (xlen > 0)
+	{
+	  ((op_t *) dstp)[0] = cccc;
+	  dstp += OPSIZ;
+	  xlen -= 1;
+	}
+      len %= OPSIZ;
+    }
+
+  /* Write the last few bytes.  */
+  while (len > 0)
+    {
+      ((unsigned char *) dstp)[0] = c;
+      dstp += 1;
+      len -= 1;
+    }
+
+  return dstpp;
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/Makefile linux-2.4.20-pre2/arch/parisc/math-emu/Makefile
--- linux-2.4.20-pre1/arch/parisc/math-emu/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/Makefile	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,22 @@
+#
+# Makefile for the linux/parisc floating point code
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := math.o
+obj-y	 := frnd.o driver.o decode_exc.o fpudispatch.o denormal.o \
+		dfmpy.o sfmpy.o sfsqrt.o dfsqrt.o dfadd.o fmpyfadd.o \
+		sfadd.o dfsub.o sfsub.o fcnvfxt.o fcnvff.o fcnvxf.o \
+		fcnvfx.o fcnvuf.o fcnvfu.o fcnvfut.o dfdiv.o sfdiv.o \
+		dfrem.o sfrem.o dfcmp.o sfcmp.o
+
+# Math emulation code beyond the FRND is required for 712/80i and
+# other very old or stripped-down PA-RISC CPUs -- not currently supported
+
+obj-$CONFIG_MATH_EMULATION	+= unimplemented-math-emulation.o
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/README linux-2.4.20-pre2/arch/parisc/math-emu/README
--- linux-2.4.20-pre1/arch/parisc/math-emu/README	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/README	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,11 @@
+All files except driver.c are snapshots from the HP-UX kernel.  They've
+been modified as little as possible.  Even though they don't fit the
+Linux coding style, please leave them in their funny format just in case
+someone in the future, with access to HP-UX source code, is generous
+enough to update our copies with later changes from HP-UX -- it'll
+make their 'diff' job easier if our code is relatively unmodified.
+
+Required Disclaimer: Hewlett-Packard makes no implied or expressed
+warranties about this code nor any promises to maintain or test it
+in any way.  This copy of this snapshot is no longer the property
+of Hewlett-Packard.
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/cnv_float.h linux-2.4.20-pre2/arch/parisc/math-emu/cnv_float.h
--- linux-2.4.20-pre1/arch/parisc/math-emu/cnv_float.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/cnv_float.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,377 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+/*
+ * Some more constants
+ */
+#define SGL_FX_MAX_EXP 30
+#define DBL_FX_MAX_EXP 62
+#define QUAD_FX_MAX_EXP 126
+
+#define Dintp1(object) (object)
+#define Dintp2(object) (object)
+
+#define Duintp1(object) (object)
+#define Duintp2(object) (object)
+
+#define Qintp0(object) (object)
+#define Qintp1(object) (object)
+#define Qintp2(object) (object)
+#define Qintp3(object) (object)
+
+
+/*
+ * These macros will be used specifically by the convert instructions.
+ *
+ *
+ * Single format macros
+ */
+
+#define Sgl_to_dbl_exponent(src_exponent,dest)			\
+    Deposit_dexponent(dest,src_exponent+(DBL_BIAS-SGL_BIAS))
+
+#define Sgl_to_dbl_mantissa(src_mantissa,destA,destB)	\
+    Deposit_dmantissap1(destA,src_mantissa>>3);		\
+    Dmantissap2(destB) = src_mantissa << 29
+
+#define Sgl_isinexact_to_fix(sgl_value,exponent)	\
+    ((exponent < (SGL_P - 1)) ?				\
+     (Sall(sgl_value) << (SGL_EXP_LENGTH + 1 + exponent)) : FALSE)
+
+#define Int_isinexact_to_sgl(int_value)	(int_value << 33 - SGL_EXP_LENGTH)
+
+#define Sgl_roundnearest_from_int(int_value,sgl_value)			\
+    if (int_value & 1<<(SGL_EXP_LENGTH - 2))   /* round bit */		\
+    	if ((int_value << 34 - SGL_EXP_LENGTH) || Slow(sgl_value))	\
+		Sall(sgl_value)++
+
+#define Dint_isinexact_to_sgl(dint_valueA,dint_valueB)		\
+    ((Dintp1(dint_valueA) << 33 - SGL_EXP_LENGTH) || Dintp2(dint_valueB))
+
+#define Sgl_roundnearest_from_dint(dint_valueA,dint_valueB,sgl_value)	\
+    if (Dintp1(dint_valueA) & 1<<(SGL_EXP_LENGTH - 2)) 			\
+    	if ((Dintp1(dint_valueA) << 34 - SGL_EXP_LENGTH) ||		\
+    	Dintp2(dint_valueB) || Slow(sgl_value)) Sall(sgl_value)++
+
+#define Dint_isinexact_to_dbl(dint_value) 	\
+    (Dintp2(dint_value) << 33 - DBL_EXP_LENGTH)
+
+#define Dbl_roundnearest_from_dint(dint_opndB,dbl_opndA,dbl_opndB) 	\
+    if (Dintp2(dint_opndB) & 1<<(DBL_EXP_LENGTH - 2))			\
+       if ((Dintp2(dint_opndB) << 34 - DBL_EXP_LENGTH) || Dlowp2(dbl_opndB))  \
+          if ((++Dallp2(dbl_opndB))==0) Dallp1(dbl_opndA)++
+
+#define Sgl_isone_roundbit(sgl_value,exponent)			\
+    ((Sall(sgl_value) << (SGL_EXP_LENGTH + 1 + exponent)) >> 31)
+
+#define Sgl_isone_stickybit(sgl_value,exponent)		\
+    (exponent < (SGL_P - 2) ?				\
+     Sall(sgl_value) << (SGL_EXP_LENGTH + 2 + exponent) : FALSE)
+
+
+/* 
+ * Double format macros
+ */
+
+#define Dbl_to_sgl_exponent(src_exponent,dest)			\
+    dest = src_exponent + (SGL_BIAS - DBL_BIAS)
+
+#define Dbl_to_sgl_mantissa(srcA,srcB,dest,inexact,guard,sticky,odd)	\
+    Shiftdouble(Dmantissap1(srcA),Dmantissap2(srcB),29,dest); 	\
+    guard = Dbit3p2(srcB);					\
+    sticky = Dallp2(srcB)<<4;					\
+    inexact = guard | sticky;					\
+    odd = Dbit2p2(srcB)
+
+#define Dbl_to_sgl_denormalized(srcA,srcB,exp,dest,inexact,guard,sticky,odd,tiny) \
+    Deposit_dexponent(srcA,1);						\
+    tiny = TRUE;							\
+    if (exp >= -2) {							\
+	if (exp == 0) {							\
+	    inexact = Dallp2(srcB) << 3;				\
+	    guard = inexact >> 31;					\
+	    sticky = inexact << 1;					\
+	    Shiftdouble(Dmantissap1(srcA),Dmantissap2(srcB),29,dest);	\
+	    odd = dest << 31;						\
+	    if (inexact) {						\
+		switch(Rounding_mode()) {				\
+		    case ROUNDPLUS:					\
+			if (Dbl_iszero_sign(srcA)) {			\
+			    dest++;					\
+			    if (Sgl_isone_hidden(dest))	\
+				tiny = FALSE;				\
+			    dest--;					\
+			}						\
+			break;						\
+		    case ROUNDMINUS:					\
+			if (Dbl_isone_sign(srcA)) {			\
+			    dest++;					\
+			    if (Sgl_isone_hidden(dest))	\
+				tiny = FALSE;				\
+			    dest--;					\
+			}						\
+			break;						\
+		    case ROUNDNEAREST:					\
+			if (guard && (sticky || odd)) {			\
+			    dest++;					\
+			    if (Sgl_isone_hidden(dest))	\
+				tiny = FALSE;				\
+			    dest--;					\
+			}						\
+			break;						\
+		}							\
+	    }								\
+		/* shift right by one to get correct result */		\
+		guard = odd;						\
+		sticky = inexact;					\
+		inexact |= guard;					\
+		dest >>= 1;						\
+    		Deposit_dsign(srcA,0);					\
+    	        Shiftdouble(Dallp1(srcA),Dallp2(srcB),30,dest);		\
+	        odd = dest << 31;					\
+	}								\
+	else {								\
+    	    inexact = Dallp2(srcB) << (2 + exp);			\
+    	    guard = inexact >> 31;					\
+    	    sticky = inexact << 1; 					\
+    	    Deposit_dsign(srcA,0);					\
+    	    if (exp == -2) dest = Dallp1(srcA);				\
+    	    else Variable_shift_double(Dallp1(srcA),Dallp2(srcB),30-exp,dest); \
+    	    odd = dest << 31;						\
+	}								\
+    }									\
+    else {								\
+    	Deposit_dsign(srcA,0);						\
+    	if (exp > (1 - SGL_P)) {					\
+    	    dest = Dallp1(srcA) >> (- 2 - exp);				\
+    	    inexact = Dallp1(srcA) << (34 + exp);			\
+    	    guard = inexact >> 31;					\
+    	    sticky = (inexact << 1) | Dallp2(srcB);			\
+    	    inexact |= Dallp2(srcB); 					\
+    	    odd = dest << 31;						\
+    	}								\
+    	else {								\
+    	    dest = 0;							\
+    	    inexact = Dallp1(srcA) | Dallp2(srcB);			\
+    	    if (exp == (1 - SGL_P)) {					\
+    	    	guard = Dhidden(srcA);					\
+    	    	sticky = Dmantissap1(srcA) | Dallp2(srcB); 		\
+    	    }								\
+    	    else {							\
+    	    	guard = 0;						\
+    	    	sticky = inexact;					\
+    	    }								\
+    	    odd = 0;							\
+    	}								\
+    }									\
+    exp = 0
+
+#define Dbl_isinexact_to_fix(dbl_valueA,dbl_valueB,exponent)		\
+    (exponent < (DBL_P-33) ? 						\
+     Dallp2(dbl_valueB) || Dallp1(dbl_valueA) << (DBL_EXP_LENGTH+1+exponent) : \
+     (exponent < (DBL_P-1) ? Dallp2(dbl_valueB) << (exponent + (33-DBL_P)) :   \
+      FALSE))
+
+#define Dbl_isoverflow_to_int(exponent,dbl_valueA,dbl_valueB)		\
+    ((exponent > SGL_FX_MAX_EXP + 1) || Dsign(dbl_valueA)==0 ||		\
+     Dmantissap1(dbl_valueA)!=0 || (Dallp2(dbl_valueB)>>21)!=0 ) 
+
+#define Dbl_isone_roundbit(dbl_valueA,dbl_valueB,exponent)              \
+    ((exponent < (DBL_P - 33) ?						\
+      Dallp1(dbl_valueA) >> ((30 - DBL_EXP_LENGTH) - exponent) :	\
+      Dallp2(dbl_valueB) >> ((DBL_P - 2) - exponent)) & 1)
+
+#define Dbl_isone_stickybit(dbl_valueA,dbl_valueB,exponent)		\
+    (exponent < (DBL_P-34) ? 						\
+     (Dallp2(dbl_valueB) || Dallp1(dbl_valueA)<<(DBL_EXP_LENGTH+2+exponent)) : \
+     (exponent<(DBL_P-2) ? (Dallp2(dbl_valueB) << (exponent + (34-DBL_P))) : \
+      FALSE))
+
+
+/* Int macros */
+
+#define Int_from_sgl_mantissa(sgl_value,exponent)	\
+    Sall(sgl_value) = 				\
+    	(unsigned)(Sall(sgl_value) << SGL_EXP_LENGTH)>>(31 - exponent)
+
+#define Int_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent)	\
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),22,Dallp1(dbl_valueA)); \
+    if (exponent < 31) Dallp1(dbl_valueA) >>= 30 - exponent;	\
+    else Dallp1(dbl_valueA) <<= 1
+
+#define Int_negate(int_value) int_value = -int_value
+
+
+/* Dint macros */
+
+#define Dint_from_sgl_mantissa(sgl_value,exponent,dresultA,dresultB)	\
+    {Sall(sgl_value) <<= SGL_EXP_LENGTH;  /*  left-justify  */		\
+    if (exponent <= 31) {						\
+    	Dintp1(dresultA) = 0;						\
+    	Dintp2(dresultB) = (unsigned)Sall(sgl_value) >> (31 - exponent); \
+    }									\
+    else {								\
+    	Dintp1(dresultA) = Sall(sgl_value) >> (63 - exponent);		\
+    	Dintp2(dresultB) = Sall(sgl_value) << (exponent - 31);		\
+    }}
+
+
+#define Dint_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent,destA,destB) \
+    {if (exponent < 32) {						\
+    	Dintp1(destA) = 0;						\
+    	if (exponent <= 20)						\
+    	    Dintp2(destB) = Dallp1(dbl_valueA) >> 20-exponent;		\
+    	else Variable_shift_double(Dallp1(dbl_valueA),Dallp2(dbl_valueB), \
+	     52-exponent,Dintp2(destB));					\
+    }									\
+    else {								\
+    	if (exponent <= 52) {						\
+    	    Dintp1(destA) = Dallp1(dbl_valueA) >> 52-exponent;		\
+	    if (exponent == 52) Dintp2(destB) = Dallp2(dbl_valueB);	\
+	    else Variable_shift_double(Dallp1(dbl_valueA),Dallp2(dbl_valueB), \
+	    52-exponent,Dintp2(destB));					\
+        }								\
+    	else {								\
+    	    Variable_shift_double(Dallp1(dbl_valueA),Dallp2(dbl_valueB), \
+	    84-exponent,Dintp1(destA));					\
+    	    Dintp2(destB) = Dallp2(dbl_valueB) << exponent-52;		\
+    	}								\
+    }}
+
+#define Dint_setzero(dresultA,dresultB) 	\
+    Dintp1(dresultA) = 0; 	\
+    Dintp2(dresultB) = 0
+
+#define Dint_setone_sign(dresultA,dresultB)		\
+    Dintp1(dresultA) = ~Dintp1(dresultA);		\
+    if ((Dintp2(dresultB) = -Dintp2(dresultB)) == 0) Dintp1(dresultA)++
+
+#define Dint_set_minint(dresultA,dresultB)		\
+    Dintp1(dresultA) = (unsigned int)1<<31;		\
+    Dintp2(dresultB) = 0
+
+#define Dint_isone_lowp2(dresultB)  (Dintp2(dresultB) & 01)
+
+#define Dint_increment(dresultA,dresultB) 		\
+    if ((++Dintp2(dresultB))==0) Dintp1(dresultA)++
+
+#define Dint_decrement(dresultA,dresultB) 		\
+    if ((Dintp2(dresultB)--)==0) Dintp1(dresultA)--
+
+#define Dint_negate(dresultA,dresultB)			\
+    Dintp1(dresultA) = ~Dintp1(dresultA);		\
+    if ((Dintp2(dresultB) = -Dintp2(dresultB))==0) Dintp1(dresultA)++
+
+#define Dint_copyfromptr(src,destA,destB) \
+     Dintp1(destA) = src->wd0;		\
+     Dintp2(destB) = src->wd1
+#define Dint_copytoptr(srcA,srcB,dest)	\
+    dest->wd0 = Dintp1(srcA);		\
+    dest->wd1 = Dintp2(srcB)
+
+
+/* other macros  */
+
+#define Find_ms_one_bit(value, position)	\
+    {						\
+	int var;				\
+	for (var=8; var >=1; var >>= 1) {	\
+	    if (value >> 32 - position)		\
+		position -= var;		\
+		else position += var;		\
+	}					\
+	if ((value >> 32 - position) == 0)	\
+	    position--;				\
+	else position -= 2;			\
+    }
+
+
+/*
+ * Unsigned int macros
+ */
+#define Duint_copyfromptr(src,destA,destB) \
+    Dint_copyfromptr(src,destA,destB)
+#define Duint_copytoptr(srcA,srcB,dest)	\
+    Dint_copytoptr(srcA,srcB,dest)
+
+#define Suint_isinexact_to_sgl(int_value) \
+    (int_value << 32 - SGL_EXP_LENGTH)
+
+#define Sgl_roundnearest_from_suint(suint_value,sgl_value)		\
+    if (suint_value & 1<<(SGL_EXP_LENGTH - 1))   /* round bit */	\
+    	if ((suint_value << 33 - SGL_EXP_LENGTH) || Slow(sgl_value))	\
+		Sall(sgl_value)++
+
+#define Duint_isinexact_to_sgl(duint_valueA,duint_valueB)	\
+    ((Duintp1(duint_valueA) << 32 - SGL_EXP_LENGTH) || Duintp2(duint_valueB))
+
+#define Sgl_roundnearest_from_duint(duint_valueA,duint_valueB,sgl_value) \
+    if (Duintp1(duint_valueA) & 1<<(SGL_EXP_LENGTH - 1))		\
+    	if ((Duintp1(duint_valueA) << 33 - SGL_EXP_LENGTH) ||		\
+    	Duintp2(duint_valueB) || Slow(sgl_value)) Sall(sgl_value)++
+
+#define Duint_isinexact_to_dbl(duint_value) 	\
+    (Duintp2(duint_value) << 32 - DBL_EXP_LENGTH)
+
+#define Dbl_roundnearest_from_duint(duint_opndB,dbl_opndA,dbl_opndB) 	\
+    if (Duintp2(duint_opndB) & 1<<(DBL_EXP_LENGTH - 1))			\
+       if ((Duintp2(duint_opndB) << 33 - DBL_EXP_LENGTH) || Dlowp2(dbl_opndB)) \
+          if ((++Dallp2(dbl_opndB))==0) Dallp1(dbl_opndA)++
+
+#define Suint_from_sgl_mantissa(src,exponent,result)	\
+    Sall(result) = (unsigned)(Sall(src) << SGL_EXP_LENGTH)>>(31 - exponent)
+
+#define Sgl_isinexact_to_unsigned(sgl_value,exponent)	\
+    Sgl_isinexact_to_fix(sgl_value,exponent)
+
+#define Duint_from_sgl_mantissa(sgl_value,exponent,dresultA,dresultB)	\
+  {Sall(sgl_value) <<= SGL_EXP_LENGTH;  /*  left-justify  */		\
+    if (exponent <= 31) {						\
+    	Dintp1(dresultA) = 0;						\
+    	Dintp2(dresultB) = (unsigned)Sall(sgl_value) >> (31 - exponent); \
+    }									\
+    else {								\
+    	Dintp1(dresultA) = Sall(sgl_value) >> (63 - exponent);		\
+    	Dintp2(dresultB) = Sall(sgl_value) << (exponent - 31);		\
+    }									\
+    Sall(sgl_value) >>= SGL_EXP_LENGTH;  /* return to original */	\
+  }
+
+#define Duint_setzero(dresultA,dresultB) 	\
+    Dint_setzero(dresultA,dresultB)
+
+#define Duint_increment(dresultA,dresultB) Dint_increment(dresultA,dresultB) 
+
+#define Duint_isone_lowp2(dresultB)  Dint_isone_lowp2(dresultB)
+
+#define Suint_from_dbl_mantissa(srcA,srcB,exponent,dest) \
+    Shiftdouble(Dallp1(srcA),Dallp2(srcB),21,dest); \
+    dest = (unsigned)dest >> 31 - exponent
+
+#define Dbl_isinexact_to_unsigned(dbl_valueA,dbl_valueB,exponent) \
+    Dbl_isinexact_to_fix(dbl_valueA,dbl_valueB,exponent)
+
+#define Duint_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent,destA,destB) \
+    Dint_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent,destA,destB) 
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/dbl_float.h linux-2.4.20-pre2/arch/parisc/math-emu/dbl_float.h
--- linux-2.4.20-pre1/arch/parisc/math-emu/dbl_float.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/dbl_float.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,847 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+/* 32-bit word grabing functions */
+#define Dbl_firstword(value) Dallp1(value)
+#define Dbl_secondword(value) Dallp2(value)
+#define Dbl_thirdword(value) dummy_location
+#define Dbl_fourthword(value) dummy_location
+
+#define Dbl_sign(object) Dsign(object)
+#define Dbl_exponent(object) Dexponent(object)
+#define Dbl_signexponent(object) Dsignexponent(object)
+#define Dbl_mantissap1(object) Dmantissap1(object)
+#define Dbl_mantissap2(object) Dmantissap2(object)
+#define Dbl_exponentmantissap1(object) Dexponentmantissap1(object)
+#define Dbl_allp1(object) Dallp1(object)
+#define Dbl_allp2(object) Dallp2(object)
+
+/* dbl_and_signs ands the sign bits of each argument and puts the result
+ * into the first argument. dbl_or_signs ors those same sign bits */
+#define Dbl_and_signs( src1dst, src2)		\
+    Dallp1(src1dst) = (Dallp1(src2)|~((unsigned int)1<<31)) & Dallp1(src1dst)
+#define Dbl_or_signs( src1dst, src2)		\
+    Dallp1(src1dst) = (Dallp1(src2)&((unsigned int)1<<31)) | Dallp1(src1dst)
+
+/* The hidden bit is always the low bit of the exponent */
+#define Dbl_clear_exponent_set_hidden(srcdst) Deposit_dexponent(srcdst,1)
+#define Dbl_clear_signexponent_set_hidden(srcdst) \
+    Deposit_dsignexponent(srcdst,1)
+#define Dbl_clear_sign(srcdst) Dallp1(srcdst) &= ~((unsigned int)1<<31)
+#define Dbl_clear_signexponent(srcdst) \
+    Dallp1(srcdst) &= Dmantissap1((unsigned int)-1)
+
+/* Exponent field for doubles has already been cleared and may be
+ * included in the shift.  Here we need to generate two double width
+ * variable shifts.  The insignificant bits can be ignored.
+ *      MTSAR f(varamount)
+ *      VSHD	srcdst.high,srcdst.low => srcdst.low
+ *	VSHD	0,srcdst.high => srcdst.high 
+ * This is very difficult to model with C expressions since the shift amount
+ * could exceed 32.  */
+/* varamount must be less than 64 */
+#define Dbl_rightshift(srcdstA, srcdstB, varamount)			\
+    {if((varamount) >= 32) {						\
+        Dallp2(srcdstB) = Dallp1(srcdstA) >> (varamount-32);		\
+        Dallp1(srcdstA)=0;						\
+    }									\
+    else if(varamount > 0) {						\
+	Variable_shift_double(Dallp1(srcdstA), Dallp2(srcdstB), 	\
+	  (varamount), Dallp2(srcdstB));				\
+	Dallp1(srcdstA) >>= varamount;					\
+    } }
+/* varamount must be less than 64 */
+#define Dbl_rightshift_exponentmantissa(srcdstA, srcdstB, varamount)	\
+    {if((varamount) >= 32) {						\
+        Dallp2(srcdstB) = Dexponentmantissap1(srcdstA) >> (varamount-32); \
+	Dallp1(srcdstA) &= ((unsigned int)1<<31);  /* clear expmant field */ \
+    }									\
+    else if(varamount > 0) {						\
+	Variable_shift_double(Dexponentmantissap1(srcdstA), Dallp2(srcdstB), \
+	(varamount), Dallp2(srcdstB));					\
+	Deposit_dexponentmantissap1(srcdstA,				\
+	    (Dexponentmantissap1(srcdstA)>>varamount));			\
+    } }
+/* varamount must be less than 64 */
+#define Dbl_leftshift(srcdstA, srcdstB, varamount)			\
+    {if((varamount) >= 32) {						\
+	Dallp1(srcdstA) = Dallp2(srcdstB) << (varamount-32);		\
+	Dallp2(srcdstB)=0;						\
+    }									\
+    else {								\
+	if ((varamount) > 0) {						\
+	    Dallp1(srcdstA) = (Dallp1(srcdstA) << (varamount)) |	\
+		(Dallp2(srcdstB) >> (32-(varamount)));			\
+	    Dallp2(srcdstB) <<= varamount;				\
+	}								\
+    } }
+#define Dbl_leftshiftby1_withextent(lefta,leftb,right,resulta,resultb)	\
+    Shiftdouble(Dallp1(lefta), Dallp2(leftb), 31, Dallp1(resulta));	\
+    Shiftdouble(Dallp2(leftb), Extall(right), 31, Dallp2(resultb)) 
+    
+#define Dbl_rightshiftby1_withextent(leftb,right,dst)		\
+    Extall(dst) = (Dallp2(leftb) << 31) | ((unsigned int)Extall(right) >> 1) | \
+		  Extlow(right)
+
+#define Dbl_arithrightshiftby1(srcdstA,srcdstB)			\
+    Shiftdouble(Dallp1(srcdstA),Dallp2(srcdstB),1,Dallp2(srcdstB));\
+    Dallp1(srcdstA) = (int)Dallp1(srcdstA) >> 1
+   
+/* Sign extend the sign bit with an integer destination */
+#define Dbl_signextendedsign(value)  Dsignedsign(value)
+
+#define Dbl_isone_hidden(dbl_value) (Is_dhidden(dbl_value)!=0)
+/* Singles and doubles may include the sign and exponent fields.  The
+ * hidden bit and the hidden overflow must be included. */
+#define Dbl_increment(dbl_valueA,dbl_valueB) \
+    if( (Dallp2(dbl_valueB) += 1) == 0 )  Dallp1(dbl_valueA) += 1
+#define Dbl_increment_mantissa(dbl_valueA,dbl_valueB) \
+    if( (Dmantissap2(dbl_valueB) += 1) == 0 )  \
+    Deposit_dmantissap1(dbl_valueA,dbl_valueA+1)
+#define Dbl_decrement(dbl_valueA,dbl_valueB) \
+    if( Dallp2(dbl_valueB) == 0 )  Dallp1(dbl_valueA) -= 1; \
+    Dallp2(dbl_valueB) -= 1
+
+#define Dbl_isone_sign(dbl_value) (Is_dsign(dbl_value)!=0)
+#define Dbl_isone_hiddenoverflow(dbl_value) (Is_dhiddenoverflow(dbl_value)!=0)
+#define Dbl_isone_lowmantissap1(dbl_valueA) (Is_dlowp1(dbl_valueA)!=0)
+#define Dbl_isone_lowmantissap2(dbl_valueB) (Is_dlowp2(dbl_valueB)!=0)
+#define Dbl_isone_signaling(dbl_value) (Is_dsignaling(dbl_value)!=0)
+#define Dbl_is_signalingnan(dbl_value) (Dsignalingnan(dbl_value)==0xfff)
+#define Dbl_isnotzero(dbl_valueA,dbl_valueB) \
+    (Dallp1(dbl_valueA) || Dallp2(dbl_valueB))
+#define Dbl_isnotzero_hiddenhigh7mantissa(dbl_value) \
+    (Dhiddenhigh7mantissa(dbl_value)!=0)
+#define Dbl_isnotzero_exponent(dbl_value) (Dexponent(dbl_value)!=0)
+#define Dbl_isnotzero_mantissa(dbl_valueA,dbl_valueB) \
+    (Dmantissap1(dbl_valueA) || Dmantissap2(dbl_valueB))
+#define Dbl_isnotzero_mantissap1(dbl_valueA) (Dmantissap1(dbl_valueA)!=0)
+#define Dbl_isnotzero_mantissap2(dbl_valueB) (Dmantissap2(dbl_valueB)!=0)
+#define Dbl_isnotzero_exponentmantissa(dbl_valueA,dbl_valueB) \
+    (Dexponentmantissap1(dbl_valueA) || Dmantissap2(dbl_valueB))
+#define Dbl_isnotzero_low4p2(dbl_value) (Dlow4p2(dbl_value)!=0)
+#define Dbl_iszero(dbl_valueA,dbl_valueB) (Dallp1(dbl_valueA)==0 && \
+    Dallp2(dbl_valueB)==0)
+#define Dbl_iszero_allp1(dbl_value) (Dallp1(dbl_value)==0)
+#define Dbl_iszero_allp2(dbl_value) (Dallp2(dbl_value)==0)
+#define Dbl_iszero_hidden(dbl_value) (Is_dhidden(dbl_value)==0)
+#define Dbl_iszero_hiddenoverflow(dbl_value) (Is_dhiddenoverflow(dbl_value)==0)
+#define Dbl_iszero_hiddenhigh3mantissa(dbl_value) \
+    (Dhiddenhigh3mantissa(dbl_value)==0)
+#define Dbl_iszero_hiddenhigh7mantissa(dbl_value) \
+    (Dhiddenhigh7mantissa(dbl_value)==0)
+#define Dbl_iszero_sign(dbl_value) (Is_dsign(dbl_value)==0)
+#define Dbl_iszero_exponent(dbl_value) (Dexponent(dbl_value)==0)
+#define Dbl_iszero_mantissa(dbl_valueA,dbl_valueB) \
+    (Dmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0)
+#define Dbl_iszero_exponentmantissa(dbl_valueA,dbl_valueB) \
+    (Dexponentmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0)
+#define Dbl_isinfinity_exponent(dbl_value)		\
+    (Dexponent(dbl_value)==DBL_INFINITY_EXPONENT)
+#define Dbl_isnotinfinity_exponent(dbl_value)		\
+    (Dexponent(dbl_value)!=DBL_INFINITY_EXPONENT)
+#define Dbl_isinfinity(dbl_valueA,dbl_valueB)			\
+    (Dexponent(dbl_valueA)==DBL_INFINITY_EXPONENT &&	\
+    Dmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0)
+#define Dbl_isnan(dbl_valueA,dbl_valueB)		\
+    (Dexponent(dbl_valueA)==DBL_INFINITY_EXPONENT &&	\
+    (Dmantissap1(dbl_valueA)!=0 || Dmantissap2(dbl_valueB)!=0))
+#define Dbl_isnotnan(dbl_valueA,dbl_valueB)		\
+    (Dexponent(dbl_valueA)!=DBL_INFINITY_EXPONENT ||	\
+    (Dmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0))
+
+#define Dbl_islessthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b)	\
+    (Dallp1(dbl_op1a) < Dallp1(dbl_op2a) ||			\
+     (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) &&			\
+      Dallp2(dbl_op1b) < Dallp2(dbl_op2b)))
+#define Dbl_isgreaterthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b)	\
+    (Dallp1(dbl_op1a) > Dallp1(dbl_op2a) ||			\
+     (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) &&			\
+      Dallp2(dbl_op1b) > Dallp2(dbl_op2b)))
+#define Dbl_isnotlessthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b)	\
+    (Dallp1(dbl_op1a) > Dallp1(dbl_op2a) ||			\
+     (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) &&			\
+      Dallp2(dbl_op1b) >= Dallp2(dbl_op2b)))
+#define Dbl_isnotgreaterthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b) \
+    (Dallp1(dbl_op1a) < Dallp1(dbl_op2a) ||			\
+     (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) &&			\
+      Dallp2(dbl_op1b) <= Dallp2(dbl_op2b)))
+#define Dbl_isequal(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b)	\
+     ((Dallp1(dbl_op1a) == Dallp1(dbl_op2a)) &&			\
+      (Dallp2(dbl_op1b) == Dallp2(dbl_op2b)))
+
+#define Dbl_leftshiftby8(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),24,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 8
+#define Dbl_leftshiftby7(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),25,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 7
+#define Dbl_leftshiftby4(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),28,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 4
+#define Dbl_leftshiftby3(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),29,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 3
+#define Dbl_leftshiftby2(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),30,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 2
+#define Dbl_leftshiftby1(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),31,Dallp1(dbl_valueA)); \
+    Dallp2(dbl_valueB) <<= 1
+
+#define Dbl_rightshiftby8(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),8,Dallp2(dbl_valueB)); \
+    Dallp1(dbl_valueA) >>= 8
+#define Dbl_rightshiftby4(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),4,Dallp2(dbl_valueB)); \
+    Dallp1(dbl_valueA) >>= 4
+#define Dbl_rightshiftby2(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),2,Dallp2(dbl_valueB)); \
+    Dallp1(dbl_valueA) >>= 2
+#define Dbl_rightshiftby1(dbl_valueA,dbl_valueB) \
+    Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),1,Dallp2(dbl_valueB)); \
+    Dallp1(dbl_valueA) >>= 1
+    
+/* This magnitude comparison uses the signless first words and
+ * the regular part2 words.  The comparison is graphically:
+ *
+ *       1st greater?  -------------
+ *                                 |
+ *       1st less?-----------------+---------
+ *                                 |        |
+ *       2nd greater or equal----->|        |
+ *                               False     True
+ */
+#define Dbl_ismagnitudeless(leftB,rightB,signlessleft,signlessright)	\
+      ((signlessleft <= signlessright) &&				\
+       ( (signlessleft < signlessright) || (Dallp2(leftB)<Dallp2(rightB)) ))
+    
+#define Dbl_copytoint_exponentmantissap1(src,dest) \
+    dest = Dexponentmantissap1(src)
+
+/* A quiet NaN has the high mantissa bit clear and at least on other (in this
+ * case the adjacent bit) bit set. */
+#define Dbl_set_quiet(dbl_value) Deposit_dhigh2mantissa(dbl_value,1)
+#define Dbl_set_exponent(dbl_value, exp) Deposit_dexponent(dbl_value,exp)
+
+#define Dbl_set_mantissa(desta,destb,valuea,valueb)	\
+    Deposit_dmantissap1(desta,valuea);			\
+    Dmantissap2(destb) = Dmantissap2(valueb)
+#define Dbl_set_mantissap1(desta,valuea)		\
+    Deposit_dmantissap1(desta,valuea)
+#define Dbl_set_mantissap2(destb,valueb)		\
+    Dmantissap2(destb) = Dmantissap2(valueb)
+
+#define Dbl_set_exponentmantissa(desta,destb,valuea,valueb)	\
+    Deposit_dexponentmantissap1(desta,valuea);			\
+    Dmantissap2(destb) = Dmantissap2(valueb)
+#define Dbl_set_exponentmantissap1(dest,value)			\
+    Deposit_dexponentmantissap1(dest,value)
+
+#define Dbl_copyfromptr(src,desta,destb) \
+    Dallp1(desta) = src->wd0;		\
+    Dallp2(destb) = src->wd1 
+#define Dbl_copytoptr(srca,srcb,dest)	\
+    dest->wd0 = Dallp1(srca);		\
+    dest->wd1 = Dallp2(srcb)
+
+/*  An infinity is represented with the max exponent and a zero mantissa */
+#define Dbl_setinfinity_exponent(dbl_value) \
+    Deposit_dexponent(dbl_value,DBL_INFINITY_EXPONENT)
+#define Dbl_setinfinity_exponentmantissa(dbl_valueA,dbl_valueB)	\
+    Deposit_dexponentmantissap1(dbl_valueA, 			\
+    (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH))));	\
+    Dmantissap2(dbl_valueB) = 0
+#define Dbl_setinfinitypositive(dbl_valueA,dbl_valueB)		\
+    Dallp1(dbl_valueA) 						\
+        = (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH)));	\
+    Dmantissap2(dbl_valueB) = 0
+#define Dbl_setinfinitynegative(dbl_valueA,dbl_valueB)		\
+    Dallp1(dbl_valueA) = ((unsigned int)1<<31) |		\
+         (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH)));	\
+    Dmantissap2(dbl_valueB) = 0
+#define Dbl_setinfinity(dbl_valueA,dbl_valueB,sign)		\
+    Dallp1(dbl_valueA) = ((unsigned int)sign << 31) | 		\
+	(DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH)));	\
+    Dmantissap2(dbl_valueB) = 0
+
+#define Dbl_sethigh4bits(dbl_value, extsign) Deposit_dhigh4p1(dbl_value,extsign)
+#define Dbl_set_sign(dbl_value,sign) Deposit_dsign(dbl_value,sign)
+#define Dbl_invert_sign(dbl_value) Deposit_dsign(dbl_value,~Dsign(dbl_value))
+#define Dbl_setone_sign(dbl_value) Deposit_dsign(dbl_value,1)
+#define Dbl_setone_lowmantissap2(dbl_value) Deposit_dlowp2(dbl_value,1)
+#define Dbl_setzero_sign(dbl_value) Dallp1(dbl_value) &= 0x7fffffff
+#define Dbl_setzero_exponent(dbl_value) 		\
+    Dallp1(dbl_value) &= 0x800fffff
+#define Dbl_setzero_mantissa(dbl_valueA,dbl_valueB)	\
+    Dallp1(dbl_valueA) &= 0xfff00000; 			\
+    Dallp2(dbl_valueB) = 0
+#define Dbl_setzero_mantissap1(dbl_value) Dallp1(dbl_value) &= 0xfff00000
+#define Dbl_setzero_mantissap2(dbl_value) Dallp2(dbl_value) = 0
+#define Dbl_setzero_exponentmantissa(dbl_valueA,dbl_valueB)	\
+    Dallp1(dbl_valueA) &= 0x80000000;		\
+    Dallp2(dbl_valueB) = 0
+#define Dbl_setzero_exponentmantissap1(dbl_valueA)	\
+    Dallp1(dbl_valueA) &= 0x80000000
+#define Dbl_setzero(dbl_valueA,dbl_valueB) \
+    Dallp1(dbl_valueA) = 0; Dallp2(dbl_valueB) = 0
+#define Dbl_setzerop1(dbl_value) Dallp1(dbl_value) = 0
+#define Dbl_setzerop2(dbl_value) Dallp2(dbl_value) = 0
+#define Dbl_setnegativezero(dbl_value) \
+    Dallp1(dbl_value) = (unsigned int)1 << 31; Dallp2(dbl_value) = 0
+#define Dbl_setnegativezerop1(dbl_value) Dallp1(dbl_value) = (unsigned int)1<<31
+
+/* Use the following macro for both overflow & underflow conditions */
+#define ovfl -
+#define unfl +
+#define Dbl_setwrapped_exponent(dbl_value,exponent,op) \
+    Deposit_dexponent(dbl_value,(exponent op DBL_WRAP))
+
+#define Dbl_setlargestpositive(dbl_valueA,dbl_valueB) 			\
+    Dallp1(dbl_valueA) = ((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) \
+			| ((1<<(32-(1+DBL_EXP_LENGTH))) - 1 );		\
+    Dallp2(dbl_valueB) = 0xFFFFFFFF
+#define Dbl_setlargestnegative(dbl_valueA,dbl_valueB) 			\
+    Dallp1(dbl_valueA) = ((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) \
+			| ((1<<(32-(1+DBL_EXP_LENGTH))) - 1 )		\
+			| ((unsigned int)1<<31);			\
+    Dallp2(dbl_valueB) = 0xFFFFFFFF
+#define Dbl_setlargest_exponentmantissa(dbl_valueA,dbl_valueB)		\
+    Deposit_dexponentmantissap1(dbl_valueA,				\
+	(((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH)))		\
+			| ((1<<(32-(1+DBL_EXP_LENGTH))) - 1 )));	\
+    Dallp2(dbl_valueB) = 0xFFFFFFFF
+
+#define Dbl_setnegativeinfinity(dbl_valueA,dbl_valueB) 			\
+    Dallp1(dbl_valueA) = ((1<<DBL_EXP_LENGTH) | DBL_INFINITY_EXPONENT) 	\
+			 << (32-(1+DBL_EXP_LENGTH)) ; 			\
+    Dallp2(dbl_valueB) = 0
+#define Dbl_setlargest(dbl_valueA,dbl_valueB,sign)			\
+    Dallp1(dbl_valueA) = ((unsigned int)sign << 31) |			\
+         ((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) |	 	\
+	 ((1 << (32-(1+DBL_EXP_LENGTH))) - 1 );				\
+    Dallp2(dbl_valueB) = 0xFFFFFFFF
+    
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Dbl_right_align(srcdstA,srcdstB,shift,extent)			\
+    if( shift >= 32 ) 							\
+	{								\
+	/* Big shift requires examining the portion shift off 		\
+	the end to properly set inexact.  */				\
+	if(shift < 64)							\
+	    {								\
+	    if(shift > 32)						\
+		{							\
+	        Variable_shift_double(Dallp1(srcdstA),Dallp2(srcdstB),	\
+		 shift-32, Extall(extent));				\
+	        if(Dallp2(srcdstB) << 64 - (shift)) Ext_setone_low(extent); \
+	        }							\
+	    else Extall(extent) = Dallp2(srcdstB);			\
+	    Dallp2(srcdstB) = Dallp1(srcdstA) >> (shift - 32);		\
+	    }								\
+	else								\
+	    {								\
+	    Extall(extent) = Dallp1(srcdstA);				\
+	    if(Dallp2(srcdstB)) Ext_setone_low(extent);			\
+	    Dallp2(srcdstB) = 0;					\
+	    }								\
+	Dallp1(srcdstA) = 0;						\
+	}								\
+    else								\
+	{								\
+	/* Small alignment is simpler.  Extension is easily set. */	\
+	if (shift > 0)							\
+	    {								\
+	    Extall(extent) = Dallp2(srcdstB) << 32 - (shift);		\
+	    Variable_shift_double(Dallp1(srcdstA),Dallp2(srcdstB),shift, \
+	     Dallp2(srcdstB));						\
+	    Dallp1(srcdstA) >>= shift;					\
+	    }								\
+	else Extall(extent) = 0;					\
+	}
+
+/* 
+ * Here we need to shift the result right to correct for an overshift
+ * (due to the exponent becoming negative) during normalization.
+ */
+#define Dbl_fix_overshift(srcdstA,srcdstB,shift,extent)			\
+	    Extall(extent) = Dallp2(srcdstB) << 32 - (shift);		\
+	    Dallp2(srcdstB) = (Dallp1(srcdstA) << 32 - (shift)) |	\
+		(Dallp2(srcdstB) >> (shift));				\
+	    Dallp1(srcdstA) = Dallp1(srcdstA) >> shift
+
+#define Dbl_hiddenhigh3mantissa(dbl_value) Dhiddenhigh3mantissa(dbl_value)
+#define Dbl_hidden(dbl_value) Dhidden(dbl_value)
+#define Dbl_lowmantissap2(dbl_value) Dlowp2(dbl_value)
+
+/* The left argument is never smaller than the right argument */
+#define Dbl_subtract(lefta,leftb,righta,rightb,resulta,resultb)			\
+    if( Dallp2(rightb) > Dallp2(leftb) ) Dallp1(lefta)--;	\
+    Dallp2(resultb) = Dallp2(leftb) - Dallp2(rightb);		\
+    Dallp1(resulta) = Dallp1(lefta) - Dallp1(righta)
+
+/* Subtract right augmented with extension from left augmented with zeros and
+ * store into result and extension. */
+#define Dbl_subtract_withextension(lefta,leftb,righta,rightb,extent,resulta,resultb)	\
+    Dbl_subtract(lefta,leftb,righta,rightb,resulta,resultb);		\
+    if( (Extall(extent) = 0-Extall(extent)) )				\
+        {								\
+        if((Dallp2(resultb)--) == 0) Dallp1(resulta)--;			\
+        }
+
+#define Dbl_addition(lefta,leftb,righta,rightb,resulta,resultb)		\
+    /* If the sum of the low words is less than either source, then	\
+     * an overflow into the next word occurred. */			\
+    Dallp1(resulta) = Dallp1(lefta) + Dallp1(righta);			\
+    if((Dallp2(resultb) = Dallp2(leftb) + Dallp2(rightb)) < Dallp2(rightb)) \
+	Dallp1(resulta)++
+
+#define Dbl_xortointp1(left,right,result)			\
+    result = Dallp1(left) XOR Dallp1(right)
+
+#define Dbl_xorfromintp1(left,right,result)			\
+    Dallp1(result) = left XOR Dallp1(right)
+
+#define Dbl_swap_lower(left,right)				\
+    Dallp2(left)  = Dallp2(left) XOR Dallp2(right);		\
+    Dallp2(right) = Dallp2(left) XOR Dallp2(right);		\
+    Dallp2(left)  = Dallp2(left) XOR Dallp2(right)
+
+/* Need to Initialize */
+#define Dbl_makequietnan(desta,destb)					\
+    Dallp1(desta) = ((DBL_EMAX+DBL_BIAS)+1)<< (32-(1+DBL_EXP_LENGTH))	\
+                 | (1<<(32-(1+DBL_EXP_LENGTH+2)));			\
+    Dallp2(destb) = 0
+#define Dbl_makesignalingnan(desta,destb)				\
+    Dallp1(desta) = ((DBL_EMAX+DBL_BIAS)+1)<< (32-(1+DBL_EXP_LENGTH))	\
+                 | (1<<(32-(1+DBL_EXP_LENGTH+1)));			\
+    Dallp2(destb) = 0
+
+#define Dbl_normalize(dbl_opndA,dbl_opndB,exponent)			\
+	while(Dbl_iszero_hiddenhigh7mantissa(dbl_opndA)) {		\
+		Dbl_leftshiftby8(dbl_opndA,dbl_opndB);			\
+		exponent -= 8;						\
+	}								\
+	if(Dbl_iszero_hiddenhigh3mantissa(dbl_opndA)) {			\
+		Dbl_leftshiftby4(dbl_opndA,dbl_opndB);			\
+		exponent -= 4;						\
+	}								\
+	while(Dbl_iszero_hidden(dbl_opndA)) {				\
+		Dbl_leftshiftby1(dbl_opndA,dbl_opndB);			\
+		exponent -= 1;						\
+	}
+
+#define Twoword_add(src1dstA,src1dstB,src2A,src2B)		\
+	/* 							\
+	 * want this macro to generate:				\
+	 *	ADD	src1dstB,src2B,src1dstB;		\
+	 *	ADDC	src1dstA,src2A,src1dstA;		\
+	 */							\
+	if ((src1dstB) + (src2B) < (src1dstB)) Dallp1(src1dstA)++; \
+	Dallp1(src1dstA) += (src2A);				\
+	Dallp2(src1dstB) += (src2B)
+
+#define Twoword_subtract(src1dstA,src1dstB,src2A,src2B)		\
+	/* 							\
+	 * want this macro to generate:				\
+	 *	SUB	src1dstB,src2B,src1dstB;		\
+	 *	SUBB	src1dstA,src2A,src1dstA;		\
+	 */							\
+	if ((src1dstB) < (src2B)) Dallp1(src1dstA)--;		\
+	Dallp1(src1dstA) -= (src2A);				\
+	Dallp2(src1dstB) -= (src2B)
+
+#define Dbl_setoverflow(resultA,resultB)				\
+	/* set result to infinity or largest number */			\
+	switch (Rounding_mode()) {					\
+		case ROUNDPLUS:						\
+			if (Dbl_isone_sign(resultA)) {			\
+				Dbl_setlargestnegative(resultA,resultB); \
+			}						\
+			else {						\
+				Dbl_setinfinitypositive(resultA,resultB); \
+			}						\
+			break;						\
+		case ROUNDMINUS:					\
+			if (Dbl_iszero_sign(resultA)) {			\
+				Dbl_setlargestpositive(resultA,resultB); \
+			}						\
+			else {						\
+				Dbl_setinfinitynegative(resultA,resultB); \
+			}						\
+			break;						\
+		case ROUNDNEAREST:					\
+			Dbl_setinfinity_exponentmantissa(resultA,resultB); \
+			break;						\
+		case ROUNDZERO:						\
+			Dbl_setlargest_exponentmantissa(resultA,resultB); \
+	}
+
+#define Dbl_denormalize(opndp1,opndp2,exponent,guard,sticky,inexact)	\
+    Dbl_clear_signexponent_set_hidden(opndp1);				\
+    if (exponent >= (1-DBL_P)) {					\
+	if (exponent >= -31) {						\
+	    guard = (Dallp2(opndp2) >> -exponent) & 1;			\
+	    if (exponent < 0) sticky |= Dallp2(opndp2) << (32+exponent); \
+	    if (exponent > -31) {					\
+		Variable_shift_double(opndp1,opndp2,1-exponent,opndp2);	\
+		Dallp1(opndp1) >>= 1-exponent;				\
+	    }								\
+	    else {							\
+		Dallp2(opndp2) = Dallp1(opndp1);			\
+		Dbl_setzerop1(opndp1);					\
+	    }								\
+	}								\
+	else {								\
+	    guard = (Dallp1(opndp1) >> -32-exponent) & 1;		\
+	    if (exponent == -32) sticky |= Dallp2(opndp2);		\
+	    else sticky |= (Dallp2(opndp2) | Dallp1(opndp1) << 64+exponent); \
+	    Dallp2(opndp2) = Dallp1(opndp1) >> -31-exponent;		\
+	    Dbl_setzerop1(opndp1);					\
+	}								\
+	inexact = guard | sticky;					\
+    }									\
+    else {								\
+	guard = 0;							\
+	sticky |= (Dallp1(opndp1) | Dallp2(opndp2));			\
+	Dbl_setzero(opndp1,opndp2);					\
+	inexact = sticky;						\
+    }
+
+/* 
+ * The fused multiply add instructions requires a double extended format,
+ * with 106 bits of mantissa.
+ */
+#define DBLEXT_THRESHOLD 106
+
+#define Dblext_setzero(valA,valB,valC,valD)	\
+    Dextallp1(valA) = 0; Dextallp2(valB) = 0;	\
+    Dextallp3(valC) = 0; Dextallp4(valD) = 0
+
+
+#define Dblext_isnotzero_mantissap3(valC) (Dextallp3(valC)!=0)
+#define Dblext_isnotzero_mantissap4(valD) (Dextallp3(valD)!=0)
+#define Dblext_isone_lowp2(val) (Dextlowp2(val)!=0)
+#define Dblext_isone_highp3(val) (Dexthighp3(val)!=0)
+#define Dblext_isnotzero_low31p3(val) (Dextlow31p3(val)!=0)
+#define Dblext_iszero(valA,valB,valC,valD) (Dextallp1(valA)==0 && \
+    Dextallp2(valB)==0 && Dextallp3(valC)==0 && Dextallp4(valD)==0)
+
+#define Dblext_copy(srca,srcb,srcc,srcd,desta,destb,destc,destd) \
+    Dextallp1(desta) = Dextallp4(srca);	\
+    Dextallp2(destb) = Dextallp4(srcb);	\
+    Dextallp3(destc) = Dextallp4(srcc);	\
+    Dextallp4(destd) = Dextallp4(srcd)
+
+#define Dblext_swap_lower(leftp2,leftp3,leftp4,rightp2,rightp3,rightp4)  \
+    Dextallp2(leftp2)  = Dextallp2(leftp2) XOR Dextallp2(rightp2);  \
+    Dextallp2(rightp2) = Dextallp2(leftp2) XOR Dextallp2(rightp2);  \
+    Dextallp2(leftp2)  = Dextallp2(leftp2) XOR Dextallp2(rightp2);  \
+    Dextallp3(leftp3)  = Dextallp3(leftp3) XOR Dextallp3(rightp3);  \
+    Dextallp3(rightp3) = Dextallp3(leftp3) XOR Dextallp3(rightp3);  \
+    Dextallp3(leftp3)  = Dextallp3(leftp3) XOR Dextallp3(rightp3);  \
+    Dextallp4(leftp4)  = Dextallp4(leftp4) XOR Dextallp4(rightp4);  \
+    Dextallp4(rightp4) = Dextallp4(leftp4) XOR Dextallp4(rightp4);  \
+    Dextallp4(leftp4)  = Dextallp4(leftp4) XOR Dextallp4(rightp4)
+
+#define Dblext_setone_lowmantissap4(dbl_value) Deposit_dextlowp4(dbl_value,1)
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Dblext_right_align(srcdstA,srcdstB,srcdstC,srcdstD,shift) \
+  {int shiftamt, sticky;						\
+    shiftamt = shift % 32;						\
+    sticky = 0;								\
+    switch (shift/32) {							\
+     case 0: if (shiftamt > 0) {					\
+	        sticky = Dextallp4(srcdstD) << 32 - (shiftamt); 	\
+                Variable_shift_double(Dextallp3(srcdstC),		\
+		 Dextallp4(srcdstD),shiftamt,Dextallp4(srcdstD));	\
+                Variable_shift_double(Dextallp2(srcdstB),		\
+		 Dextallp3(srcdstC),shiftamt,Dextallp3(srcdstC));	\
+                Variable_shift_double(Dextallp1(srcdstA),		\
+		 Dextallp2(srcdstB),shiftamt,Dextallp2(srcdstB));	\
+	        Dextallp1(srcdstA) >>= shiftamt;			\
+	     }								\
+	     break;							\
+     case 1: if (shiftamt > 0) {					\
+                sticky = (Dextallp3(srcdstC) << 31 - shiftamt) |	\
+			 Dextallp4(srcdstD);				\
+                Variable_shift_double(Dextallp2(srcdstB),		\
+		 Dextallp3(srcdstC),shiftamt,Dextallp4(srcdstD));	\
+                Variable_shift_double(Dextallp1(srcdstA),		\
+		 Dextallp2(srcdstB),shiftamt,Dextallp3(srcdstC));	\
+	     }								\
+	     else {							\
+		sticky = Dextallp4(srcdstD);				\
+		Dextallp4(srcdstD) = Dextallp3(srcdstC);		\
+		Dextallp3(srcdstC) = Dextallp2(srcdstB);		\
+	     }								\
+	     Dextallp2(srcdstB) = Dextallp1(srcdstA) >> shiftamt;	\
+	     Dextallp1(srcdstA) = 0;					\
+	     break;							\
+     case 2: if (shiftamt > 0) {					\
+                sticky = (Dextallp2(srcdstB) << 31 - shiftamt) |	\
+			 Dextallp3(srcdstC) | Dextallp4(srcdstD);	\
+                Variable_shift_double(Dextallp1(srcdstA),		\
+		 Dextallp2(srcdstB),shiftamt,Dextallp4(srcdstD));	\
+	     }								\
+	     else {							\
+		sticky = Dextallp3(srcdstC) | Dextallp4(srcdstD);	\
+		Dextallp4(srcdstD) = Dextallp2(srcdstB);		\
+	     }								\
+	     Dextallp3(srcdstC) = Dextallp1(srcdstA) >> shiftamt;	\
+	     Dextallp1(srcdstA) = Dextallp2(srcdstB) = 0;		\
+	     break;							\
+     case 3: if (shiftamt > 0) {					\
+                sticky = (Dextallp1(srcdstA) << 31 - shiftamt) |	\
+			 Dextallp2(srcdstB) | Dextallp3(srcdstC) |	\
+			 Dextallp4(srcdstD);				\
+	     }								\
+	     else {							\
+		sticky = Dextallp2(srcdstB) | Dextallp3(srcdstC) |	\
+		    Dextallp4(srcdstD);					\
+	     }								\
+	     Dextallp4(srcdstD) = Dextallp1(srcdstA) >> shiftamt;	\
+	     Dextallp1(srcdstA) = Dextallp2(srcdstB) = 0;		\
+	     Dextallp3(srcdstC) = 0;					\
+	     break;							\
+    }									\
+    if (sticky) Dblext_setone_lowmantissap4(srcdstD);			\
+  }
+
+/* The left argument is never smaller than the right argument */
+#define Dblext_subtract(lefta,leftb,leftc,leftd,righta,rightb,rightc,rightd,resulta,resultb,resultc,resultd) \
+    if( Dextallp4(rightd) > Dextallp4(leftd) ) 			\
+	if( (Dextallp3(leftc)--) == 0)				\
+	    if( (Dextallp2(leftb)--) == 0) Dextallp1(lefta)--;	\
+    Dextallp4(resultd) = Dextallp4(leftd) - Dextallp4(rightd);	\
+    if( Dextallp3(rightc) > Dextallp3(leftc) ) 			\
+        if( (Dextallp2(leftb)--) == 0) Dextallp1(lefta)--;	\
+    Dextallp3(resultc) = Dextallp3(leftc) - Dextallp3(rightc);	\
+    if( Dextallp2(rightb) > Dextallp2(leftb) ) Dextallp1(lefta)--; \
+    Dextallp2(resultb) = Dextallp2(leftb) - Dextallp2(rightb);	\
+    Dextallp1(resulta) = Dextallp1(lefta) - Dextallp1(righta)
+
+#define Dblext_addition(lefta,leftb,leftc,leftd,righta,rightb,rightc,rightd,resulta,resultb,resultc,resultd) \
+    /* If the sum of the low words is less than either source, then \
+     * an overflow into the next word occurred. */ \
+    if ((Dextallp4(resultd) = Dextallp4(leftd)+Dextallp4(rightd)) < \
+	Dextallp4(rightd)) \
+	if((Dextallp3(resultc) = Dextallp3(leftc)+Dextallp3(rightc)+1) <= \
+	    Dextallp3(rightc)) \
+	    if((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)+1) \
+	        <= Dextallp2(rightb))  \
+		    Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+	    else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta); \
+	else \
+	    if ((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)) < \
+	        Dextallp2(rightb)) \
+		    Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+	    else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta); \
+    else \
+	if ((Dextallp3(resultc) = Dextallp3(leftc)+Dextallp3(rightc)) < \
+	    Dextallp3(rightc))  \
+	    if ((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)+1) \
+	        <= Dextallp2(rightb)) \
+		    Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+	    else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta); \
+	else \
+	    if ((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)) < \
+	        Dextallp2(rightb)) \
+		    Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+	    else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)
+
+
+#define Dblext_arithrightshiftby1(srcdstA,srcdstB,srcdstC,srcdstD)	\
+    Shiftdouble(Dextallp3(srcdstC),Dextallp4(srcdstD),1,Dextallp4(srcdstD)); \
+    Shiftdouble(Dextallp2(srcdstB),Dextallp3(srcdstC),1,Dextallp3(srcdstC)); \
+    Shiftdouble(Dextallp1(srcdstA),Dextallp2(srcdstB),1,Dextallp2(srcdstB)); \
+    Dextallp1(srcdstA) = (int)Dextallp1(srcdstA) >> 1
+   
+#define Dblext_leftshiftby8(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),24,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),24,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),24,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 8
+#define Dblext_leftshiftby4(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),28,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),28,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),28,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 4
+#define Dblext_leftshiftby3(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),29,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),29,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),29,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 3
+#define Dblext_leftshiftby2(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),30,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),30,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),30,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 2
+#define Dblext_leftshiftby1(valA,valB,valC,valD) \
+    Shiftdouble(Dextallp1(valA),Dextallp2(valB),31,Dextallp1(valA)); \
+    Shiftdouble(Dextallp2(valB),Dextallp3(valC),31,Dextallp2(valB)); \
+    Shiftdouble(Dextallp3(valC),Dextallp4(valD),31,Dextallp3(valC)); \
+    Dextallp4(valD) <<= 1
+
+#define Dblext_rightshiftby4(valueA,valueB,valueC,valueD) \
+    Shiftdouble(Dextallp3(valueC),Dextallp4(valueD),4,Dextallp4(valueD)); \
+    Shiftdouble(Dextallp2(valueB),Dextallp3(valueC),4,Dextallp3(valueC)); \
+    Shiftdouble(Dextallp1(valueA),Dextallp2(valueB),4,Dextallp2(valueB)); \
+    Dextallp1(valueA) >>= 4
+#define Dblext_rightshiftby1(valueA,valueB,valueC,valueD) \
+    Shiftdouble(Dextallp3(valueC),Dextallp4(valueD),1,Dextallp4(valueD)); \
+    Shiftdouble(Dextallp2(valueB),Dextallp3(valueC),1,Dextallp3(valueC)); \
+    Shiftdouble(Dextallp1(valueA),Dextallp2(valueB),1,Dextallp2(valueB)); \
+    Dextallp1(valueA) >>= 1
+
+#define Dblext_xortointp1(left,right,result) Dbl_xortointp1(left,right,result)
+
+#define Dblext_xorfromintp1(left,right,result) \
+	Dbl_xorfromintp1(left,right,result)
+
+#define Dblext_copytoint_exponentmantissap1(src,dest) \
+	Dbl_copytoint_exponentmantissap1(src,dest)
+
+#define Dblext_ismagnitudeless(leftB,rightB,signlessleft,signlessright) \
+	Dbl_ismagnitudeless(leftB,rightB,signlessleft,signlessright)
+
+#define Dbl_copyto_dblext(src1,src2,dest1,dest2,dest3,dest4) \
+	Dextallp1(dest1) = Dallp1(src1); Dextallp2(dest2) = Dallp2(src2); \
+	Dextallp3(dest3) = 0; Dextallp4(dest4) = 0
+
+#define Dblext_set_sign(dbl_value,sign)  Dbl_set_sign(dbl_value,sign)  
+#define Dblext_clear_signexponent_set_hidden(srcdst) \
+	Dbl_clear_signexponent_set_hidden(srcdst) 
+#define Dblext_clear_signexponent(srcdst) Dbl_clear_signexponent(srcdst) 
+#define Dblext_clear_sign(srcdst) Dbl_clear_sign(srcdst) 
+#define Dblext_isone_hidden(dbl_value) Dbl_isone_hidden(dbl_value) 
+
+/*
+ * The Fourword_add() macro assumes that integers are 4 bytes in size.
+ * It will break if this is not the case.
+ */
+
+#define Fourword_add(src1dstA,src1dstB,src1dstC,src1dstD,src2A,src2B,src2C,src2D) \
+	/* 								\
+	 * want this macro to generate:					\
+	 *	ADD	src1dstD,src2D,src1dstD;			\
+	 *	ADDC	src1dstC,src2C,src1dstC;			\
+	 *	ADDC	src1dstB,src2B,src1dstB;			\
+	 *	ADDC	src1dstA,src2A,src1dstA;			\
+	 */								\
+	if ((unsigned int)(src1dstD += (src2D)) < (unsigned int)(src2D)) { \
+	   if ((unsigned int)(src1dstC += (src2C) + 1) <=		\
+	       (unsigned int)(src2C)) {					\
+	     if ((unsigned int)(src1dstB += (src2B) + 1) <=		\
+		 (unsigned int)(src2B)) src1dstA++;			\
+	   }								\
+	   else if ((unsigned int)(src1dstB += (src2B)) < 		\
+		    (unsigned int)(src2B)) src1dstA++;			\
+	}								\
+	else {								\
+	   if ((unsigned int)(src1dstC += (src2C)) <			\
+	       (unsigned int)(src2C)) {					\
+	      if ((unsigned int)(src1dstB += (src2B) + 1) <=		\
+		  (unsigned int)(src2B)) src1dstA++;			\
+	   }								\
+	   else if ((unsigned int)(src1dstB += (src2B)) <		\
+		    (unsigned int)(src2B)) src1dstA++;			\
+	}								\
+	src1dstA += (src2A)
+
+#define Dblext_denormalize(opndp1,opndp2,opndp3,opndp4,exponent,is_tiny) \
+  {int shiftamt, sticky;						\
+    is_tiny = TRUE;							\
+    if (exponent == 0 && (Dextallp3(opndp3) || Dextallp4(opndp4))) {	\
+	switch (Rounding_mode()) {					\
+	case ROUNDPLUS:							\
+		if (Dbl_iszero_sign(opndp1)) {				\
+			Dbl_increment(opndp1,opndp2);			\
+			if (Dbl_isone_hiddenoverflow(opndp1))		\
+				is_tiny = FALSE;			\
+			Dbl_decrement(opndp1,opndp2);			\
+		}							\
+		break;							\
+	case ROUNDMINUS:						\
+		if (Dbl_isone_sign(opndp1)) {				\
+			Dbl_increment(opndp1,opndp2);			\
+			if (Dbl_isone_hiddenoverflow(opndp1))		\
+				is_tiny = FALSE;			\
+			Dbl_decrement(opndp1,opndp2);			\
+		}							\
+		break;							\
+	case ROUNDNEAREST:						\
+		if (Dblext_isone_highp3(opndp3) &&			\
+		    (Dblext_isone_lowp2(opndp2) || 			\
+		     Dblext_isnotzero_low31p3(opndp3)))	{		\
+			Dbl_increment(opndp1,opndp2);			\
+			if (Dbl_isone_hiddenoverflow(opndp1))		\
+				is_tiny = FALSE;			\
+			Dbl_decrement(opndp1,opndp2);			\
+		}							\
+		break;							\
+	}								\
+    }									\
+    Dblext_clear_signexponent_set_hidden(opndp1);			\
+    if (exponent >= (1-QUAD_P)) {					\
+	shiftamt = (1-exponent) % 32;					\
+	switch((1-exponent)/32) {					\
+	  case 0: sticky = Dextallp4(opndp4) << 32-(shiftamt);		\
+		  Variableshiftdouble(opndp3,opndp4,shiftamt,opndp4);	\
+		  Variableshiftdouble(opndp2,opndp3,shiftamt,opndp3);	\
+		  Variableshiftdouble(opndp1,opndp2,shiftamt,opndp2);	\
+		  Dextallp1(opndp1) >>= shiftamt;			\
+		  break;						\
+	  case 1: sticky = (Dextallp3(opndp3) << 32-(shiftamt)) | 	\
+			   Dextallp4(opndp4);				\
+		  Variableshiftdouble(opndp2,opndp3,shiftamt,opndp4);	\
+		  Variableshiftdouble(opndp1,opndp2,shiftamt,opndp3);	\
+		  Dextallp2(opndp2) = Dextallp1(opndp1) >> shiftamt;	\
+		  Dextallp1(opndp1) = 0;				\
+		  break;						\
+	  case 2: sticky = (Dextallp2(opndp2) << 32-(shiftamt)) |	\
+			    Dextallp3(opndp3) | Dextallp4(opndp4);	\
+		  Variableshiftdouble(opndp1,opndp2,shiftamt,opndp4);	\
+		  Dextallp3(opndp3) = Dextallp1(opndp1) >> shiftamt;	\
+		  Dextallp1(opndp1) = Dextallp2(opndp2) = 0;		\
+		  break;						\
+	  case 3: sticky = (Dextallp1(opndp1) << 32-(shiftamt)) |	\
+		  	Dextallp2(opndp2) | Dextallp3(opndp3) | 	\
+			Dextallp4(opndp4);				\
+		  Dextallp4(opndp4) = Dextallp1(opndp1) >> shiftamt;	\
+		  Dextallp1(opndp1) = Dextallp2(opndp2) = 0;		\
+		  Dextallp3(opndp3) = 0;				\
+		  break;						\
+	}								\
+    }									\
+    else {								\
+	sticky = Dextallp1(opndp1) | Dextallp2(opndp2) |		\
+		 Dextallp3(opndp3) | Dextallp4(opndp4);			\
+	Dblext_setzero(opndp1,opndp2,opndp3,opndp4);			\
+    }									\
+    if (sticky) Dblext_setone_lowmantissap4(opndp4);			\
+    exponent = 0;							\
+  }
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/decode_exc.c linux-2.4.20-pre2/arch/parisc/math-emu/decode_exc.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/decode_exc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/decode_exc.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,368 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/fp/decode_exc.c		$ Revision: $
+ *
+ *  Purpose:
+ *	<<please update with a synopsis of the functionality provided by this file>>
+ *
+ *  External Interfaces:
+ *	<<the following list was autogenerated, please review>>
+ *	decode_fpu(Fpu_register, trap_counts)
+ *
+ *  Internal Interfaces:
+ *	<<please update>>
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+/* #include "types.h" */
+#include <asm/signal.h>
+#include <asm/siginfo.h>
+/* #include <machine/sys/mdep_private.h> */
+
+#undef Fpustatus_register
+#define Fpustatus_register Fpu_register[0]
+
+/* General definitions */
+#define DOESTRAP 1
+#define NOTRAP 0
+#define SIGNALCODE(signal, code) ((signal) << 24 | (code));
+#define copropbit	1<<31-2	/* bit position 2 */
+#define opclass		9	/* bits 21 & 22 */
+#define fmt		11	/* bits 19 & 20 */
+#define df		13	/* bits 17 & 18 */
+#define twobits		3	/* mask low-order 2 bits */
+#define fivebits	31	/* mask low-order 5 bits */
+#define MAX_EXCP_REG	7	/* number of excpeption registers to check */
+
+/* Exception register definitions */
+#define Excp_type(index) Exceptiontype(Fpu_register[index])
+#define Excp_instr(index) Instructionfield(Fpu_register[index])
+#define Clear_excp_register(index) Allexception(Fpu_register[index]) = 0
+#define Excp_format() \
+    (current_ir >> ((current_ir>>opclass & twobits)==1 ? df : fmt) & twobits)
+
+/* Miscellaneous definitions */
+#define Fpu_sgl(index) Fpu_register[index*2]
+
+#define Fpu_dblp1(index) Fpu_register[index*2]
+#define Fpu_dblp2(index) Fpu_register[(index*2)+1]
+
+#define Fpu_quadp1(index) Fpu_register[index*2]
+#define Fpu_quadp2(index) Fpu_register[(index*2)+1]
+#define Fpu_quadp3(index) Fpu_register[(index*2)+2]
+#define Fpu_quadp4(index) Fpu_register[(index*2)+3]
+
+/* Single precision floating-point definitions */
+#ifndef Sgl_decrement
+# define Sgl_decrement(sgl_value) Sall(sgl_value)--
+#endif
+
+/* Double precision floating-point definitions */
+#ifndef Dbl_decrement
+# define Dbl_decrement(dbl_valuep1,dbl_valuep2) \
+    if ((Dallp2(dbl_valuep2)--) == 0) Dallp1(dbl_valuep1)-- 
+#endif
+
+
+#define update_trap_counts(Fpu_register, aflags, bflags, trap_counts) {	\
+	aflags=(Fpu_register[0])>>27;	/* assumes zero fill. 32 bit */	\
+	Fpu_register[0] |= bflags;					\
+}
+
+u_int
+decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])
+{
+    unsigned int current_ir, excp;
+    int target, exception_index = 1;
+    boolean inexact;
+    unsigned int aflags;
+    unsigned int bflags;
+    unsigned int excptype;
+
+
+    /* Keep stats on how many floating point exceptions (based on type)
+     * that happen.  Want to keep this overhead low, but still provide
+     * some information to the customer.  All exits from this routine
+     * need to restore Fpu_register[0]
+    */
+
+    bflags=(Fpu_register[0] & 0xf8000000);
+    Fpu_register[0] &= 0x07ffffff;
+
+    /* exception_index is used to index the exception register queue.  It
+     *   always points at the last register that contains a valid exception.  A
+     *   zero value implies no exceptions (also the initialized value).  Setting
+     *   the T-bit resets the exception_index to zero.
+     */
+
+    /*
+     * Check for reserved-op exception.  A reserved-op exception does not 
+     * set any exception registers nor does it set the T-bit.  If the T-bit
+     * is not set then a reserved-op exception occurred.
+     *
+     * At some point, we may want to report reserved op exceptions as
+     * illegal instructions.
+     */
+    
+    if (!Is_tbit_set()) {
+	update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+	return SIGNALCODE(SIGILL, ILL_COPROC);
+    }
+
+    /* 
+     * Is a coprocessor op. 
+     *
+     * Now we need to determine what type of exception occurred.
+     */
+    for (exception_index=1; exception_index<=MAX_EXCP_REG; exception_index++) {
+	current_ir = Excp_instr(exception_index);
+	  /*
+	   * On PA89: there are 5 different unimplemented exception
+	   * codes: 0x1, 0x9, 0xb, 0x3, and 0x23.  PA-RISC 2.0 adds
+	   * another, 0x2b.  Only these have the low order bit set.
+	   */
+	excptype = Excp_type(exception_index);
+	if (excptype & UNIMPLEMENTEDEXCEPTION) {
+		/*
+		 * Clear T-bit and exception register so that
+		 * we can tell if a trap really occurs while 
+		 * emulating the instruction.
+		 */
+		Clear_tbit();
+		Clear_excp_register(exception_index);
+		/*
+		 * Now emulate this instruction.  If a trap occurs,
+		 * fpudispatch will return a non-zero number 
+		 */
+		excp = fpudispatch(current_ir,excptype,0,Fpu_register);
+		/* accumulate the status flags, don't lose them as in hpux */
+		if (excp) {
+			/*
+			 * We now need to make sure that the T-bit and the
+			 * exception register contain the correct values
+			 * before continuing.
+			 */
+			/*
+			 * Set t-bit since it might still be needed for a
+			 * subsequent real trap (I don't understand fully -PB)
+			 */
+			Set_tbit();
+			/* some of the following code uses
+			 * Excp_type(exception_index) so fix that up */
+			Set_exceptiontype_and_instr_field(excp,current_ir,
+			 Fpu_register[exception_index]);
+			if (excp == UNIMPLEMENTEDEXCEPTION) {
+				/*
+			 	 * it is really unimplemented, so restore the
+			 	 * TIMEX extended unimplemented exception code
+			 	 */
+				excp = excptype;
+				update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+				return SIGNALCODE(SIGILL, ILL_COPROC);
+			}
+			/* some of the following code uses excptype, so
+			 * fix that up too */
+			excptype = excp;
+		}
+		/* handle exceptions other than the real UNIMPLIMENTED the
+		 * same way as if the hardware had caused them */
+		if (excp == NOEXCEPTION)
+			/* For now use 'break', should technically be 'continue' */
+			break;
+	}
+
+	  /*
+	   * In PA89, the underflow exception has been extended to encode
+	   * additional information.  The exception looks like pp01x0,
+	   * where x is 1 if inexact and pp represent the inexact bit (I)
+	   * and the round away bit (RA)
+	   */
+	if (excptype & UNDERFLOWEXCEPTION) {
+		/* check for underflow trap enabled */
+		if (Is_underflowtrap_enabled()) {
+			update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+			return SIGNALCODE(SIGFPE, FPE_FLTUND);
+		} else {
+		    /*
+		     * Isn't a real trap; we need to 
+		     * return the default value.
+		     */
+		    target = current_ir & fivebits;
+#ifndef lint
+		    if (Ibit(Fpu_register[exception_index])) inexact = TRUE;
+		    else inexact = FALSE;
+#endif
+		    switch (Excp_format()) {
+		      case SGL:
+		        /*
+		         * If ra (round-away) is set, will 
+		         * want to undo the rounding done
+		         * by the hardware.
+		         */
+		        if (Rabit(Fpu_register[exception_index])) 
+				Sgl_decrement(Fpu_sgl(target));
+
+			/* now denormalize */
+			sgl_denormalize(&Fpu_sgl(target),&inexact,Rounding_mode());
+		    	break;
+		      case DBL:
+		    	/*
+		    	 * If ra (round-away) is set, will 
+		    	 * want to undo the rounding done
+		    	 * by the hardware.
+		    	 */
+		    	if (Rabit(Fpu_register[exception_index])) 
+				Dbl_decrement(Fpu_dblp1(target),Fpu_dblp2(target));
+
+			/* now denormalize */
+			dbl_denormalize(&Fpu_dblp1(target),&Fpu_dblp2(target),
+			  &inexact,Rounding_mode());
+		    	break;
+		    }
+		    if (inexact) Set_underflowflag();
+		    /* 
+		     * Underflow can generate an inexact
+		     * exception.  If inexact trap is enabled,
+		     * want to do an inexact trap, otherwise 
+		     * set inexact flag.
+		     */
+		    if (inexact && Is_inexacttrap_enabled()) {
+		    	/*
+		    	 * Set exception field of exception register
+		    	 * to inexact, parm field to zero.
+			 * Underflow bit should be cleared.
+		    	 */
+		    	Set_exceptiontype(Fpu_register[exception_index],
+			 INEXACTEXCEPTION);
+			Set_parmfield(Fpu_register[exception_index],0);
+			update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+			return SIGNALCODE(SIGFPE, FPE_FLTRES);
+		    }
+		    else {
+		    	/*
+		    	 * Exception register needs to be cleared.  
+			 * Inexact flag needs to be set if inexact.
+		    	 */
+		    	Clear_excp_register(exception_index);
+		    	if (inexact) Set_inexactflag();
+		    }
+		}
+		continue;
+	}
+	switch(Excp_type(exception_index)) {
+	  case OVERFLOWEXCEPTION:
+	  case OVERFLOWEXCEPTION | INEXACTEXCEPTION:
+		/* check for overflow trap enabled */
+			update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+		if (Is_overflowtrap_enabled()) {
+			update_trap_counts(Fpu_register, aflags, bflags, 
+					   trap_counts);
+			return SIGNALCODE(SIGFPE, FPE_FLTOVF);
+		} else {
+			/*
+			 * Isn't a real trap; we need to 
+			 * return the default value.
+			 */
+			target = current_ir & fivebits;
+			switch (Excp_format()) {
+			  case SGL: 
+				Sgl_setoverflow(Fpu_sgl(target));
+				break;
+			  case DBL:
+				Dbl_setoverflow(Fpu_dblp1(target),Fpu_dblp2(target));
+				break;
+			}
+			Set_overflowflag();
+			/* 
+			 * Overflow always generates an inexact
+			 * exception.  If inexact trap is enabled,
+			 * want to do an inexact trap, otherwise 
+			 * set inexact flag.
+			 */
+			if (Is_inexacttrap_enabled()) {
+				/*
+				 * Set exception field of exception
+				 * register to inexact.  Overflow
+				 * bit should be cleared.
+				 */
+				Set_exceptiontype(Fpu_register[exception_index],
+				 INEXACTEXCEPTION);
+				update_trap_counts(Fpu_register, aflags, bflags,
+					   trap_counts);
+				return SIGNALCODE(SIGFPE, FPE_FLTRES);
+			}
+			else {
+				/*
+				 * Exception register needs to be cleared.  
+				 * Inexact flag needs to be set.
+				 */
+				Clear_excp_register(exception_index);
+				Set_inexactflag();
+			}
+		}
+		break;
+	  case INVALIDEXCEPTION:
+		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+		return SIGNALCODE(SIGFPE, FPE_FLTINV);
+	  case DIVISIONBYZEROEXCEPTION:
+		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+	  	return SIGNALCODE(SIGFPE, FPE_FLTDIV);
+	  case INEXACTEXCEPTION:
+		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+		return SIGNALCODE(SIGFPE, FPE_FLTRES);
+	  default:
+		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+		printk(__FILE__ "(%d) Unknown FPU exception 0x%x\n",
+			__LINE__, Excp_type(exception_index));
+		return SIGNALCODE(SIGILL, ILL_COPROC);
+	  case NOEXCEPTION:	/* no exception */
+		/*
+		 * Clear exception register in case 
+		 * other fields are non-zero.
+		 */
+		Clear_excp_register(exception_index);
+		break;
+	}
+    }
+    /*
+     * No real exceptions occurred.
+     */
+    Clear_tbit();
+    update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+    return(NOTRAP);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/denormal.c linux-2.4.20-pre2/arch/parisc/math-emu/denormal.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/denormal.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/denormal.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,135 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/fp/denormal.c		$ Revision: $
+ *
+ *  Purpose:
+ *	<<please update with a synopsis of the functionality provided by this file>>
+ *
+ *  External Interfaces:
+ *	<<the following list was autogenerated, please review>>
+ *	dbl_denormalize(dbl_opndp1,dbl_opndp2,inexactflag,rmode)
+ *	sgl_denormalize(sgl_opnd,inexactflag,rmode)
+ *
+ *  Internal Interfaces:
+ *	<<please update>>
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "hppa.h"
+#include "types.h"
+/* #include <machine/sys/mdep_private.h> */
+
+#undef Fpustatus_register
+#define Fpustatus_register Fpu_register[0]
+
+void
+sgl_denormalize(unsigned int *sgl_opnd, boolean *inexactflag, int rmode)
+{
+	unsigned int opnd;
+	int sign, exponent;
+	boolean guardbit = FALSE, stickybit, inexact;
+
+	opnd = *sgl_opnd;
+	stickybit = *inexactflag;
+        exponent = Sgl_exponent(opnd) - SGL_WRAP;
+        sign = Sgl_sign(opnd);
+	Sgl_denormalize(opnd,exponent,guardbit,stickybit,inexact);
+	if (inexact) {
+	    switch (rmode) {
+	      case ROUNDPLUS:
+		if (sign == 0) {
+			Sgl_increment(opnd);
+		}
+		break;
+	      case ROUNDMINUS:
+		if (sign != 0) {
+			Sgl_increment(opnd);
+		}
+		break;
+	      case ROUNDNEAREST:
+		if (guardbit && (stickybit || 
+		       Sgl_isone_lowmantissa(opnd))) {
+			   Sgl_increment(opnd);
+		}
+		break;
+	    }
+	}
+	Sgl_set_sign(opnd,sign);
+	*sgl_opnd = opnd;
+	*inexactflag = inexact;
+	return;
+}
+
+void
+dbl_denormalize(unsigned int *dbl_opndp1,
+	unsigned int * dbl_opndp2,
+	boolean *inexactflag,
+	int rmode)
+{
+	unsigned int opndp1, opndp2;
+	int sign, exponent;
+	boolean guardbit = FALSE, stickybit, inexact;
+
+	opndp1 = *dbl_opndp1;
+	opndp2 = *dbl_opndp2;
+	stickybit = *inexactflag;
+	exponent = Dbl_exponent(opndp1) - DBL_WRAP;
+	sign = Dbl_sign(opndp1);
+	Dbl_denormalize(opndp1,opndp2,exponent,guardbit,stickybit,inexact);
+	if (inexact) {
+	    switch (rmode) {
+	      case ROUNDPLUS:
+		if (sign == 0) {
+			Dbl_increment(opndp1,opndp2);
+		}
+		break;
+	      case ROUNDMINUS:
+		if (sign != 0) {
+			Dbl_increment(opndp1,opndp2);
+		}
+		break;
+	      case ROUNDNEAREST:
+		if (guardbit && (stickybit || 
+		       Dbl_isone_lowmantissap2(opndp2))) {
+			   Dbl_increment(opndp1,opndp2);
+		}
+		break;
+	    }
+	}
+	Dbl_set_sign(opndp1,sign);
+	*dbl_opndp1 = opndp1;
+	*dbl_opndp2 = opndp2;
+	*inexactflag = inexact;
+	return;
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/dfadd.c linux-2.4.20-pre2/arch/parisc/math-emu/dfadd.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/dfadd.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/dfadd.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,524 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfadd.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double_add: add two double precision values.
+ *
+ *  External Interfaces:
+ *	dbl_fadd(leftptr, rightptr, dstptr, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double_add: add two double precision values.
+ */
+dbl_fadd(
+    dbl_floating_point *leftptr,
+    dbl_floating_point *rightptr,
+    dbl_floating_point *dstptr,
+    unsigned int *status)
+{
+    register unsigned int signless_upper_left, signless_upper_right, save;
+    register unsigned int leftp1, leftp2, rightp1, rightp2, extent;
+    register unsigned int resultp1 = 0, resultp2 = 0;
+    
+    register int result_exponent, right_exponent, diff_exponent;
+    register int sign_save, jumpsize;
+    register boolean inexact = FALSE;
+    register boolean underflowtrap;
+        
+    /* Create local copies of the numbers */
+    Dbl_copyfromptr(leftptr,leftp1,leftp2);
+    Dbl_copyfromptr(rightptr,rightp1,rightp2);
+
+    /* A zero "save" helps discover equal operands (for later),  *
+     * and is used in swapping operands (if needed).             */
+    Dbl_xortointp1(leftp1,rightp1,/*to*/save);
+
+    /*
+     * check first operand for NaN's or infinity
+     */
+    if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)
+	{
+	if (Dbl_iszero_mantissa(leftp1,leftp2)) 
+	    {
+	    if (Dbl_isnotnan(rightp1,rightp2)) 
+		{
+		if (Dbl_isinfinity(rightp1,rightp2) && save!=0) 
+		    {
+		    /* 
+		     * invalid since operands are opposite signed infinity's
+		     */
+		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                    Set_invalidflag();
+                    Dbl_makequietnan(resultp1,resultp2);
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		/*
+	 	 * return infinity
+	 	 */
+		Dbl_copytoptr(leftp1,leftp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    }
+	else 
+	    {
+            /*
+             * is NaN; signaling or quiet?
+             */
+            if (Dbl_isone_signaling(leftp1)) 
+		{
+               	/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+        	/* make NaN quiet */
+        	Set_invalidflag();
+        	Dbl_set_quiet(leftp1);
+        	}
+	    /* 
+	     * is second operand a signaling NaN? 
+	     */
+	    else if (Dbl_is_signalingnan(rightp1)) 
+		{
+        	/* trap if INVALIDTRAP enabled */
+               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Dbl_set_quiet(rightp1);
+		Dbl_copytoptr(rightp1,rightp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    /*
+ 	     * return quiet NaN
+ 	     */
+	    Dbl_copytoptr(leftp1,leftp2,dstptr);
+ 	    return(NOEXCEPTION);
+	    }
+	} /* End left NaN or Infinity processing */
+    /*
+     * check second operand for NaN's or infinity
+     */
+    if (Dbl_isinfinity_exponent(rightp1)) 
+	{
+	if (Dbl_iszero_mantissa(rightp1,rightp2)) 
+	    {
+	    /* return infinity */
+	    Dbl_copytoptr(rightp1,rightp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+        /*
+         * is NaN; signaling or quiet?
+         */
+        if (Dbl_isone_signaling(rightp1)) 
+	    {
+            /* trap if INVALIDTRAP enabled */
+	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+	    /* make NaN quiet */
+	    Set_invalidflag();
+	    Dbl_set_quiet(rightp1);
+	    }
+	/*
+	 * return quiet NaN
+ 	 */
+	Dbl_copytoptr(rightp1,rightp2,dstptr);
+	return(NOEXCEPTION);
+    	} /* End right NaN or Infinity processing */
+
+    /* Invariant: Must be dealing with finite numbers */
+
+    /* Compare operands by removing the sign */
+    Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);
+    Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);
+
+    /* sign difference selects add or sub operation. */
+    if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))
+	{
+	/* Set the left operand to the larger one by XOR swap *
+	 *  First finish the first word using "save"          */
+	Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);
+	Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);
+     	Dbl_swap_lower(leftp2,rightp2);
+	result_exponent = Dbl_exponent(leftp1);
+	}
+    /* Invariant:  left is not smaller than right. */ 
+
+    if((right_exponent = Dbl_exponent(rightp1)) == 0)
+        {
+	/* Denormalized operands.  First look for zeroes */
+	if(Dbl_iszero_mantissa(rightp1,rightp2)) 
+	    {
+	    /* right is zero */
+	    if(Dbl_iszero_exponentmantissa(leftp1,leftp2))
+		{
+		/* Both operands are zeros */
+		if(Is_rounding_mode(ROUNDMINUS))
+		    {
+		    Dbl_or_signs(leftp1,/*with*/rightp1);
+		    }
+		else
+		    {
+		    Dbl_and_signs(leftp1,/*with*/rightp1);
+		    }
+		}
+	    else 
+		{
+		/* Left is not a zero and must be the result.  Trapped
+		 * underflows are signaled if left is denormalized.  Result
+		 * is always exact. */
+		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+		    {
+		    /* need to normalize results mantissa */
+	    	    sign_save = Dbl_signextendedsign(leftp1);
+		    Dbl_leftshiftby1(leftp1,leftp2);
+		    Dbl_normalize(leftp1,leftp2,result_exponent);
+		    Dbl_set_sign(leftp1,/*using*/sign_save);
+                    Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);
+		    Dbl_copytoptr(leftp1,leftp2,dstptr);
+		    /* inexact = FALSE */
+		    return(UNDERFLOWEXCEPTION);
+		    }
+		}
+	    Dbl_copytoptr(leftp1,leftp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+
+	/* Neither are zeroes */
+	Dbl_clear_sign(rightp1);	/* Exponent is already cleared */
+	if(result_exponent == 0 )
+	    {
+	    /* Both operands are denormalized.  The result must be exact
+	     * and is simply calculated.  A sum could become normalized and a
+	     * difference could cancel to a true zero. */
+	    if( (/*signed*/int) save < 0 )
+		{
+		Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,
+		/*into*/resultp1,resultp2);
+		if(Dbl_iszero_mantissa(resultp1,resultp2))
+		    {
+		    if(Is_rounding_mode(ROUNDMINUS))
+			{
+			Dbl_setone_sign(resultp1);
+			}
+		    else
+			{
+			Dbl_setzero_sign(resultp1);
+			}
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		}
+	    else
+		{
+		Dbl_addition(leftp1,leftp2,rightp1,rightp2,
+		/*into*/resultp1,resultp2);
+		if(Dbl_isone_hidden(resultp1))
+		    {
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		}
+	    if(Is_underflowtrap_enabled())
+		{
+		/* need to normalize result */
+	    	sign_save = Dbl_signextendedsign(resultp1);
+		Dbl_leftshiftby1(resultp1,resultp2);
+		Dbl_normalize(resultp1,resultp2,result_exponent);
+		Dbl_set_sign(resultp1,/*using*/sign_save);
+                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+	        Dbl_copytoptr(resultp1,resultp2,dstptr);
+		/* inexact = FALSE */
+	        return(UNDERFLOWEXCEPTION);
+		}
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+	right_exponent = 1;	/* Set exponent to reflect different bias
+				 * with denomalized numbers. */
+	}
+    else
+	{
+	Dbl_clear_signexponent_set_hidden(rightp1);
+	}
+    Dbl_clear_exponent_set_hidden(leftp1);
+    diff_exponent = result_exponent - right_exponent;
+
+    /* 
+     * Special case alignment of operands that would force alignment 
+     * beyond the extent of the extension.  A further optimization
+     * could special case this but only reduces the path length for this
+     * infrequent case.
+     */
+    if(diff_exponent > DBL_THRESHOLD)
+	{
+	diff_exponent = DBL_THRESHOLD;
+	}
+    
+    /* Align right operand by shifting to right */
+    Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,
+    /*and lower to*/extent);
+
+    /* Treat sum and difference of the operands separately. */
+    if( (/*signed*/int) save < 0 )
+	{
+	/*
+	 * Difference of the two operands.  Their can be no overflow.  A
+	 * borrow can occur out of the hidden bit and force a post
+	 * normalization phase.
+	 */
+	Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,
+	/*with*/extent,/*into*/resultp1,resultp2);
+	if(Dbl_iszero_hidden(resultp1))
+	    {
+	    /* Handle normalization */
+	    /* A straight foward algorithm would now shift the result
+	     * and extension left until the hidden bit becomes one.  Not
+	     * all of the extension bits need participate in the shift.
+	     * Only the two most significant bits (round and guard) are
+	     * needed.  If only a single shift is needed then the guard
+	     * bit becomes a significant low order bit and the extension
+	     * must participate in the rounding.  If more than a single 
+	     * shift is needed, then all bits to the right of the guard 
+	     * bit are zeros, and the guard bit may or may not be zero. */
+	    sign_save = Dbl_signextendedsign(resultp1);
+            Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);
+
+            /* Need to check for a zero result.  The sign and exponent
+	     * fields have already been zeroed.  The more efficient test
+	     * of the full object can be used.
+	     */
+    	    if(Dbl_iszero(resultp1,resultp2))
+		/* Must have been "x-x" or "x+(-x)". */
+		{
+		if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    result_exponent--;
+	    /* Look to see if normalization is finished. */
+	    if(Dbl_isone_hidden(resultp1))
+		{
+		if(result_exponent==0)
+		    {
+		    /* Denormalized, exponent should be zero.  Left operand *
+		     * was normalized, so extent (guard, round) was zero    */
+		    goto underflow;
+		    }
+		else
+		    {
+		    /* No further normalization is needed. */
+		    Dbl_set_sign(resultp1,/*using*/sign_save);
+	    	    Ext_leftshiftby1(extent);
+		    goto round;
+		    }
+		}
+
+	    /* Check for denormalized, exponent should be zero.  Left    *
+	     * operand was normalized, so extent (guard, round) was zero */
+	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+	       result_exponent==0) goto underflow;
+
+	    /* Shift extension to complete one bit of normalization and
+	     * update exponent. */
+	    Ext_leftshiftby1(extent);
+
+	    /* Discover first one bit to determine shift amount.  Use a
+	     * modified binary search.  We have already shifted the result
+	     * one position right and still not found a one so the remainder
+	     * of the extension must be zero and simplifies rounding. */
+	    /* Scan bytes */
+	    while(Dbl_iszero_hiddenhigh7mantissa(resultp1))
+		{
+		Dbl_leftshiftby8(resultp1,resultp2);
+		if((result_exponent -= 8) <= 0  && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Now narrow it down to the nibble */
+	    if(Dbl_iszero_hiddenhigh3mantissa(resultp1))
+		{
+		/* The lower nibble contains the normalizing one */
+		Dbl_leftshiftby4(resultp1,resultp2);
+		if((result_exponent -= 4) <= 0 && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Select case were first bit is set (already normalized)
+	     * otherwise select the proper shift. */
+	    if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)
+		{
+		/* Already normalized */
+		if(result_exponent <= 0) goto underflow;
+		Dbl_set_sign(resultp1,/*using*/sign_save);
+		Dbl_set_exponent(resultp1,/*using*/result_exponent);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    Dbl_sethigh4bits(resultp1,/*using*/sign_save);
+	    switch(jumpsize) 
+		{
+		case 1:
+		    {
+		    Dbl_leftshiftby3(resultp1,resultp2);
+		    result_exponent -= 3;
+		    break;
+		    }
+		case 2:
+		case 3:
+		    {
+		    Dbl_leftshiftby2(resultp1,resultp2);
+		    result_exponent -= 2;
+		    break;
+		    }
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+		    {
+		    Dbl_leftshiftby1(resultp1,resultp2);
+		    result_exponent -= 1;
+		    break;
+		    }
+		}
+	    if(result_exponent > 0) 
+		{
+		Dbl_set_exponent(resultp1,/*using*/result_exponent);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION); 	/* Sign bit is already set */
+		}
+	    /* Fixup potential underflows */
+	  underflow:
+	    if(Is_underflowtrap_enabled())
+		{
+		Dbl_set_sign(resultp1,sign_save);
+                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    /* 
+	     * Since we cannot get an inexact denormalized result,
+	     * we can now return.
+	     */
+	    Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);
+	    Dbl_clear_signexponent(resultp1);
+	    Dbl_set_sign(resultp1,sign_save);
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    return(NOEXCEPTION);
+	    } /* end if(hidden...)... */
+	/* Fall through and round */
+	} /* end if(save < 0)... */
+    else 
+	{
+	/* Add magnitudes */
+	Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);
+	if(Dbl_isone_hiddenoverflow(resultp1))
+	    {
+	    /* Prenormalization required. */
+	    Dbl_rightshiftby1_withextent(resultp2,extent,extent);
+	    Dbl_arithrightshiftby1(resultp1,resultp2);
+	    result_exponent++;
+	    } /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+    
+    /* Round the result.  If the extension is all zeros,then the result is
+     * exact.  Otherwise round in the correct direction.  No underflow is
+     * possible. If a postnormalization is necessary, then the mantissa is
+     * all zeros so no shift is needed. */
+  round:
+    if(Ext_isnotzero(extent))
+	{
+	inexact = TRUE;
+	switch(Rounding_mode())
+	    {
+	    case ROUNDNEAREST: /* The default. */
+	    if(Ext_isone_sign(extent))
+		{
+		/* at least 1/2 ulp */
+		if(Ext_isnotzero_lower(extent)  ||
+		  Dbl_isone_lowmantissap2(resultp2))
+		    {
+		    /* either exactly half way and odd or more than 1/2ulp */
+		    Dbl_increment(resultp1,resultp2);
+		    }
+		}
+	    break;
+
+	    case ROUNDPLUS:
+	    if(Dbl_iszero_sign(resultp1))
+		{
+		/* Round up positive results */
+		Dbl_increment(resultp1,resultp2);
+		}
+	    break;
+	    
+	    case ROUNDMINUS:
+	    if(Dbl_isone_sign(resultp1))
+		{
+		/* Round down negative results */
+		Dbl_increment(resultp1,resultp2);
+		}
+	    
+	    case ROUNDZERO:;
+	    /* truncate is simple */
+	    } /* end switch... */
+	if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+    if(result_exponent == DBL_INFINITY_EXPONENT)
+        {
+        /* Overflow */
+        if(Is_overflowtrap_enabled())
+	    {
+	    Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    if (inexact)
+		if (Is_inexacttrap_enabled())
+			return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+		else Set_inexactflag();
+	    return(OVERFLOWEXCEPTION);
+	    }
+        else
+	    {
+	    inexact = TRUE;
+	    Set_overflowflag();
+	    Dbl_setoverflow(resultp1,resultp2);
+	    }
+	}
+    else Dbl_set_exponent(resultp1,result_exponent);
+    Dbl_copytoptr(resultp1,resultp2,dstptr);
+    if(inexact) 
+	if(Is_inexacttrap_enabled())
+	    return(INEXACTEXCEPTION);
+	else Set_inexactflag();
+    return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/dfcmp.c linux-2.4.20-pre2/arch/parisc/math-emu/dfcmp.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/dfcmp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/dfcmp.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,181 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfcmp.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	dbl_cmp: compare two values
+ *
+ *  External Interfaces:
+ *	dbl_fcmp(leftptr, rightptr, cond, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "dbl_float.h"
+    
+/*
+ * dbl_cmp: compare two values
+ */
+int
+dbl_fcmp (dbl_floating_point * leftptr, dbl_floating_point * rightptr,
+	  unsigned int cond, unsigned int *status)
+                                           
+                       /* The predicate to be tested */
+                         
+    {
+    register unsigned int leftp1, leftp2, rightp1, rightp2;
+    register int xorresult;
+        
+    /* Create local copies of the numbers */
+    Dbl_copyfromptr(leftptr,leftp1,leftp2);
+    Dbl_copyfromptr(rightptr,rightp1,rightp2);
+    /*
+     * Test for NaN
+     */
+    if(    (Dbl_exponent(leftp1) == DBL_INFINITY_EXPONENT)
+        || (Dbl_exponent(rightp1) == DBL_INFINITY_EXPONENT) )
+	{
+	/* Check if a NaN is involved.  Signal an invalid exception when 
+	 * comparing a signaling NaN or when comparing quiet NaNs and the
+	 * low bit of the condition is set */
+        if( ((Dbl_exponent(leftp1) == DBL_INFINITY_EXPONENT)
+	    && Dbl_isnotzero_mantissa(leftp1,leftp2) 
+	    && (Exception(cond) || Dbl_isone_signaling(leftp1)))
+	   ||
+	    ((Dbl_exponent(rightp1) == DBL_INFINITY_EXPONENT)
+	    && Dbl_isnotzero_mantissa(rightp1,rightp2) 
+	    && (Exception(cond) || Dbl_isone_signaling(rightp1))) )
+	    {
+	    if( Is_invalidtrap_enabled() ) {
+	    	Set_status_cbit(Unordered(cond));
+		return(INVALIDEXCEPTION);
+	    }
+	    else Set_invalidflag();
+	    Set_status_cbit(Unordered(cond));
+	    return(NOEXCEPTION);
+	    }
+	/* All the exceptional conditions are handled, now special case
+	   NaN compares */
+        else if( ((Dbl_exponent(leftp1) == DBL_INFINITY_EXPONENT)
+	    && Dbl_isnotzero_mantissa(leftp1,leftp2))
+	   ||
+	    ((Dbl_exponent(rightp1) == DBL_INFINITY_EXPONENT)
+	    && Dbl_isnotzero_mantissa(rightp1,rightp2)) )
+	    {
+	    /* NaNs always compare unordered. */
+	    Set_status_cbit(Unordered(cond));
+	    return(NOEXCEPTION);
+	    }
+	/* infinities will drop down to the normal compare mechanisms */
+	}
+    /* First compare for unequal signs => less or greater or
+     * special equal case */
+    Dbl_xortointp1(leftp1,rightp1,xorresult);
+    if( xorresult < 0 )
+        {
+        /* left negative => less, left positive => greater.
+         * equal is possible if both operands are zeros. */
+        if( Dbl_iszero_exponentmantissa(leftp1,leftp2) 
+	  && Dbl_iszero_exponentmantissa(rightp1,rightp2) )
+            {
+	    Set_status_cbit(Equal(cond));
+	    }
+	else if( Dbl_isone_sign(leftp1) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+        }
+    /* Signs are the same.  Treat negative numbers separately
+     * from the positives because of the reversed sense.  */
+    else if(Dbl_isequal(leftp1,leftp2,rightp1,rightp2))
+        {
+        Set_status_cbit(Equal(cond));
+        }
+    else if( Dbl_iszero_sign(leftp1) )
+        {
+        /* Positive compare */
+	if( Dbl_allp1(leftp1) < Dbl_allp1(rightp1) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else if( Dbl_allp1(leftp1) > Dbl_allp1(rightp1) )
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+	else
+	    {
+	    /* Equal first parts.  Now we must use unsigned compares to
+	     * resolve the two possibilities. */
+	    if( Dbl_allp2(leftp2) < Dbl_allp2(rightp2) )
+		{
+		Set_status_cbit(Lessthan(cond));
+		}
+	    else 
+		{
+		Set_status_cbit(Greaterthan(cond));
+		}
+	    }
+	}
+    else
+        {
+        /* Negative compare.  Signed or unsigned compares
+         * both work the same.  That distinction is only
+         * important when the sign bits differ. */
+	if( Dbl_allp1(leftp1) > Dbl_allp1(rightp1) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else if( Dbl_allp1(leftp1) < Dbl_allp1(rightp1) )
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+	else
+	    {
+	    /* Equal first parts.  Now we must use unsigned compares to
+	     * resolve the two possibilities. */
+	    if( Dbl_allp2(leftp2) > Dbl_allp2(rightp2) )
+		{
+		Set_status_cbit(Lessthan(cond));
+		}
+	    else 
+		{
+		Set_status_cbit(Greaterthan(cond));
+		}
+	    }
+        }
+	return(NOEXCEPTION);
+    }
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/dfdiv.c linux-2.4.20-pre2/arch/parisc/math-emu/dfdiv.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/dfdiv.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/dfdiv.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,400 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfdiv.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Precision Floating-point Divide
+ *
+ *  External Interfaces:
+ *	dbl_fdiv(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ *  Double Precision Floating-point Divide
+ */
+
+int
+dbl_fdiv (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2,
+	  dbl_floating_point * dstptr, unsigned int *status)
+{
+	register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
+	register unsigned int opnd3p1, opnd3p2, resultp1, resultp2;
+	register int dest_exponent, count;
+	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	boolean is_tiny;
+
+	Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
+	/* 
+	 * set sign bit of result 
+	 */
+	if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) 
+		Dbl_setnegativezerop1(resultp1);  
+	else Dbl_setzerop1(resultp1);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd1p1)) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
+				if (Dbl_isinfinity(opnd2p1,opnd2p2)) {
+					/* 
+					 * invalid since both operands 
+					 * are infinity 
+					 */
+					if (Is_invalidtrap_enabled())
+                                		return(INVALIDEXCEPTION);
+                                	Set_invalidflag();
+                                	Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+			 	 * return infinity
+			 	 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Dbl_isone_signaling(opnd1p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled())
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd1p1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled())
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+                	return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd2p1)) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			/*
+			 * return zero
+			 */
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Dbl_isone_signaling(opnd2p1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(opnd2p1);
+                }
+                /*
+                 * return quiet NaN
+                 */
+		Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                return(NOEXCEPTION);
+	}
+        /*
+         * check for division by zero
+         */
+        if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+                if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+                        /* invalid since both operands are zero */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        Set_invalidflag();
+                        Dbl_makequietnan(resultp1,resultp2);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        return(NOEXCEPTION);
+                }
+                if (Is_divisionbyzerotrap_enabled())
+                       	return(DIVISIONBYZEROEXCEPTION);
+                Set_divisionbyzeroflag();
+                Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+                Dbl_copytoptr(resultp1,resultp2,dstptr);
+                return(NOEXCEPTION);
+        }
+	/*
+	 * Generate exponent 
+	 */
+	dest_exponent = Dbl_exponent(opnd1p1) - Dbl_exponent(opnd2p1) + DBL_BIAS;
+
+	/*
+	 * Generate mantissa
+	 */
+	if (Dbl_isnotzero_exponent(opnd1p1)) {
+		/* set hidden bit */
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /* is denormalized, want to normalize */
+                Dbl_clear_signexponent(opnd1p1);
+                Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_normalize(opnd1p1,opnd1p2,dest_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Dbl_isnotzero_exponent(opnd2p1)) {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+	else {
+                /* is denormalized; want to normalize */
+                Dbl_clear_signexponent(opnd2p1);
+                Dbl_leftshiftby1(opnd2p1,opnd2p2);
+                while (Dbl_iszero_hiddenhigh7mantissa(opnd2p1)) {
+                        dest_exponent+=8;
+                        Dbl_leftshiftby8(opnd2p1,opnd2p2);
+                }
+                if (Dbl_iszero_hiddenhigh3mantissa(opnd2p1)) {
+                        dest_exponent+=4;
+                        Dbl_leftshiftby4(opnd2p1,opnd2p2);
+                }
+                while (Dbl_iszero_hidden(opnd2p1)) {
+                        dest_exponent++;
+                        Dbl_leftshiftby1(opnd2p1,opnd2p2);
+                }
+	}
+
+	/* Divide the source mantissas */
+
+	/* 
+	 * A non-restoring divide algorithm is used.
+	 */
+	Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+	Dbl_setzero(opnd3p1,opnd3p2);
+	for (count=1; count <= DBL_P && (opnd1p1 || opnd1p2); count++) {
+		Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		if (Dbl_iszero_sign(opnd1p1)) {
+			Dbl_setone_lowmantissap2(opnd3p2);
+			Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+		}
+		else {
+			Twoword_add(opnd1p1, opnd1p2, opnd2p1, opnd2p2);
+		}
+	}
+	if (count <= DBL_P) {
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		Dbl_setone_lowmantissap2(opnd3p2);
+		Dbl_leftshift(opnd3p1,opnd3p2,(DBL_P-count));
+		if (Dbl_iszero_hidden(opnd3p1)) {
+			Dbl_leftshiftby1(opnd3p1,opnd3p2);
+			dest_exponent--;
+		}
+	}
+	else {
+		if (Dbl_iszero_hidden(opnd3p1)) {
+			/* need to get one more bit of result */
+			Dbl_leftshiftby1(opnd1p1,opnd1p2);
+			Dbl_leftshiftby1(opnd3p1,opnd3p2);
+			if (Dbl_iszero_sign(opnd1p1)) {
+				Dbl_setone_lowmantissap2(opnd3p2);
+				Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+			}
+			else {
+				Twoword_add(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+			}
+			dest_exponent--;
+		}
+		if (Dbl_iszero_sign(opnd1p1)) guardbit = TRUE;
+		stickybit = Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2);
+	}
+	inexact = guardbit | stickybit;
+
+	/* 
+	 * round result 
+	 */
+	if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
+		Dbl_clear_signexponent(opnd3p1);
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) 
+					Dbl_increment(opnd3p1,opnd3p2);
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) 
+					Dbl_increment(opnd3p1,opnd3p2);
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+			      		Dbl_increment(opnd3p1,opnd3p2);
+				}
+		}
+		if (Dbl_isone_hidden(opnd3p1)) dest_exponent++;
+	}
+	Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+
+        /* 
+         * Test for overflow
+         */
+	if (dest_exponent >= DBL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact) 
+                            if (Is_inexacttrap_enabled())
+                                return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return(OVERFLOWEXCEPTION);
+                }
+		Set_overflowflag();
+                /* set result to infinity or largest number */
+		Dbl_setoverflow(resultp1,resultp2);
+		inexact = TRUE;
+	}
+        /* 
+         * Test for underflow
+         */
+	else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact) 
+                            if (Is_inexacttrap_enabled())
+                                return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return(UNDERFLOWEXCEPTION);
+                }
+
+		/* Determine if should set underflow flag */
+		is_tiny = TRUE;
+		if (dest_exponent == 0 && inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+				      	Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			}
+		}
+
+                /*
+                 * denormalize result or set to signed zero
+                 */
+		stickybit = inexact;
+		Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit,
+		 stickybit,inexact);
+
+		/* return rounded number */ 
+		if (inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+			      		Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			}
+                	if (is_tiny) Set_underflowflag();
+                }
+		Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+	}
+	else Dbl_set_exponent(resultp1,dest_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+
+	/* check for inexact */
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/dfmpy.c linux-2.4.20-pre2/arch/parisc/math-emu/dfmpy.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/dfmpy.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/dfmpy.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,394 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfmpy.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Precision Floating-point Multiply
+ *
+ *  External Interfaces:
+ *	dbl_fmpy(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ *  Double Precision Floating-point Multiply
+ */
+
+int
+dbl_fmpy(
+	    dbl_floating_point *srcptr1,
+	    dbl_floating_point *srcptr2,
+	    dbl_floating_point *dstptr,
+	    unsigned int *status)
+{
+	register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
+	register unsigned int opnd3p1, opnd3p2, resultp1, resultp2;
+	register int dest_exponent, count;
+	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	boolean is_tiny;
+
+	Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
+
+	/* 
+	 * set sign bit of result 
+	 */
+	if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) 
+		Dbl_setnegativezerop1(resultp1); 
+	else Dbl_setzerop1(resultp1);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd1p1)) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+                                		return(INVALIDEXCEPTION);
+                                	Set_invalidflag();
+                                	Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+			 	 * return infinity
+			 	 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Dbl_isone_signaling(opnd1p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd1p1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled())
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+                	return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd2p1)) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+				/* invalid since operands are zero & infinity */
+				if (Is_invalidtrap_enabled())
+                                	return(INVALIDEXCEPTION);
+                                Set_invalidflag();
+                                Dbl_makequietnan(opnd2p1,opnd2p2);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+			 * return infinity
+			 */
+			Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Dbl_isone_signaling(opnd2p1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(opnd2p1);
+                }
+                /*
+                 * return quiet NaN
+                 */
+		Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent 
+	 */
+	dest_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) -DBL_BIAS;
+
+	/*
+	 * Generate mantissa
+	 */
+	if (Dbl_isnotzero_exponent(opnd1p1)) {
+		/* set hidden bit */
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /* is denormalized, adjust exponent */
+                Dbl_clear_signexponent(opnd1p1);
+                Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_normalize(opnd1p1,opnd1p2,dest_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Dbl_isnotzero_exponent(opnd2p1)) {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /* is denormalized; want to normalize */
+                Dbl_clear_signexponent(opnd2p1);
+                Dbl_leftshiftby1(opnd2p1,opnd2p2);
+		Dbl_normalize(opnd2p1,opnd2p2,dest_exponent);
+	}
+
+	/* Multiply two source mantissas together */
+
+	/* make room for guard bits */
+	Dbl_leftshiftby7(opnd2p1,opnd2p2);
+	Dbl_setzero(opnd3p1,opnd3p2);
+        /* 
+         * Four bits at a time are inspected in each loop, and a 
+         * simple shift and add multiply algorithm is used. 
+         */ 
+	for (count=1;count<=DBL_P;count+=4) {
+		stickybit |= Dlow4p2(opnd3p2);
+		Dbl_rightshiftby4(opnd3p1,opnd3p2);
+		if (Dbit28p2(opnd1p2)) {
+	 		/* Twoword_add should be an ADDC followed by an ADD. */
+                        Twoword_add(opnd3p1, opnd3p2, opnd2p1<<3 | opnd2p2>>29, 
+				    opnd2p2<<3);
+		}
+		if (Dbit29p2(opnd1p2)) {
+                        Twoword_add(opnd3p1, opnd3p2, opnd2p1<<2 | opnd2p2>>30, 
+				    opnd2p2<<2);
+		}
+		if (Dbit30p2(opnd1p2)) {
+                        Twoword_add(opnd3p1, opnd3p2, opnd2p1<<1 | opnd2p2>>31,
+				    opnd2p2<<1);
+		}
+		if (Dbit31p2(opnd1p2)) {
+                        Twoword_add(opnd3p1, opnd3p2, opnd2p1, opnd2p2);
+		}
+		Dbl_rightshiftby4(opnd1p1,opnd1p2);
+	}
+	if (Dbit3p1(opnd3p1)==0) {
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+	}
+	else {
+		/* result mantissa >= 2. */
+		dest_exponent++;
+	}
+	/* check for denormalized result */
+	while (Dbit3p1(opnd3p1)==0) {
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		dest_exponent--;
+	}
+	/*
+	 * check for guard, sticky and inexact bits 
+	 */
+	stickybit |= Dallp2(opnd3p2) << 25;
+	guardbit = (Dallp2(opnd3p2) << 24) >> 31;
+	inexact = guardbit | stickybit;
+
+	/* align result mantissa */
+	Dbl_rightshiftby8(opnd3p1,opnd3p2);
+
+	/* 
+	 * round result 
+	 */
+	if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
+		Dbl_clear_signexponent(opnd3p1);
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) 
+					Dbl_increment(opnd3p1,opnd3p2);
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) 
+					Dbl_increment(opnd3p1,opnd3p2);
+				break;
+			case ROUNDNEAREST:
+				if (guardbit) {
+			   	if (stickybit || Dbl_isone_lowmantissap2(opnd3p2))
+			      	Dbl_increment(opnd3p1,opnd3p2);
+				}
+		}
+		if (Dbl_isone_hidden(opnd3p1)) dest_exponent++;
+	}
+	Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+
+        /* 
+         * Test for overflow
+         */
+	if (dest_exponent >= DBL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+			Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return (OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+			    else Set_inexactflag();
+			return (OVERFLOWEXCEPTION);
+                }
+		inexact = TRUE;
+		Set_overflowflag();
+                /* set result to infinity or largest number */
+		Dbl_setoverflow(resultp1,resultp2);
+	}
+        /* 
+         * Test for underflow
+         */
+	else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+			Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return (UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+			    else Set_inexactflag();
+			return (UNDERFLOWEXCEPTION);
+                }
+
+		/* Determine if should set underflow flag */
+		is_tiny = TRUE;
+		if (dest_exponent == 0 && inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+				      	Dbl_increment(opnd3p1,opnd3p2);
+					if (Dbl_isone_hiddenoverflow(opnd3p1))
+                			    is_tiny = FALSE;
+					Dbl_decrement(opnd3p1,opnd3p2);
+				}
+				break;
+			}
+		}
+
+		/*
+		 * denormalize result or set to signed zero
+		 */
+		stickybit = inexact;
+		Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit,
+		 stickybit,inexact);
+
+		/* return zero or smallest number */
+		if (inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Dbl_isone_lowmantissap2(opnd3p2))) {
+			      		Dbl_increment(opnd3p1,opnd3p2);
+				}
+				break;
+			}
+                	if (is_tiny) Set_underflowflag();
+		}
+		Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+	}
+	else Dbl_set_exponent(resultp1,dest_exponent);
+	/* check for inexact */
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/dfrem.c linux-2.4.20-pre2/arch/parisc/math-emu/dfrem.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/dfrem.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/dfrem.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,297 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfrem.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Precision Floating-point Remainder
+ *
+ *  External Interfaces:
+ *	dbl_frem(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ *  Double Precision Floating-point Remainder
+ */
+
+int
+dbl_frem (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2,
+	  dbl_floating_point * dstptr, unsigned int *status)
+{
+	register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
+	register unsigned int resultp1, resultp2;
+	register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
+	register boolean roundup = FALSE;
+
+	Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if ((opnd1_exponent = Dbl_exponent(opnd1p1)) == DBL_INFINITY_EXPONENT) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
+				/* invalid since first operand is infinity */
+				if (Is_invalidtrap_enabled()) 
+                                	return(INVALIDEXCEPTION);
+                                Set_invalidflag();
+                                Dbl_makequietnan(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Dbl_isone_signaling(opnd1p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd1p1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+                	return(NOEXCEPTION);
+		}
+	} 
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if ((opnd2_exponent = Dbl_exponent(opnd2p1)) == DBL_INFINITY_EXPONENT) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			/*
+			 * return first operand
+			 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Dbl_isone_signaling(opnd2p1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(opnd2p1);
+                }
+                /*
+                 * return quiet NaN
+                 */
+		Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+                return(NOEXCEPTION);
+	}
+	/*
+	 * check second operand for zero
+	 */
+	if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+		/* invalid since second operand is zero */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                Set_invalidflag();
+                Dbl_makequietnan(resultp1,resultp2);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+
+	/* 
+	 * get sign of result
+	 */
+	resultp1 = opnd1p1;  
+
+	/* 
+	 * check for denormalized operands
+	 */
+	if (opnd1_exponent == 0) {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* normalize, then continue */
+		opnd1_exponent = 1;
+		Dbl_normalize(opnd1p1,opnd1p2,opnd1_exponent);
+	}
+	else {
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	if (opnd2_exponent == 0) {
+		/* normalize, then continue */
+		opnd2_exponent = 1;
+		Dbl_normalize(opnd2p1,opnd2p2,opnd2_exponent);
+	}
+	else {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+
+	/* find result exponent and divide step loop count */
+	dest_exponent = opnd2_exponent - 1;
+	stepcount = opnd1_exponent - opnd2_exponent;
+
+	/*
+	 * check for opnd1/opnd2 < 1
+	 */
+	if (stepcount < 0) {
+		/*
+		 * check for opnd1/opnd2 > 1/2
+		 *
+		 * In this case n will round to 1, so 
+		 *    r = opnd1 - opnd2 
+		 */
+		if (stepcount == -1 && 
+		    Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+			/* set sign */
+			Dbl_allp1(resultp1) = ~Dbl_allp1(resultp1);
+			/* align opnd2 with opnd1 */
+			Dbl_leftshiftby1(opnd2p1,opnd2p2); 
+			Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,
+			 opnd2p1,opnd2p2);
+			/* now normalize */
+                	while (Dbl_iszero_hidden(opnd2p1)) {
+                        	Dbl_leftshiftby1(opnd2p1,opnd2p2);
+                        	dest_exponent--;
+			}
+			Dbl_set_exponentmantissa(resultp1,resultp2,opnd2p1,opnd2p2);
+			goto testforunderflow;
+		}
+		/*
+		 * opnd1/opnd2 <= 1/2
+		 *
+		 * In this case n will round to zero, so 
+		 *    r = opnd1
+		 */
+		Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
+		dest_exponent = opnd1_exponent;
+		goto testforunderflow;
+	}
+
+	/*
+	 * Generate result
+	 *
+	 * Do iterative subtract until remainder is less than operand 2.
+	 */
+	while (stepcount-- > 0 && (Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2))) {
+		if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+			Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
+		}
+		Dbl_leftshiftby1(opnd1p1,opnd1p2);
+	}
+	/*
+	 * Do last subtract, then determine which way to round if remainder 
+	 * is exactly 1/2 of opnd2 
+	 */
+	if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+		Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
+		roundup = TRUE;
+	}
+	if (stepcount > 0 || Dbl_iszero(opnd1p1,opnd1p2)) {
+		/* division is exact, remainder is zero */
+		Dbl_setzero_exponentmantissa(resultp1,resultp2);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+
+	/* 
+	 * Check for cases where opnd1/opnd2 < n 
+	 *
+	 * In this case the result's sign will be opposite that of
+	 * opnd1.  The mantissa also needs some correction.
+	 */
+	Dbl_leftshiftby1(opnd1p1,opnd1p2);
+	if (Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+		Dbl_invert_sign(resultp1);
+		Dbl_leftshiftby1(opnd2p1,opnd2p2);
+		Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,opnd1p1,opnd1p2);
+	}
+	/* check for remainder being exactly 1/2 of opnd2 */
+	else if (Dbl_isequal(opnd1p1,opnd1p2,opnd2p1,opnd2p2) && roundup) { 
+		Dbl_invert_sign(resultp1);
+	}
+
+	/* normalize result's mantissa */
+        while (Dbl_iszero_hidden(opnd1p1)) {
+                dest_exponent--;
+                Dbl_leftshiftby1(opnd1p1,opnd1p2);
+        }
+	Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
+
+        /* 
+         * Test for underflow
+         */
+    testforunderflow:
+	if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
+			/* frem is always exact */
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(UNDERFLOWEXCEPTION);
+                }
+                /*
+                 * denormalize result or set to signed zero
+                 */
+                if (dest_exponent >= (1 - DBL_P)) {
+			Dbl_rightshift_exponentmantissa(resultp1,resultp2,
+			 1-dest_exponent);
+                }
+                else {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+		}
+	}
+	else Dbl_set_exponent(resultp1,dest_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/dfsqrt.c linux-2.4.20-pre2/arch/parisc/math-emu/dfsqrt.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/dfsqrt.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/dfsqrt.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,195 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfsqrt.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Floating-point Square Root
+ *
+ *  External Interfaces:
+ *	dbl_fsqrt(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ *  Double Floating-point Square Root
+ */
+
+/*ARGSUSED*/
+unsigned int
+dbl_fsqrt(
+	    dbl_floating_point *srcptr,
+	    unsigned int *nullptr,
+	    dbl_floating_point *dstptr,
+	    unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, resultp1, resultp2;
+	register unsigned int newbitp1, newbitp2, sump1, sump2;
+	register int src_exponent;
+	register boolean guardbit = FALSE, even_exponent;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+        /*
+         * check source operand for NaN or infinity
+         */
+        if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
+                /*
+                 * is signaling NaN?
+                 */
+                if (Dbl_isone_signaling(srcp1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(srcp1);
+                }
+                /*
+                 * Return quiet NaN or positive infinity.
+		 *  Fall thru to negative test if negative infinity.
+                 */
+		if (Dbl_iszero_sign(srcp1) || 
+		    Dbl_isnotzero_mantissa(srcp1,srcp2)) {
+                	Dbl_copytoptr(srcp1,srcp2,dstptr);
+                	return(NOEXCEPTION);
+		}
+        }
+
+        /*
+         * check for zero source operand
+         */
+	if (Dbl_iszero_exponentmantissa(srcp1,srcp2)) {
+		Dbl_copytoptr(srcp1,srcp2,dstptr);
+		return(NOEXCEPTION);
+	}
+
+        /*
+         * check for negative source operand 
+         */
+	if (Dbl_isone_sign(srcp1)) {
+		/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Dbl_makequietnan(srcp1,srcp2);
+		Dbl_copytoptr(srcp1,srcp2,dstptr);
+		return(NOEXCEPTION);
+	}
+
+	/*
+	 * Generate result
+	 */
+	if (src_exponent > 0) {
+		even_exponent = Dbl_hidden(srcp1);
+		Dbl_clear_signexponent_set_hidden(srcp1);
+	}
+	else {
+		/* normalize operand */
+		Dbl_clear_signexponent(srcp1);
+		src_exponent++;
+		Dbl_normalize(srcp1,srcp2,src_exponent);
+		even_exponent = src_exponent & 1;
+	}
+	if (even_exponent) {
+		/* exponent is even */
+		/* Add comment here.  Explain why odd exponent needs correction */
+		Dbl_leftshiftby1(srcp1,srcp2);
+	}
+	/*
+	 * Add comment here.  Explain following algorithm.
+	 * 
+	 * Trust me, it works.
+	 *
+	 */
+	Dbl_setzero(resultp1,resultp2);
+	Dbl_allp1(newbitp1) = 1 << (DBL_P - 32);
+	Dbl_setzero_mantissap2(newbitp2);
+	while (Dbl_isnotzero(newbitp1,newbitp2) && Dbl_isnotzero(srcp1,srcp2)) {
+		Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,sump1,sump2);
+		if(Dbl_isnotgreaterthan(sump1,sump2,srcp1,srcp2)) {
+			Dbl_leftshiftby1(newbitp1,newbitp2);
+			/* update result */
+			Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,
+			 resultp1,resultp2);  
+			Dbl_subtract(srcp1,srcp2,sump1,sump2,srcp1,srcp2);
+			Dbl_rightshiftby2(newbitp1,newbitp2);
+		}
+		else {
+			Dbl_rightshiftby1(newbitp1,newbitp2);
+		}
+		Dbl_leftshiftby1(srcp1,srcp2);
+	}
+	/* correct exponent for pre-shift */
+	if (even_exponent) {
+		Dbl_rightshiftby1(resultp1,resultp2);
+	}
+
+	/* check for inexact */
+	if (Dbl_isnotzero(srcp1,srcp2)) {
+		if (!even_exponent && Dbl_islessthan(resultp1,resultp2,srcp1,srcp2)) {
+			Dbl_increment(resultp1,resultp2);
+		}
+		guardbit = Dbl_lowmantissap2(resultp2);
+		Dbl_rightshiftby1(resultp1,resultp2);
+
+		/*  now round result  */
+		switch (Rounding_mode()) {
+		case ROUNDPLUS:
+		     Dbl_increment(resultp1,resultp2);
+		     break;
+		case ROUNDNEAREST:
+		     /* stickybit is always true, so guardbit 
+		      * is enough to determine rounding */
+		     if (guardbit) {
+			    Dbl_increment(resultp1,resultp2);
+		     }
+		     break;
+		}
+		/* increment result exponent by 1 if mantissa overflowed */
+		if (Dbl_isone_hiddenoverflow(resultp1)) src_exponent+=2;
+
+		if (Is_inexacttrap_enabled()) {
+			Dbl_set_exponent(resultp1,
+			 ((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	else {
+		Dbl_rightshiftby1(resultp1,resultp2);
+	}
+	Dbl_set_exponent(resultp1,((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/dfsub.c linux-2.4.20-pre2/arch/parisc/math-emu/dfsub.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/dfsub.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/dfsub.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,526 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/dfsub.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double_subtract: subtract two double precision values.
+ *
+ *  External Interfaces:
+ *	dbl_fsub(leftptr, rightptr, dstptr, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double_subtract: subtract two double precision values.
+ */
+int
+dbl_fsub(
+	    dbl_floating_point *leftptr,
+	    dbl_floating_point *rightptr,
+	    dbl_floating_point *dstptr,
+	    unsigned int *status)
+    {
+    register unsigned int signless_upper_left, signless_upper_right, save;
+    register unsigned int leftp1, leftp2, rightp1, rightp2, extent;
+    register unsigned int resultp1 = 0, resultp2 = 0;
+    
+    register int result_exponent, right_exponent, diff_exponent;
+    register int sign_save, jumpsize;
+    register boolean inexact = FALSE, underflowtrap;
+        
+    /* Create local copies of the numbers */
+    Dbl_copyfromptr(leftptr,leftp1,leftp2);
+    Dbl_copyfromptr(rightptr,rightp1,rightp2);
+
+    /* A zero "save" helps discover equal operands (for later),  *
+     * and is used in swapping operands (if needed).             */
+    Dbl_xortointp1(leftp1,rightp1,/*to*/save);
+
+    /*
+     * check first operand for NaN's or infinity
+     */
+    if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)
+	{
+	if (Dbl_iszero_mantissa(leftp1,leftp2)) 
+	    {
+	    if (Dbl_isnotnan(rightp1,rightp2)) 
+		{
+		if (Dbl_isinfinity(rightp1,rightp2) && save==0) 
+		    {
+		    /* 
+		     * invalid since operands are same signed infinity's
+		     */
+		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                    Set_invalidflag();
+                    Dbl_makequietnan(resultp1,resultp2);
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		/*
+	 	 * return infinity
+	 	 */
+		Dbl_copytoptr(leftp1,leftp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    }
+	else 
+	    {
+            /*
+             * is NaN; signaling or quiet?
+             */
+            if (Dbl_isone_signaling(leftp1)) 
+		{
+               	/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+        	/* make NaN quiet */
+        	Set_invalidflag();
+        	Dbl_set_quiet(leftp1);
+        	}
+	    /* 
+	     * is second operand a signaling NaN? 
+	     */
+	    else if (Dbl_is_signalingnan(rightp1)) 
+		{
+        	/* trap if INVALIDTRAP enabled */
+               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Dbl_set_quiet(rightp1);
+		Dbl_copytoptr(rightp1,rightp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    /*
+ 	     * return quiet NaN
+ 	     */
+	    Dbl_copytoptr(leftp1,leftp2,dstptr);
+ 	    return(NOEXCEPTION);
+	    }
+	} /* End left NaN or Infinity processing */
+    /*
+     * check second operand for NaN's or infinity
+     */
+    if (Dbl_isinfinity_exponent(rightp1)) 
+	{
+	if (Dbl_iszero_mantissa(rightp1,rightp2)) 
+	    {
+	    /* return infinity */
+	    Dbl_invert_sign(rightp1);
+	    Dbl_copytoptr(rightp1,rightp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+        /*
+         * is NaN; signaling or quiet?
+         */
+        if (Dbl_isone_signaling(rightp1)) 
+	    {
+            /* trap if INVALIDTRAP enabled */
+	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+	    /* make NaN quiet */
+	    Set_invalidflag();
+	    Dbl_set_quiet(rightp1);
+	    }
+	/*
+	 * return quiet NaN
+ 	 */
+	Dbl_copytoptr(rightp1,rightp2,dstptr);
+	return(NOEXCEPTION);
+    	} /* End right NaN or Infinity processing */
+
+    /* Invariant: Must be dealing with finite numbers */
+
+    /* Compare operands by removing the sign */
+    Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);
+    Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);
+
+    /* sign difference selects add or sub operation. */
+    if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))
+	{
+	/* Set the left operand to the larger one by XOR swap *
+	 *  First finish the first word using "save"          */
+	Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);
+	Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);
+     	Dbl_swap_lower(leftp2,rightp2);
+	result_exponent = Dbl_exponent(leftp1);
+	Dbl_invert_sign(leftp1);
+	}
+    /* Invariant:  left is not smaller than right. */ 
+
+    if((right_exponent = Dbl_exponent(rightp1)) == 0)
+        {
+	/* Denormalized operands.  First look for zeroes */
+	if(Dbl_iszero_mantissa(rightp1,rightp2)) 
+	    {
+	    /* right is zero */
+	    if(Dbl_iszero_exponentmantissa(leftp1,leftp2))
+		{
+		/* Both operands are zeros */
+		Dbl_invert_sign(rightp1);
+		if(Is_rounding_mode(ROUNDMINUS))
+		    {
+		    Dbl_or_signs(leftp1,/*with*/rightp1);
+		    }
+		else
+		    {
+		    Dbl_and_signs(leftp1,/*with*/rightp1);
+		    }
+		}
+	    else 
+		{
+		/* Left is not a zero and must be the result.  Trapped
+		 * underflows are signaled if left is denormalized.  Result
+		 * is always exact. */
+		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+		    {
+		    /* need to normalize results mantissa */
+	    	    sign_save = Dbl_signextendedsign(leftp1);
+		    Dbl_leftshiftby1(leftp1,leftp2);
+		    Dbl_normalize(leftp1,leftp2,result_exponent);
+		    Dbl_set_sign(leftp1,/*using*/sign_save);
+                    Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);
+		    Dbl_copytoptr(leftp1,leftp2,dstptr);
+		    /* inexact = FALSE */
+		    return(UNDERFLOWEXCEPTION);
+		    }
+		}
+	    Dbl_copytoptr(leftp1,leftp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+
+	/* Neither are zeroes */
+	Dbl_clear_sign(rightp1);	/* Exponent is already cleared */
+	if(result_exponent == 0 )
+	    {
+	    /* Both operands are denormalized.  The result must be exact
+	     * and is simply calculated.  A sum could become normalized and a
+	     * difference could cancel to a true zero. */
+	    if( (/*signed*/int) save >= 0 )
+		{
+		Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,
+		 /*into*/resultp1,resultp2);
+		if(Dbl_iszero_mantissa(resultp1,resultp2))
+		    {
+		    if(Is_rounding_mode(ROUNDMINUS))
+			{
+			Dbl_setone_sign(resultp1);
+			}
+		    else
+			{
+			Dbl_setzero_sign(resultp1);
+			}
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		}
+	    else
+		{
+		Dbl_addition(leftp1,leftp2,rightp1,rightp2,
+		 /*into*/resultp1,resultp2);
+		if(Dbl_isone_hidden(resultp1))
+		    {
+		    Dbl_copytoptr(resultp1,resultp2,dstptr);
+		    return(NOEXCEPTION);
+		    }
+		}
+	    if(Is_underflowtrap_enabled())
+		{
+		/* need to normalize result */
+	    	sign_save = Dbl_signextendedsign(resultp1);
+		Dbl_leftshiftby1(resultp1,resultp2);
+		Dbl_normalize(resultp1,resultp2,result_exponent);
+		Dbl_set_sign(resultp1,/*using*/sign_save);
+                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    return(NOEXCEPTION);
+	    }
+	right_exponent = 1;	/* Set exponent to reflect different bias
+				 * with denomalized numbers. */
+	}
+    else
+	{
+	Dbl_clear_signexponent_set_hidden(rightp1);
+	}
+    Dbl_clear_exponent_set_hidden(leftp1);
+    diff_exponent = result_exponent - right_exponent;
+
+    /* 
+     * Special case alignment of operands that would force alignment 
+     * beyond the extent of the extension.  A further optimization
+     * could special case this but only reduces the path length for this
+     * infrequent case.
+     */
+    if(diff_exponent > DBL_THRESHOLD)
+	{
+	diff_exponent = DBL_THRESHOLD;
+	}
+    
+    /* Align right operand by shifting to right */
+    Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,
+     /*and lower to*/extent);
+
+    /* Treat sum and difference of the operands separately. */
+    if( (/*signed*/int) save >= 0 )
+	{
+	/*
+	 * Difference of the two operands.  Their can be no overflow.  A
+	 * borrow can occur out of the hidden bit and force a post
+	 * normalization phase.
+	 */
+	Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,
+	 /*with*/extent,/*into*/resultp1,resultp2);
+	if(Dbl_iszero_hidden(resultp1))
+	    {
+	    /* Handle normalization */
+	    /* A straight foward algorithm would now shift the result
+	     * and extension left until the hidden bit becomes one.  Not
+	     * all of the extension bits need participate in the shift.
+	     * Only the two most significant bits (round and guard) are
+	     * needed.  If only a single shift is needed then the guard
+	     * bit becomes a significant low order bit and the extension
+	     * must participate in the rounding.  If more than a single 
+	     * shift is needed, then all bits to the right of the guard 
+	     * bit are zeros, and the guard bit may or may not be zero. */
+	    sign_save = Dbl_signextendedsign(resultp1);
+            Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);
+
+            /* Need to check for a zero result.  The sign and exponent
+	     * fields have already been zeroed.  The more efficient test
+	     * of the full object can be used.
+	     */
+    	    if(Dbl_iszero(resultp1,resultp2))
+		/* Must have been "x-x" or "x+(-x)". */
+		{
+		if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    result_exponent--;
+	    /* Look to see if normalization is finished. */
+	    if(Dbl_isone_hidden(resultp1))
+		{
+		if(result_exponent==0)
+		    {
+		    /* Denormalized, exponent should be zero.  Left operand *
+		     * was normalized, so extent (guard, round) was zero    */
+		    goto underflow;
+		    }
+		else
+		    {
+		    /* No further normalization is needed. */
+		    Dbl_set_sign(resultp1,/*using*/sign_save);
+	    	    Ext_leftshiftby1(extent);
+		    goto round;
+		    }
+		}
+
+	    /* Check for denormalized, exponent should be zero.  Left    *
+	     * operand was normalized, so extent (guard, round) was zero */
+	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+	       result_exponent==0) goto underflow;
+
+	    /* Shift extension to complete one bit of normalization and
+	     * update exponent. */
+	    Ext_leftshiftby1(extent);
+
+	    /* Discover first one bit to determine shift amount.  Use a
+	     * modified binary search.  We have already shifted the result
+	     * one position right and still not found a one so the remainder
+	     * of the extension must be zero and simplifies rounding. */
+	    /* Scan bytes */
+	    while(Dbl_iszero_hiddenhigh7mantissa(resultp1))
+		{
+		Dbl_leftshiftby8(resultp1,resultp2);
+		if((result_exponent -= 8) <= 0  && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Now narrow it down to the nibble */
+	    if(Dbl_iszero_hiddenhigh3mantissa(resultp1))
+		{
+		/* The lower nibble contains the normalizing one */
+		Dbl_leftshiftby4(resultp1,resultp2);
+		if((result_exponent -= 4) <= 0 && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Select case were first bit is set (already normalized)
+	     * otherwise select the proper shift. */
+	    if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)
+		{
+		/* Already normalized */
+		if(result_exponent <= 0) goto underflow;
+		Dbl_set_sign(resultp1,/*using*/sign_save);
+		Dbl_set_exponent(resultp1,/*using*/result_exponent);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+		}
+	    Dbl_sethigh4bits(resultp1,/*using*/sign_save);
+	    switch(jumpsize) 
+		{
+		case 1:
+		    {
+		    Dbl_leftshiftby3(resultp1,resultp2);
+		    result_exponent -= 3;
+		    break;
+		    }
+		case 2:
+		case 3:
+		    {
+		    Dbl_leftshiftby2(resultp1,resultp2);
+		    result_exponent -= 2;
+		    break;
+		    }
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+		    {
+		    Dbl_leftshiftby1(resultp1,resultp2);
+		    result_exponent -= 1;
+		    break;
+		    }
+		}
+	    if(result_exponent > 0) 
+		{
+		Dbl_set_exponent(resultp1,/*using*/result_exponent);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);		/* Sign bit is already set */
+		}
+	    /* Fixup potential underflows */
+	  underflow:
+	    if(Is_underflowtrap_enabled())
+		{
+		Dbl_set_sign(resultp1,sign_save);
+                Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    /* 
+	     * Since we cannot get an inexact denormalized result,
+	     * we can now return.
+	     */
+	    Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);
+	    Dbl_clear_signexponent(resultp1);
+	    Dbl_set_sign(resultp1,sign_save);
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    return(NOEXCEPTION);
+	    } /* end if(hidden...)... */
+	/* Fall through and round */
+	} /* end if(save >= 0)... */
+    else 
+	{
+	/* Subtract magnitudes */
+	Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);
+	if(Dbl_isone_hiddenoverflow(resultp1))
+	    {
+	    /* Prenormalization required. */
+	    Dbl_rightshiftby1_withextent(resultp2,extent,extent);
+	    Dbl_arithrightshiftby1(resultp1,resultp2);
+	    result_exponent++;
+	    } /* end if hiddenoverflow... */
+	} /* end else ...subtract magnitudes... */
+    
+    /* Round the result.  If the extension is all zeros,then the result is
+     * exact.  Otherwise round in the correct direction.  No underflow is
+     * possible. If a postnormalization is necessary, then the mantissa is
+     * all zeros so no shift is needed. */
+  round:
+    if(Ext_isnotzero(extent))
+	{
+	inexact = TRUE;
+	switch(Rounding_mode())
+	    {
+	    case ROUNDNEAREST: /* The default. */
+	    if(Ext_isone_sign(extent))
+		{
+		/* at least 1/2 ulp */
+		if(Ext_isnotzero_lower(extent)  ||
+		  Dbl_isone_lowmantissap2(resultp2))
+		    {
+		    /* either exactly half way and odd or more than 1/2ulp */
+		    Dbl_increment(resultp1,resultp2);
+		    }
+		}
+	    break;
+
+	    case ROUNDPLUS:
+	    if(Dbl_iszero_sign(resultp1))
+		{
+		/* Round up positive results */
+		Dbl_increment(resultp1,resultp2);
+		}
+	    break;
+	    
+	    case ROUNDMINUS:
+	    if(Dbl_isone_sign(resultp1))
+		{
+		/* Round down negative results */
+		Dbl_increment(resultp1,resultp2);
+		}
+	    
+	    case ROUNDZERO:;
+	    /* truncate is simple */
+	    } /* end switch... */
+	if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+    if(result_exponent == DBL_INFINITY_EXPONENT)
+        {
+        /* Overflow */
+        if(Is_overflowtrap_enabled())
+	    {
+	    Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+	    Dbl_copytoptr(resultp1,resultp2,dstptr);
+	    if (inexact)
+	    if (Is_inexacttrap_enabled())
+		return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+		else Set_inexactflag();
+	    return(OVERFLOWEXCEPTION);
+	    }
+        else
+	    {
+	    inexact = TRUE;
+	    Set_overflowflag();
+	    Dbl_setoverflow(resultp1,resultp2);
+	    }
+	}
+    else Dbl_set_exponent(resultp1,result_exponent);
+    Dbl_copytoptr(resultp1,resultp2,dstptr);
+    if(inexact) 
+	if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+	else Set_inexactflag();
+    return(NOEXCEPTION);
+    }
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/driver.c linux-2.4.20-pre2/arch/parisc/math-emu/driver.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/driver.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/driver.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,125 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ *  linux/arch/math-emu/driver.c.c
+ *
+ *	decodes and dispatches unimplemented FPU instructions
+ *
+ *  Copyright (C) 1999, 2000  Philipp Rumpf <prumpf@tux.org>
+ *  Copyright (C) 2001	      Hewlett-Packard <bame@debian.org>
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include "float.h"
+#include "math-emu.h"
+
+
+#define fptpos 31
+#define fpr1pos 10
+#define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))
+
+#define FPUDEBUG 0
+
+/* Format of the floating-point exception registers. */
+struct exc_reg {
+	unsigned int exception : 6;
+	unsigned int ei : 26;
+};
+
+/* Macros for grabbing bits of the instruction format from the 'ei'
+   field above. */
+/* Major opcode 0c and 0e */
+#define FP0CE_UID(i) (((i) >> 6) & 3)
+#define FP0CE_CLASS(i) (((i) >> 9) & 3)
+#define FP0CE_SUBOP(i) (((i) >> 13) & 7)
+#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
+#define FP0C_FORMAT(i) (((i) >> 11) & 3)
+#define FP0E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 0c, uid 2 (performance monitoring) */
+#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
+
+/* Major opcode 2e (fused operations).   */
+#define FP2E_SUBOP(i)  (((i) >> 5) & 1)
+#define FP2E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 26 (FMPYSUB) */
+/* Major opcode 06 (FMPYADD) */
+#define FPx6_FORMAT(i) ((i) & 0x1f)
+
+/* Flags and enable bits of the status word. */
+#define FPSW_FLAGS(w) ((w) >> 27)
+#define FPSW_ENABLE(w) ((w) & 0x1f)
+#define FPSW_V (1<<4)
+#define FPSW_Z (1<<3)
+#define FPSW_O (1<<2)
+#define FPSW_U (1<<1)
+#define FPSW_I (1<<0)
+
+/* Handle a floating point exception.  Return zero if the faulting
+   instruction can be completed successfully. */
+int
+handle_fpe(struct pt_regs *regs)
+{
+	extern void printbinary(unsigned long x, int nbits);
+	struct siginfo si;
+	unsigned int orig_sw, sw;
+	int signalcode;
+	/* need an intermediate copy of float regs because FPU emulation
+	 * code expects an artificial last entry which contains zero
+	 */
+	__u64 frcopy[33];
+
+	memcpy(frcopy, regs->fr, sizeof regs->fr);
+	frcopy[32] = 0;
+
+	memcpy(&orig_sw, frcopy, sizeof(orig_sw));
+
+	if (FPUDEBUG) {
+		printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n   ");
+		printbinary(orig_sw, 32);
+		printk(KERN_DEBUG "\n");
+	}
+
+	signalcode = decode_fpu(frcopy, 0x666);
+
+	/* Status word = FR0L. */
+	memcpy(&sw, frcopy, sizeof(sw));
+	if (FPUDEBUG) {
+		printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n",
+			signalcode >> 24, signalcode & 0xffffff);
+		printbinary(sw, 32);
+		printk(KERN_DEBUG "\n");
+	}
+
+	memcpy(regs->fr, frcopy, sizeof regs->fr);
+	if (signalcode != 0) {
+	    si.si_signo = signalcode >> 24;
+	    si.si_errno = 0;
+	    si.si_code = signalcode & 0xffffff;
+	    si.si_addr = (void *) regs->iaoq[0];
+	    force_sig_info(si.si_signo, &si, current);
+	    return -1;
+	}
+
+	return signalcode ? -1 : 0;
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fcnvff.c linux-2.4.20-pre2/arch/parisc/math-emu/fcnvff.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/fcnvff.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fcnvff.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,309 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvff.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Floating-point to Double Floating-point
+ *	Double Floating-point to Single Floating-point
+ *
+ *  External Interfaces:
+ *	dbl_to_sgl_fcnvff(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvff(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Single Floating-point to Double Floating-point 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvff(
+	    sgl_floating_point *srcptr,
+	    unsigned int *nullptr,
+	    dbl_floating_point *dstptr,
+	    unsigned int *status)
+{
+	register unsigned int src, resultp1, resultp2;
+	register int src_exponent;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src);
+	Dbl_allp1(resultp1) = Sgl_all(src);  /* set sign of result */
+	/* 
+ 	 * Test for NaN or infinity
+ 	 */
+	if (src_exponent == SGL_INFINITY_EXPONENT) {
+		/*
+		 * determine if NaN or infinity
+		 */
+		if (Sgl_iszero_mantissa(src)) {
+			/*
+			 * is infinity; want to return double infinity
+			 */
+			Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		else {
+			/* 
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(src)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(INVALIDEXCEPTION);
+				/* make NaN quiet */
+				else {
+					Set_invalidflag();
+					Sgl_set_quiet(src);
+				}
+			}
+			/* 
+			 * NaN is quiet, return as double NaN 
+			 */
+			Dbl_setinfinity_exponent(resultp1);
+			Sgl_to_dbl_mantissa(src,resultp1,resultp2);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+	/* 
+ 	 * Test for zero or denormalized
+ 	 */
+	if (src_exponent == 0) {
+		/*
+		 * determine if zero or denormalized
+		 */
+		if (Sgl_isnotzero_mantissa(src)) {
+			/*
+			 * is denormalized; want to normalize
+			 */
+			Sgl_clear_signexponent(src);
+			Sgl_leftshiftby1(src);
+			Sgl_normalize(src,src_exponent);
+			Sgl_to_dbl_exponent(src_exponent,resultp1);
+			Sgl_to_dbl_mantissa(src,resultp1,resultp2);
+		}
+		else {
+			Dbl_setzero_exponentmantissa(resultp1,resultp2);
+		}
+		Dbl_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * No special cases, just complete the conversion
+	 */
+	Sgl_to_dbl_exponent(src_exponent, resultp1);
+	Sgl_to_dbl_mantissa(Sgl_mantissa(src), resultp1,resultp2);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Floating-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvff(
+		    dbl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    sgl_floating_point *dstptr,
+		    unsigned int *status)
+{
+        register unsigned int srcp1, srcp2, result;
+        register int src_exponent, dest_exponent, dest_mantissa;
+        register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	register boolean lsb_odd = FALSE;
+	boolean is_tiny;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+        src_exponent = Dbl_exponent(srcp1);
+	Sgl_all(result) = Dbl_allp1(srcp1);  /* set sign of result */
+        /* 
+         * Test for NaN or infinity
+         */
+        if (src_exponent == DBL_INFINITY_EXPONENT) {
+                /*
+                 * determine if NaN or infinity
+                 */
+                if (Dbl_iszero_mantissa(srcp1,srcp2)) {
+                        /*
+                         * is infinity; want to return single infinity
+                         */
+                        Sgl_setinfinity_exponentmantissa(result);
+                        *dstptr = result;
+                        return(NOEXCEPTION);
+                }
+                /* 
+                 * is NaN; signaling or quiet?
+                 */
+                if (Dbl_isone_signaling(srcp1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        else {
+				Set_invalidflag();
+                        	/* make NaN quiet */
+                        	Dbl_set_quiet(srcp1);
+			}
+                }
+                /* 
+                 * NaN is quiet, return as single NaN 
+                 */
+                Sgl_setinfinity_exponent(result);
+		Sgl_set_mantissa(result,Dallp1(srcp1)<<3 | Dallp2(srcp2)>>29);
+		if (Sgl_iszero_mantissa(result)) Sgl_set_quiet(result);
+                *dstptr = result;
+                return(NOEXCEPTION);
+        }
+        /*
+         * Generate result
+         */
+        Dbl_to_sgl_exponent(src_exponent,dest_exponent);
+	if (dest_exponent > 0) {
+        	Dbl_to_sgl_mantissa(srcp1,srcp2,dest_mantissa,inexact,guardbit, 
+		stickybit,lsb_odd);
+	}
+	else {
+		if (Dbl_iszero_exponentmantissa(srcp1,srcp2)){
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                if (Is_underflowtrap_enabled()) {
+			Dbl_to_sgl_mantissa(srcp1,srcp2,dest_mantissa,inexact,
+			guardbit,stickybit,lsb_odd);
+                }
+		else {
+			/* compute result, determine inexact info,
+			 * and set Underflowflag if appropriate
+			 */
+			Dbl_to_sgl_denormalized(srcp1,srcp2,dest_exponent,
+			dest_mantissa,inexact,guardbit,stickybit,lsb_odd,
+			is_tiny);
+		}
+	}
+        /* 
+         * Now round result if not exact
+         */
+        if (inexact) {
+                switch (Rounding_mode()) {
+                        case ROUNDPLUS: 
+                                if (Sgl_iszero_sign(result)) dest_mantissa++;
+                                break;
+                        case ROUNDMINUS: 
+                                if (Sgl_isone_sign(result)) dest_mantissa++;
+                                break;
+                        case ROUNDNEAREST:
+                                if (guardbit) {
+                                   if (stickybit || lsb_odd) dest_mantissa++;
+                                   }
+                }
+        }
+        Sgl_set_exponentmantissa(result,dest_mantissa);
+
+        /*
+         * check for mantissa overflow after rounding
+         */
+        if ((dest_exponent>0 || Is_underflowtrap_enabled()) && 
+	    Sgl_isone_hidden(result)) dest_exponent++;
+
+        /* 
+         * Test for overflow
+         */
+        if (dest_exponent >= SGL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /* 
+                         * Check for gross overflow
+                         */
+                        if (dest_exponent >= SGL_INFINITY_EXPONENT+SGL_WRAP) 
+                        	return(UNIMPLEMENTEDEXCEPTION);
+                        
+                        /*
+                         * Adjust bias of result
+                         */
+			Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
+			*dstptr = result;
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return(OVERFLOWEXCEPTION|INEXACTEXCEPTION);
+			    else Set_inexactflag();
+                        return(OVERFLOWEXCEPTION);
+                }
+                Set_overflowflag();
+		inexact = TRUE;
+		/* set result to infinity or largest number */
+		Sgl_setoverflow(result);
+        }
+        /* 
+         * Test for underflow
+         */
+        else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /* 
+                         * Check for gross underflow
+                         */
+                        if (dest_exponent <= -(SGL_WRAP))
+                        	return(UNIMPLEMENTEDEXCEPTION);
+                        /*
+                         * Adjust bias of result
+                         */
+			Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+			*dstptr = result;
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return(UNDERFLOWEXCEPTION|INEXACTEXCEPTION);
+			    else Set_inexactflag();
+                        return(UNDERFLOWEXCEPTION);
+                }
+                 /* 
+                  * result is denormalized or signed zero
+                  */
+               if (inexact && is_tiny) Set_underflowflag();
+
+        }
+	else Sgl_set_exponent(result,dest_exponent);
+	*dstptr = result;
+        /* 
+         * Trap if inexact trap is enabled
+         */
+        if (inexact)
+        	if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+        	else Set_inexactflag();
+        return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fcnvfu.c linux-2.4.20-pre2/arch/parisc/math-emu/fcnvfu.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/fcnvfu.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fcnvfu.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,536 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvfu.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Floating-point to Unsigned Fixed-point Converts
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/************************************************************************
+ *  Floating-point to Unsigned Fixed-point Converts			*
+ ************************************************************************/
+
+/*
+ *  Single Floating-point to Single Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfu(
+			sgl_floating_point *srcptr,
+			unsigned int *nullptr,
+			unsigned int *dstptr,
+			unsigned int *status)
+{
+	register unsigned int src, result;
+	register int src_exponent;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP + 1) {
+		if (Sgl_isone_sign(src)) {
+			result = 0;
+		} else {
+			result = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Sgl_isone_sign(src)) {
+			result = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		Sgl_clear_signexponent_set_hidden(src);
+		Suint_from_sgl_mantissa(src,src_exponent,result);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				result++;
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				if (Sgl_isone_roundbit(src,src_exponent) &&
+				    (Sgl_isone_stickybit(src,src_exponent) ||
+				     (result & 1))) {
+			     		result++;
+				}
+				break;
+			}
+		}
+	} else {
+		result = 0;
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Sgl_iszero_sign(src)) {
+					result++;
+				}
+				break;
+			case ROUNDMINUS:
+				if (Sgl_isone_sign(src)) {
+					result = 0;
+					if (Is_invalidtrap_enabled()) {
+						return(INVALIDEXCEPTION);
+					}
+					Set_invalidflag();
+					inexact = FALSE;
+				}
+				break;
+			case ROUNDNEAREST:
+				if (src_exponent == -1 &&
+				    Sgl_isnotzero_mantissa(src)) {
+					if (Sgl_isone_sign(src)) {
+						result = 0;
+						if (Is_invalidtrap_enabled()) {
+							return(INVALIDEXCEPTION);
+						}
+						Set_invalidflag();
+						inexact = FALSE;
+					}
+			      		else result++;
+				}
+				break;
+			}
+		}
+	}
+	*dstptr = result;
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point to Double Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfu(
+		    sgl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    dbl_unsigned *dstptr,
+		    unsigned int *status)
+{
+	register int src_exponent;
+	register unsigned int src, resultp1, resultp2;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP + 1) {
+		if (Sgl_isone_sign(src)) {
+			resultp1 = resultp2 = 0;
+		} else {
+			resultp1 = resultp2 = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+    		Duint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Sgl_isone_sign(src)) {
+			resultp1 = resultp2 = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+    			Duint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Sgl_clear_signexponent_set_hidden(src);
+		Duint_from_sgl_mantissa(src,src_exponent,resultp1,resultp2);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				Duint_increment(resultp1,resultp2);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				if (Sgl_isone_roundbit(src,src_exponent) &&
+				    (Sgl_isone_stickybit(src,src_exponent) || 
+				     Duint_isone_lowp2(resultp2))) {
+					Duint_increment(resultp1,resultp2);
+				}
+				break;
+			}
+		}
+	} else {
+		Duint_setzero(resultp1,resultp2);
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Sgl_iszero_sign(src)) {
+					Duint_increment(resultp1,resultp2);
+				}
+				break;
+			case ROUNDMINUS:
+				if (Sgl_isone_sign(src)) {
+					resultp1 = resultp2 = 0;
+					if (Is_invalidtrap_enabled()) {
+						return(INVALIDEXCEPTION);
+					}
+					Set_invalidflag();
+					inexact = FALSE;
+				}
+				break;
+			case ROUNDNEAREST:
+				if (src_exponent == -1 &&
+				    Sgl_isnotzero_mantissa(src)) {
+					if (Sgl_isone_sign(src)) {
+						resultp1 = 0;
+						resultp2 = 0;
+						if (Is_invalidtrap_enabled()) {
+							return(INVALIDEXCEPTION);
+						}
+						Set_invalidflag();
+						inexact = FALSE;
+					}
+					else Duint_increment(resultp1,resultp2);
+				}
+			}
+		}
+	}
+	Duint_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr,
+		   unsigned int *dstptr, unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, result;
+	register int src_exponent;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP + 1) {
+		if (Dbl_isone_sign(srcp1)) {
+			result = 0;
+		} else {
+			result = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Dbl_isone_sign(srcp1)) {
+			result = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		Dbl_clear_signexponent_set_hidden(srcp1);
+		Suint_from_dbl_mantissa(srcp1,srcp2,src_exponent,result);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     result++;
+			     break;
+			case ROUNDMINUS: /* never negative */
+			     break;
+			case ROUNDNEAREST:
+			     if(Dbl_isone_roundbit(srcp1,srcp2,src_exponent) &&
+				(Dbl_isone_stickybit(srcp1,srcp2,src_exponent)||
+				 result&1))
+				   result++;
+			     break;
+			}
+			/* check for overflow */
+			if (result == 0) {
+				result = 0xffffffff;
+				if (Is_invalidtrap_enabled()) {
+					return(INVALIDEXCEPTION);
+				}
+				Set_invalidflag();
+				*dstptr = result;
+				return(NOEXCEPTION);
+			}
+		}
+	} else {
+		result = 0;
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Dbl_iszero_sign(srcp1)) result++;
+				break;
+			case ROUNDMINUS:
+				if (Dbl_isone_sign(srcp1)) {
+					result = 0;
+					if (Is_invalidtrap_enabled()) {
+						return(INVALIDEXCEPTION);
+					}
+					Set_invalidflag();
+					inexact = FALSE;
+				}
+				break;
+			case ROUNDNEAREST:
+				if (src_exponent == -1 &&
+				    Dbl_isnotzero_mantissa(srcp1,srcp2))
+					if (Dbl_isone_sign(srcp1)) {
+						result = 0;
+						if (Is_invalidtrap_enabled()) {
+							return(INVALIDEXCEPTION);
+						}
+						Set_invalidflag();
+						inexact = FALSE;
+					}
+					else result++;
+			}
+		}
+	}
+	*dstptr = result;
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Double Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr,
+		   dbl_unsigned * dstptr, unsigned int *status)
+{
+	register int src_exponent;
+	register unsigned int srcp1, srcp2, resultp1, resultp2;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP + 1) {
+		if (Dbl_isone_sign(srcp1)) {
+			resultp1 = resultp2 = 0;
+		} else {
+			resultp1 = resultp2 = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+    		Duint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+ 
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Dbl_isone_sign(srcp1)) {
+			resultp1 = resultp2 = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+    			Duint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Dbl_clear_signexponent_set_hidden(srcp1);
+		Duint_from_dbl_mantissa(srcp1,srcp2,src_exponent,resultp1,
+		  resultp2);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				Duint_increment(resultp1,resultp2);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				if(Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+				  if(Dbl_isone_stickybit(srcp1,srcp2,src_exponent) || 
+				     Duint_isone_lowp2(resultp2))
+					Duint_increment(resultp1,resultp2);
+			} 
+		}
+	} else {
+		Duint_setzero(resultp1,resultp2);
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Dbl_iszero_sign(srcp1)) {
+					Duint_increment(resultp1,resultp2);
+				}
+				break;
+			case ROUNDMINUS:
+				if (Dbl_isone_sign(srcp1)) {
+					resultp1 = resultp2 = 0;
+					if (Is_invalidtrap_enabled()) {
+						return(INVALIDEXCEPTION);
+					}
+					Set_invalidflag();
+					inexact = FALSE;
+				}
+				break;
+			case ROUNDNEAREST:
+				if (src_exponent == -1 &&
+				    Dbl_isnotzero_mantissa(srcp1,srcp2))
+					if (Dbl_iszero_sign(srcp1)) {
+						Duint_increment(resultp1,resultp2);
+					} else {
+						resultp1 = 0;
+						resultp2 = 0;
+						if (Is_invalidtrap_enabled()) {
+							return(INVALIDEXCEPTION);
+						}
+						Set_invalidflag();
+						inexact = FALSE;
+					}
+			}
+		}
+	}
+	Duint_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fcnvfut.c linux-2.4.20-pre2/arch/parisc/math-emu/fcnvfut.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/fcnvfut.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fcnvfut.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,332 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvfut.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Floating-point to Unsigned Fixed-point Converts with Truncation
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvfut(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvfut(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvfut(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvfut(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/************************************************************************
+ *  Floating-point to Unsigned Fixed-point Converts with Truncation	*
+ ************************************************************************/
+
+/*
+ *  Convert single floating-point to single fixed-point format
+ *  with truncated result
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr,
+		    unsigned int *dstptr, unsigned int *status)
+{
+	register unsigned int src, result;
+	register int src_exponent;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP + 1) {
+		if (Sgl_isone_sign(src)) {
+			result = 0;
+		} else {
+			result = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Sgl_isone_sign(src)) {
+			result = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		Sgl_clear_signexponent_set_hidden(src);
+		Suint_from_sgl_mantissa(src,src_exponent,result);
+		*dstptr = result;
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		*dstptr = 0;
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point to Double Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr,
+		    dbl_unsigned * dstptr, unsigned int *status)
+{
+	register int src_exponent;
+	register unsigned int src, resultp1, resultp2;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP + 1) {
+		if (Sgl_isone_sign(src)) {
+			resultp1 = resultp2 = 0;
+		} else {
+			resultp1 = resultp2 = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+    		Duint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Sgl_isone_sign(src)) {
+			resultp1 = resultp2 = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+    			Duint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Sgl_clear_signexponent_set_hidden(src);
+		Duint_from_sgl_mantissa(src,src_exponent,resultp1,resultp2);
+		Duint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		Duint_setzero(resultp1,resultp2);
+		Duint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfut (dbl_floating_point * srcptr, unsigned int *nullptr,
+		    unsigned int *dstptr, unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, result;
+	register int src_exponent;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP + 1) {
+		if (Dbl_isone_sign(srcp1)) {
+			result = 0;
+		} else {
+			result = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Dbl_isone_sign(srcp1)) {
+			result = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		Dbl_clear_signexponent_set_hidden(srcp1);
+		Suint_from_dbl_mantissa(srcp1,srcp2,src_exponent,result);
+		*dstptr = result;
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		*dstptr = 0;
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Double Unsigned Fixed 
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfut (dbl_floating_point * srcptr, unsigned int *nullptr,
+		    dbl_unsigned * dstptr, unsigned int *status)
+{
+	register int src_exponent;
+	register unsigned int srcp1, srcp2, resultp1, resultp2;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP + 1) {
+		if (Dbl_isone_sign(srcp1)) {
+			resultp1 = resultp2 = 0;
+		} else {
+			resultp1 = resultp2 = 0xffffffff;
+		}
+		if (Is_invalidtrap_enabled()) {
+			return(INVALIDEXCEPTION);
+		}
+		Set_invalidflag();
+    		Duint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		/* 
+		 * Check sign.
+		 * If negative, trap unimplemented.
+		 */
+		if (Dbl_isone_sign(srcp1)) {
+			resultp1 = resultp2 = 0;
+			if (Is_invalidtrap_enabled()) {
+				return(INVALIDEXCEPTION);
+			}
+			Set_invalidflag();
+    			Duint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Dbl_clear_signexponent_set_hidden(srcp1);
+		Duint_from_dbl_mantissa(srcp1,srcp2,src_exponent,
+		  resultp1,resultp2);
+		Duint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		Duint_setzero(resultp1,resultp2);
+		Duint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fcnvfx.c linux-2.4.20-pre2/arch/parisc/math-emu/fcnvfx.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/fcnvfx.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fcnvfx.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,501 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvfx.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Floating-point to Single Fixed-point
+ *	Single Floating-point to Double Fixed-point 
+ *	Double Floating-point to Single Fixed-point 
+ *	Double Floating-point to Double Fixed-point 
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Single Floating-point to Single Fixed-point 
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfx(
+		    sgl_floating_point *srcptr,
+		    sgl_floating_point *nullptr,
+		    int *dstptr,
+		    sgl_floating_point *status)
+{
+	register unsigned int src, temp;
+	register int src_exponent, result;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > SGL_FX_MAX_EXP + 1) || 
+		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+                        if (Sgl_iszero_sign(src)) result = 0x7fffffff;
+                        else result = 0x80000000; 
+
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+       		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		temp = src;
+		Sgl_clear_signexponent_set_hidden(temp);
+		Int_from_sgl_mantissa(temp,src_exponent);
+		if (Sgl_isone_sign(src))  result = -Sgl_all(temp);
+		else result = Sgl_all(temp);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Sgl_iszero_sign(src)) result++;
+			     break;
+			case ROUNDMINUS:
+			     if (Sgl_isone_sign(src)) result--;
+			     break;
+			case ROUNDNEAREST:
+			     if (Sgl_isone_roundbit(src,src_exponent)) {
+			        if (Sgl_isone_stickybit(src,src_exponent) 
+				|| (Sgl_isone_lowmantissa(temp)))
+			           if (Sgl_iszero_sign(src)) result++;
+			           else result--;
+			     }
+			} 
+		}
+	}
+	else {
+		result = 0;
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Sgl_iszero_sign(src)) result++;
+			     break;
+			case ROUNDMINUS:
+			     if (Sgl_isone_sign(src)) result--;
+			     break;
+			case ROUNDNEAREST:
+			     if (src_exponent == -1)
+			        if (Sgl_isnotzero_mantissa(src))
+			           if (Sgl_iszero_sign(src)) result++;
+			           else result--;
+			} 
+		}
+	}
+	*dstptr = result;
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point to Double Fixed-point 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfx(
+		sgl_floating_point *srcptr,
+		unsigned int *nullptr,
+		dbl_integer *dstptr,
+		unsigned int *status)
+{
+	register int src_exponent, resultp1;
+	register unsigned int src, temp, resultp2;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
+		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+                        if (Sgl_iszero_sign(src)) {
+                              resultp1 = 0x7fffffff;
+			      resultp2 = 0xffffffff;
+			}
+                        else {
+			    resultp1 = 0x80000000; 
+			    resultp2 = 0;
+			}
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+    		        Dint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Dint_set_minint(resultp1,resultp2);
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		temp = src;
+		Sgl_clear_signexponent_set_hidden(temp);
+		Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
+		if (Sgl_isone_sign(src)) {
+			Dint_setone_sign(resultp1,resultp2);
+		}
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Sgl_iszero_sign(src)) {
+				Dint_increment(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDMINUS:
+                             if (Sgl_isone_sign(src)) {
+				Dint_decrement(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDNEAREST:
+                             if (Sgl_isone_roundbit(src,src_exponent))
+                                if (Sgl_isone_stickybit(src,src_exponent) || 
+				(Dint_isone_lowp2(resultp2)))
+				   if (Sgl_iszero_sign(src)) {
+				      Dint_increment(resultp1,resultp2);
+				   }
+                                   else {
+				      Dint_decrement(resultp1,resultp2);
+				   }
+                        }
+                }
+        }
+	else {
+		Dint_setzero(resultp1,resultp2);
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Sgl_iszero_sign(src)) {
+				Dint_increment(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDMINUS:
+                             if (Sgl_isone_sign(src)) {
+				Dint_decrement(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDNEAREST:
+                             if (src_exponent == -1)
+                                if (Sgl_isnotzero_mantissa(src))
+                                   if (Sgl_iszero_sign(src)) {
+				      Dint_increment(resultp1,resultp2);
+				   }
+                                   else {
+				      Dint_decrement(resultp1,resultp2);
+				   }
+			}
+		}
+	}
+	Dint_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Fixed-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfx(
+		    dbl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    int *dstptr,
+		    unsigned int *status)
+{
+	register unsigned int srcp1,srcp2, tempp1,tempp2;
+	register int src_exponent, result;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP) {
+		/* check for MININT */
+		if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
+                        if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
+                        else result = 0x80000000; 
+
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		tempp1 = srcp1;
+		tempp2 = srcp2;
+		Dbl_clear_signexponent_set_hidden(tempp1);
+		Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
+		if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
+			result = -Dbl_allp1(tempp1);
+		else result = Dbl_allp1(tempp1);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+                        inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Dbl_iszero_sign(srcp1)) result++;
+                             break;
+                        case ROUNDMINUS:
+                             if (Dbl_isone_sign(srcp1)) result--;
+                             break;
+                        case ROUNDNEAREST:
+                             if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+                                if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) || 
+				(Dbl_isone_lowmantissap1(tempp1)))
+                                   if (Dbl_iszero_sign(srcp1)) result++;
+                                   else result--;
+                        } 
+			/* check for overflow */
+			if ((Dbl_iszero_sign(srcp1) && result < 0) ||
+			    (Dbl_isone_sign(srcp1) && result > 0)) {
+			        
+                          if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
+                          else result = 0x80000000; 
+
+	                  if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                          }
+                          Set_invalidflag();
+			  *dstptr = result;
+			  return(NOEXCEPTION);
+			}
+                }
+	}
+	else {
+		result = 0;
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+                        inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Dbl_iszero_sign(srcp1)) result++;
+                             break;
+                        case ROUNDMINUS:
+                             if (Dbl_isone_sign(srcp1)) result--;
+                             break;
+                        case ROUNDNEAREST:
+                             if (src_exponent == -1)
+                                if (Dbl_isnotzero_mantissa(srcp1,srcp2))
+                                   if (Dbl_iszero_sign(srcp1)) result++;
+                                   else result--;
+			}
+                }
+	}
+	*dstptr = result;
+        if (inexact) {
+                if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+        }
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Double Fixed-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfx(
+		    dbl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    dbl_integer *dstptr,
+		    unsigned int *status)
+{
+	register int src_exponent, resultp1;
+	register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
+		Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
+                        if (Dbl_iszero_sign(srcp1)) {
+                              resultp1 = 0x7fffffff;
+			      resultp2 = 0xffffffff;
+			}
+                        else {
+			    resultp1 = 0x80000000; 
+			    resultp2 = 0;
+			}
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+    		        Dint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+ 
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		tempp1 = srcp1;
+		tempp2 = srcp2;
+		Dbl_clear_signexponent_set_hidden(tempp1);
+		Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,resultp1,
+		resultp2);
+		if (Dbl_isone_sign(srcp1)) {
+			Dint_setone_sign(resultp1,resultp2);
+		}
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+                        inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Dbl_iszero_sign(srcp1)) {
+				Dint_increment(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDMINUS:
+                             if (Dbl_isone_sign(srcp1)) {
+				Dint_decrement(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDNEAREST:
+                             if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+                                if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) || 
+				(Dint_isone_lowp2(resultp2)))
+                                   if (Dbl_iszero_sign(srcp1)) {
+				      Dint_increment(resultp1,resultp2);
+				   }
+                                   else {
+				      Dint_decrement(resultp1,resultp2);
+				   }
+                        } 
+                }
+	}
+	else {
+		Dint_setzero(resultp1,resultp2);
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+                        inexact = TRUE;
+                        /*  round result  */
+                        switch (Rounding_mode()) {
+                        case ROUNDPLUS:
+                             if (Dbl_iszero_sign(srcp1)) {
+				Dint_increment(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDMINUS:
+                             if (Dbl_isone_sign(srcp1)) {
+				Dint_decrement(resultp1,resultp2);
+			     }
+                             break;
+                        case ROUNDNEAREST:
+                             if (src_exponent == -1)
+                                if (Dbl_isnotzero_mantissa(srcp1,srcp2))
+                                   if (Dbl_iszero_sign(srcp1)) {
+				      Dint_increment(resultp1,resultp2);
+				   }
+                                   else {
+				      Dint_decrement(resultp1,resultp2);
+				   }
+			}
+                }
+	}
+	Dint_copytoptr(resultp1,resultp2,dstptr);
+        if (inexact) {
+                if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+        	else Set_inexactflag();
+        }
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fcnvfxt.c linux-2.4.20-pre2/arch/parisc/math-emu/fcnvfxt.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/fcnvfxt.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fcnvfxt.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,328 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvfxt.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Floating-point to Single Fixed-point /w truncated result
+ *	Single Floating-point to Double Fixed-point /w truncated result
+ *	Double Floating-point to Single Fixed-point /w truncated result
+ *	Double Floating-point to Double Fixed-point /w truncated result
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Convert single floating-point to single fixed-point format
+ *  with truncated result
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfxt(
+		    sgl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    int *dstptr,
+		    unsigned int *status)
+{
+	register unsigned int src, temp;
+	register int src_exponent, result;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > SGL_FX_MAX_EXP + 1) || 
+		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+                        if (Sgl_iszero_sign(src)) result = 0x7fffffff;
+                        else result = 0x80000000; 
+
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		temp = src;
+		Sgl_clear_signexponent_set_hidden(temp);
+		Int_from_sgl_mantissa(temp,src_exponent);
+		if (Sgl_isone_sign(src))  result = -Sgl_all(temp);
+		else result = Sgl_all(temp);
+		*dstptr = result;
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		*dstptr = 0;
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point to Double Fixed-point 
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfxt(
+		    sgl_floating_point *srcptr,
+		    unsigned int *nullptr,
+		    dbl_integer *dstptr,
+		    unsigned int *status)
+{
+	register int src_exponent, resultp1;
+	register unsigned int src, temp, resultp2;
+
+	src = *srcptr;
+	src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
+		Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+                        if (Sgl_iszero_sign(src)) {
+                              resultp1 = 0x7fffffff;
+			      resultp2 = 0xffffffff;
+			}
+                        else {
+			    resultp1 = 0x80000000; 
+			    resultp2 = 0;
+			}
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+    		        Dint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+		Dint_set_minint(resultp1,resultp2);
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		temp = src;
+		Sgl_clear_signexponent_set_hidden(temp);
+		Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
+		if (Sgl_isone_sign(src)) {
+			Dint_setone_sign(resultp1,resultp2);
+		}
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		Dint_setzero(resultp1,resultp2);
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Single Fixed-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfxt(
+			dbl_floating_point *srcptr,
+			unsigned int *nullptr,
+			int *dstptr,
+			unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, tempp1, tempp2;
+	register int src_exponent, result;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > SGL_FX_MAX_EXP) {
+		/* check for MININT */
+		if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
+                        if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
+                        else result = 0x80000000; 
+
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		tempp1 = srcp1;
+		tempp2 = srcp2;
+		Dbl_clear_signexponent_set_hidden(tempp1);
+		Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
+		if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
+			result = -Dbl_allp1(tempp1);
+		else result = Dbl_allp1(tempp1);
+		*dstptr = result;
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		*dstptr = 0;
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point to Double Fixed-point 
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfxt(
+			dbl_floating_point *srcptr,
+			unsigned int *nullptr,
+			dbl_integer *dstptr,
+			unsigned int *status)
+{
+	register int src_exponent, resultp1;
+	register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+	src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+	/* 
+	 * Test for overflow
+	 */
+	if (src_exponent > DBL_FX_MAX_EXP) {
+		/* check for MININT */
+		if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
+		Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
+                        if (Dbl_iszero_sign(srcp1)) {
+                              resultp1 = 0x7fffffff;
+			      resultp2 = 0xffffffff;
+			}
+                        else {
+			    resultp1 = 0x80000000; 
+			    resultp2 = 0;
+			}
+	                if (Is_invalidtrap_enabled()) {
+                            return(INVALIDEXCEPTION);
+                        }
+                        Set_invalidflag();
+    		        Dint_copytoptr(resultp1,resultp2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		tempp1 = srcp1;
+		tempp2 = srcp2;
+		Dbl_clear_signexponent_set_hidden(tempp1);
+		Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,
+		resultp1,resultp2);
+		if (Dbl_isone_sign(srcp1)) {
+			Dint_setone_sign(resultp1,resultp2);
+		}
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	else {
+		Dint_setzero(resultp1,resultp2);
+		Dint_copytoptr(resultp1,resultp2,dstptr);
+
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+			else Set_inexactflag();
+		}
+	}
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fcnvuf.c linux-2.4.20-pre2/arch/parisc/math-emu/fcnvuf.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/fcnvuf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fcnvuf.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,318 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvuf.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Fixed point to Floating-point Converts
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvuf(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvuf(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/************************************************************************
+ *  Fixed point to Floating-point Converts				*
+ ************************************************************************/
+
+/*
+ *  Convert Single Unsigned Fixed to Single Floating-point format
+ */
+
+int
+sgl_to_sgl_fcnvuf(
+			unsigned int *srcptr,
+			unsigned int *nullptr,
+			sgl_floating_point *dstptr,
+			unsigned int *status)
+{
+	register unsigned int src, result = 0;
+	register int dst_exponent;
+
+	src = *srcptr;
+
+	/* Check for zero */ 
+	if (src == 0) { 
+	       	Sgl_setzero(result); 
+		*dstptr = result;
+	       	return(NOEXCEPTION); 
+	} 
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	/*
+	 * Check word for most significant bit set.  Returns
+	 * a value in dst_exponent indicating the bit position,
+	 * between -1 and 30.
+	 */
+	Find_ms_one_bit(src,dst_exponent);
+	/*  left justify source, with msb at bit position 0  */
+	src <<= dst_exponent+1;
+	Sgl_set_mantissa(result, src >> SGL_EXP_LENGTH);
+	Sgl_set_exponent(result, 30+SGL_BIAS - dst_exponent);
+
+	/* check for inexact */
+	if (Suint_isinexact_to_sgl(src)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				Sgl_increment(result);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				Sgl_roundnearest_from_suint(src,result);
+				break;
+		}
+		if (Is_inexacttrap_enabled()) {
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Unsigned Fixed to Double Floating-point 
+ */
+
+int
+sgl_to_dbl_fcnvuf(
+			unsigned int *srcptr,
+			unsigned int *nullptr,
+			dbl_floating_point *dstptr,
+			unsigned int *status)
+{
+	register int dst_exponent;
+	register unsigned int src, resultp1 = 0, resultp2 = 0;
+
+	src = *srcptr;
+
+	/* Check for zero */
+	if (src == 0) {
+	       	Dbl_setzero(resultp1,resultp2);
+	       	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	       	return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	/*
+	 * Check word for most significant bit set.  Returns
+	 * a value in dst_exponent indicating the bit position,
+	 * between -1 and 30.
+	 */
+	Find_ms_one_bit(src,dst_exponent);
+	/*  left justify source, with msb at bit position 0  */
+	src <<= dst_exponent+1;
+	Dbl_set_mantissap1(resultp1, src >> DBL_EXP_LENGTH);
+	Dbl_set_mantissap2(resultp2, src << (32-DBL_EXP_LENGTH));
+	Dbl_set_exponent(resultp1, (30+DBL_BIAS) - dst_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Unsigned Fixed to Single Floating-point 
+ */
+
+int
+dbl_to_sgl_fcnvuf(
+			dbl_unsigned *srcptr,
+			unsigned int *nullptr,
+			sgl_floating_point *dstptr,
+			unsigned int *status)
+{
+	int dst_exponent;
+	unsigned int srcp1, srcp2, result = 0;
+
+	Duint_copyfromptr(srcptr,srcp1,srcp2);
+
+	/* Check for zero */
+	if (srcp1 == 0 && srcp2 == 0) {
+	       	Sgl_setzero(result);
+	       	*dstptr = result;
+	       	return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	if (srcp1 == 0) {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp2,dst_exponent);
+		/*  left justify source, with msb at bit position 0  */
+		srcp1 = srcp2 << dst_exponent+1;    
+		srcp2 = 0;
+		/*
+		 *  since msb set is in second word, need to 
+		 *  adjust bit position count
+		 */
+		dst_exponent += 32;
+	}
+	else {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 *
+		 */
+		Find_ms_one_bit(srcp1,dst_exponent);
+		/*  left justify source, with msb at bit position 0  */
+		if (dst_exponent >= 0) {
+			Variable_shift_double(srcp1,srcp2,(31-dst_exponent),
+			 srcp1); 
+			srcp2 <<= dst_exponent+1;
+		}
+	}
+	Sgl_set_mantissa(result, srcp1 >> SGL_EXP_LENGTH);
+	Sgl_set_exponent(result, (62+SGL_BIAS) - dst_exponent);
+
+	/* check for inexact */
+	if (Duint_isinexact_to_sgl(srcp1,srcp2)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				Sgl_increment(result);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				Sgl_roundnearest_from_duint(srcp1,srcp2,result);
+				break;
+		}
+		if (Is_inexacttrap_enabled()) {
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Unsigned Fixed to Double Floating-point 
+ */
+
+int
+dbl_to_dbl_fcnvuf(
+		    dbl_unsigned *srcptr,
+		    unsigned int *nullptr,
+		    dbl_floating_point *dstptr,
+		    unsigned int *status)
+{
+	register int dst_exponent;
+	register unsigned int srcp1, srcp2, resultp1 = 0, resultp2 = 0;
+
+	Duint_copyfromptr(srcptr,srcp1,srcp2);
+
+	/* Check for zero */
+	if (srcp1 == 0 && srcp2 ==0) {
+	       	Dbl_setzero(resultp1,resultp2);
+	       	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	       	return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	if (srcp1 == 0) {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp2,dst_exponent);
+		/*  left justify source, with msb at bit position 0  */
+		srcp1 = srcp2 << dst_exponent+1;
+		srcp2 = 0;
+		/*
+		 *  since msb set is in second word, need to 
+		 *  adjust bit position count
+		 */
+		dst_exponent += 32;
+	}
+	else {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp1,dst_exponent);
+		/*  left justify source, with msb at bit position 0  */
+		if (dst_exponent >= 0) {
+			Variable_shift_double(srcp1,srcp2,(31-dst_exponent),
+			 srcp1); 
+			srcp2 <<= dst_exponent+1;
+		}
+	}
+	Dbl_set_mantissap1(resultp1, srcp1 >> DBL_EXP_LENGTH);
+	Shiftdouble(srcp1,srcp2,DBL_EXP_LENGTH,resultp2);
+	Dbl_set_exponent(resultp1, (62+DBL_BIAS) - dst_exponent);
+
+	/* check for inexact */
+	if (Duint_isinexact_to_dbl(srcp2)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				Dbl_increment(resultp1,resultp2);
+				break;
+			case ROUNDMINUS: /* never negative */
+				break;
+			case ROUNDNEAREST:
+				Dbl_roundnearest_from_duint(srcp2,resultp1,
+				resultp2);
+				break;
+		}
+		if (Is_inexacttrap_enabled()) {
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
+
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fcnvxf.c linux-2.4.20-pre2/arch/parisc/math-emu/fcnvxf.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/fcnvxf.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fcnvxf.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,386 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fcnvxf.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Fixed-point to Single Floating-point
+ *	Single Fixed-point to Double Floating-point 
+ *	Double Fixed-point to Single Floating-point 
+ *	Double Fixed-point to Double Floating-point 
+ *
+ *  External Interfaces:
+ *	dbl_to_dbl_fcnvxf(srcptr,nullptr,dstptr,status)
+ *	dbl_to_sgl_fcnvxf(srcptr,nullptr,dstptr,status)
+ *	sgl_to_dbl_fcnvxf(srcptr,nullptr,dstptr,status)
+ *	sgl_to_sgl_fcnvxf(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Convert single fixed-point to single floating-point format
+ */
+
+int
+sgl_to_sgl_fcnvxf(
+		    int *srcptr,
+		    unsigned int *nullptr,
+		    sgl_floating_point *dstptr,
+		    unsigned int *status)
+{
+	register int src, dst_exponent;
+	register unsigned int result = 0;
+
+	src = *srcptr;
+	/* 
+	 * set sign bit of result and get magnitude of source 
+	 */
+	if (src < 0) {
+		Sgl_setone_sign(result);  
+		Int_negate(src);
+	}
+	else {
+		Sgl_setzero_sign(result);
+        	/* Check for zero */ 
+        	if (src == 0) { 
+                	Sgl_setzero(result); 
+			*dstptr = result;
+                	return(NOEXCEPTION); 
+        	} 
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	/*
+	 * Check word for most significant bit set.  Returns
+	 * a value in dst_exponent indicating the bit position,
+	 * between -1 and 30.
+	 */
+	Find_ms_one_bit(src,dst_exponent);
+	/*  left justify source, with msb at bit position 1  */
+	if (dst_exponent >= 0) src <<= dst_exponent;
+	else src = 1 << 30;
+	Sgl_set_mantissa(result, src >> (SGL_EXP_LENGTH-1));
+	Sgl_set_exponent(result, 30+SGL_BIAS - dst_exponent);
+
+	/* check for inexact */
+	if (Int_isinexact_to_sgl(src)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) 
+					Sgl_increment(result);
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) 
+					Sgl_increment(result);
+				break;
+			case ROUNDNEAREST:
+				Sgl_roundnearest_from_int(src,result);
+		}
+		if (Is_inexacttrap_enabled()) {
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Fixed-point to Double Floating-point 
+ */
+
+int
+sgl_to_dbl_fcnvxf(
+		    int *srcptr,
+		    unsigned int *nullptr,
+		    dbl_floating_point *dstptr,
+		    unsigned int *status)
+{
+	register int src, dst_exponent;
+	register unsigned int resultp1 = 0, resultp2 = 0;
+
+	src = *srcptr;
+	/* 
+	 * set sign bit of result and get magnitude of source 
+	 */
+	if (src < 0) {
+		Dbl_setone_sign(resultp1);  
+		Int_negate(src);
+	}
+	else {
+		Dbl_setzero_sign(resultp1);
+        	/* Check for zero */
+        	if (src == 0) {
+                	Dbl_setzero(resultp1,resultp2);
+                	Dbl_copytoptr(resultp1,resultp2,dstptr);
+                	return(NOEXCEPTION);
+        	}
+	}
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	/*
+	 * Check word for most significant bit set.  Returns
+	 * a value in dst_exponent indicating the bit position,
+	 * between -1 and 30.
+	 */
+	Find_ms_one_bit(src,dst_exponent);
+	/*  left justify source, with msb at bit position 1  */
+	if (dst_exponent >= 0) src <<= dst_exponent;
+	else src = 1 << 30;
+	Dbl_set_mantissap1(resultp1, src >> DBL_EXP_LENGTH - 1);
+	Dbl_set_mantissap2(resultp2, src << (33-DBL_EXP_LENGTH));
+	Dbl_set_exponent(resultp1, (30+DBL_BIAS) - dst_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Fixed-point to Single Floating-point 
+ */
+
+int
+dbl_to_sgl_fcnvxf(
+			dbl_integer *srcptr,
+			unsigned int *nullptr,
+			sgl_floating_point *dstptr,
+			unsigned int *status)
+{
+	int dst_exponent, srcp1;
+	unsigned int result = 0, srcp2;
+
+	Dint_copyfromptr(srcptr,srcp1,srcp2);
+	/* 
+	 * set sign bit of result and get magnitude of source 
+	 */
+	if (srcp1 < 0) {
+		Sgl_setone_sign(result);  
+		Dint_negate(srcp1,srcp2);
+	}
+	else {
+		Sgl_setzero_sign(result);
+        	/* Check for zero */
+        	if (srcp1 == 0 && srcp2 == 0) {
+                	Sgl_setzero(result);
+                	*dstptr = result;
+                	return(NOEXCEPTION);
+		}
+        }
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	if (srcp1 == 0) {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp2,dst_exponent);
+		/*  left justify source, with msb at bit position 1  */
+		if (dst_exponent >= 0) {
+			srcp1 = srcp2 << dst_exponent;    
+			srcp2 = 0;
+		}
+		else {
+			srcp1 = srcp2 >> 1;
+			srcp2 <<= 31; 
+		}
+		/*
+		 *  since msb set is in second word, need to 
+		 *  adjust bit position count
+		 */
+		dst_exponent += 32;
+	}
+	else {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 *
+		 */
+		Find_ms_one_bit(srcp1,dst_exponent);
+		/*  left justify source, with msb at bit position 1  */
+		if (dst_exponent > 0) {
+			Variable_shift_double(srcp1,srcp2,(32-dst_exponent),
+			 srcp1); 
+			srcp2 <<= dst_exponent;
+		}
+		/*
+		 * If dst_exponent = 0, we don't need to shift anything.
+		 * If dst_exponent = -1, src = - 2**63 so we won't need to 
+		 * shift srcp2.
+		 */
+		else srcp1 >>= -(dst_exponent);
+	}
+	Sgl_set_mantissa(result, srcp1 >> SGL_EXP_LENGTH - 1);
+	Sgl_set_exponent(result, (62+SGL_BIAS) - dst_exponent);
+
+	/* check for inexact */
+	if (Dint_isinexact_to_sgl(srcp1,srcp2)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) 
+					Sgl_increment(result);
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) 
+					Sgl_increment(result);
+				break;
+			case ROUNDNEAREST:
+				Sgl_roundnearest_from_dint(srcp1,srcp2,result);
+		}
+		if (Is_inexacttrap_enabled()) {
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Fixed-point to Double Floating-point 
+ */
+
+int
+dbl_to_dbl_fcnvxf(
+		    dbl_integer *srcptr,
+		    unsigned int *nullptr,
+		    dbl_floating_point *dstptr,
+		    unsigned int *status)
+{
+	register int srcp1, dst_exponent;
+	register unsigned int srcp2, resultp1 = 0, resultp2 = 0;
+
+	Dint_copyfromptr(srcptr,srcp1,srcp2);
+	/* 
+	 * set sign bit of result and get magnitude of source 
+	 */
+	if (srcp1 < 0) {
+		Dbl_setone_sign(resultp1);
+		Dint_negate(srcp1,srcp2);
+	}
+	else {
+		Dbl_setzero_sign(resultp1);
+        	/* Check for zero */
+        	if (srcp1 == 0 && srcp2 ==0) {
+                	Dbl_setzero(resultp1,resultp2);
+                	Dbl_copytoptr(resultp1,resultp2,dstptr);
+                	return(NOEXCEPTION);
+		}
+        }
+	/*
+	 * Generate exponent and normalized mantissa
+	 */
+	dst_exponent = 16;    /* initialize for normalization */
+	if (srcp1 == 0) {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp2,dst_exponent);
+		/*  left justify source, with msb at bit position 1  */
+		if (dst_exponent >= 0) {
+			srcp1 = srcp2 << dst_exponent;    
+			srcp2 = 0;
+		}
+		else {
+			srcp1 = srcp2 >> 1;
+			srcp2 <<= 31;
+		}
+		/*
+		 *  since msb set is in second word, need to 
+		 *  adjust bit position count
+		 */
+		dst_exponent += 32;
+	}
+	else {
+		/*
+		 * Check word for most significant bit set.  Returns
+		 * a value in dst_exponent indicating the bit position,
+		 * between -1 and 30.
+		 */
+		Find_ms_one_bit(srcp1,dst_exponent);
+		/*  left justify source, with msb at bit position 1  */
+		if (dst_exponent > 0) {
+			Variable_shift_double(srcp1,srcp2,(32-dst_exponent),
+			 srcp1); 
+			srcp2 <<= dst_exponent;
+		}
+		/*
+		 * If dst_exponent = 0, we don't need to shift anything.
+		 * If dst_exponent = -1, src = - 2**63 so we won't need to 
+		 * shift srcp2.
+		 */
+		else srcp1 >>= -(dst_exponent);
+	}
+	Dbl_set_mantissap1(resultp1, srcp1 >> (DBL_EXP_LENGTH-1));
+	Shiftdouble(srcp1,srcp2,DBL_EXP_LENGTH-1,resultp2);
+	Dbl_set_exponent(resultp1, (62+DBL_BIAS) - dst_exponent);
+
+	/* check for inexact */
+	if (Dint_isinexact_to_dbl(srcp2)) {
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Dbl_iszero_sign(resultp1)) {
+					Dbl_increment(resultp1,resultp2);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Dbl_isone_sign(resultp1)) {
+					Dbl_increment(resultp1,resultp2);
+				}
+				break;
+			case ROUNDNEAREST:
+				Dbl_roundnearest_from_dint(srcp2,resultp1,
+				resultp2);
+		}
+		if (Is_inexacttrap_enabled()) {
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/float.h linux-2.4.20-pre2/arch/parisc/math-emu/float.h
--- linux-2.4.20-pre1/arch/parisc/math-emu/float.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/float.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,582 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ * 
+ *  File: 
+ *      @(#)	pa/spmath/float.h		$Revision: 1.2 $
+ * 
+ *  Purpose:
+ *      <<please update with a synopis of the functionality provided by this file>>
+ * 
+ *  BE header:  no
+ *
+ *  Shipped:  yes
+ *	/usr/conf/pa/spmath/float.h
+ *
+ * END_DESC  
+*/
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+#include "fpbits.h"
+#include "hppa.h"
+/*
+ * Want to pick up the FPU capability flags, not the PDC structures.
+ * 'LOCORE' isn't really true in this case, but we don't want the C structures
+ * so it suits our purposes
+ */
+#define LOCORE
+#include "fpu.h"
+
+/*
+ * Declare the basic structures for the 3 different
+ * floating-point precisions.
+ *        
+ * Single number  
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|       exp     |               mantissa                      |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define	Sall(object) (object)
+#define	Ssign(object) Bitfield_extract( 0,  1,object)
+#define	Ssignedsign(object) Bitfield_signed_extract( 0,  1,object)
+#define	Sexponent(object) Bitfield_extract( 1,  8,object)
+#define	Smantissa(object) Bitfield_mask( 9, 23,object)
+#define	Ssignaling(object) Bitfield_extract( 9,  1,object)
+#define	Ssignalingnan(object) Bitfield_extract( 1,  9,object)
+#define	Shigh2mantissa(object) Bitfield_extract( 9,  2,object)
+#define	Sexponentmantissa(object) Bitfield_mask( 1, 31,object)
+#define	Ssignexponent(object) Bitfield_extract( 0,  9,object)
+#define	Shidden(object) Bitfield_extract( 8,  1,object)
+#define	Shiddenoverflow(object) Bitfield_extract( 7,  1,object)
+#define	Shiddenhigh7mantissa(object) Bitfield_extract( 8,  8,object)
+#define	Shiddenhigh3mantissa(object) Bitfield_extract( 8,  4,object)
+#define	Slow(object) Bitfield_mask( 31,  1,object)
+#define	Slow4(object) Bitfield_mask( 28,  4,object)
+#define	Slow31(object) Bitfield_mask( 1, 31,object)
+#define	Shigh31(object) Bitfield_extract( 0, 31,object)
+#define	Ssignedhigh31(object) Bitfield_signed_extract( 0, 31,object)
+#define	Shigh4(object) Bitfield_extract( 0,  4,object)
+#define	Sbit24(object) Bitfield_extract( 24,  1,object)
+#define	Sbit28(object) Bitfield_extract( 28,  1,object)
+#define	Sbit29(object) Bitfield_extract( 29,  1,object)
+#define	Sbit30(object) Bitfield_extract( 30,  1,object)
+#define	Sbit31(object) Bitfield_mask( 31,  1,object)
+
+#define Deposit_ssign(object,value) Bitfield_deposit(value,0,1,object)
+#define Deposit_sexponent(object,value) Bitfield_deposit(value,1,8,object)
+#define Deposit_smantissa(object,value) Bitfield_deposit(value,9,23,object)
+#define Deposit_shigh2mantissa(object,value) Bitfield_deposit(value,9,2,object)
+#define Deposit_sexponentmantissa(object,value) \
+    Bitfield_deposit(value,1,31,object)
+#define Deposit_ssignexponent(object,value) Bitfield_deposit(value,0,9,object)
+#define Deposit_slow(object,value) Bitfield_deposit(value,31,1,object)
+#define Deposit_shigh4(object,value) Bitfield_deposit(value,0,4,object)
+
+#define	Is_ssign(object) Bitfield_mask( 0,  1,object)
+#define	Is_ssignaling(object) Bitfield_mask( 9,  1,object)
+#define	Is_shidden(object) Bitfield_mask( 8,  1,object)
+#define	Is_shiddenoverflow(object) Bitfield_mask( 7,  1,object)
+#define	Is_slow(object) Bitfield_mask( 31,  1,object)
+#define	Is_sbit24(object) Bitfield_mask( 24,  1,object)
+#define	Is_sbit28(object) Bitfield_mask( 28,  1,object)
+#define	Is_sbit29(object) Bitfield_mask( 29,  1,object)
+#define	Is_sbit30(object) Bitfield_mask( 30,  1,object)
+#define	Is_sbit31(object) Bitfield_mask( 31,  1,object)
+
+/* 
+ * Double number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|       exponent      |          mantissa part 1              |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    mantissa part 2                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Dallp1(object) (object)
+#define Dsign(object) Bitfield_extract( 0,  1,object)
+#define Dsignedsign(object) Bitfield_signed_extract( 0,  1,object)
+#define Dexponent(object) Bitfield_extract( 1,  11,object)
+#define Dmantissap1(object) Bitfield_mask( 12, 20,object)
+#define Dsignaling(object) Bitfield_extract( 12,  1,object)
+#define Dsignalingnan(object) Bitfield_extract( 1,  12,object)
+#define Dhigh2mantissa(object) Bitfield_extract( 12,  2,object)
+#define Dexponentmantissap1(object) Bitfield_mask( 1, 31,object)
+#define Dsignexponent(object) Bitfield_extract( 0, 12,object)
+#define Dhidden(object) Bitfield_extract( 11,  1,object)
+#define Dhiddenoverflow(object) Bitfield_extract( 10,  1,object)
+#define Dhiddenhigh7mantissa(object) Bitfield_extract( 11,  8,object)
+#define Dhiddenhigh3mantissa(object) Bitfield_extract( 11,  4,object)
+#define Dlowp1(object) Bitfield_mask( 31,  1,object)
+#define Dlow31p1(object) Bitfield_mask( 1, 31,object)
+#define Dhighp1(object) Bitfield_extract( 0,  1,object)
+#define Dhigh4p1(object) Bitfield_extract( 0,  4,object)
+#define Dhigh31p1(object) Bitfield_extract( 0, 31,object)
+#define Dsignedhigh31p1(object) Bitfield_signed_extract( 0, 31,object)
+#define Dbit3p1(object) Bitfield_extract( 3,  1,object)
+
+#define Deposit_dsign(object,value) Bitfield_deposit(value,0,1,object)
+#define Deposit_dexponent(object,value) Bitfield_deposit(value,1,11,object)
+#define Deposit_dmantissap1(object,value) Bitfield_deposit(value,12,20,object)
+#define Deposit_dhigh2mantissa(object,value) Bitfield_deposit(value,12,2,object)
+#define Deposit_dexponentmantissap1(object,value) \
+    Bitfield_deposit(value,1,31,object)
+#define Deposit_dsignexponent(object,value) Bitfield_deposit(value,0,12,object)
+#define Deposit_dlowp1(object,value) Bitfield_deposit(value,31,1,object)
+#define Deposit_dhigh4p1(object,value) Bitfield_deposit(value,0,4,object)
+
+#define Is_dsign(object) Bitfield_mask( 0,  1,object)
+#define Is_dsignaling(object) Bitfield_mask( 12,  1,object)
+#define Is_dhidden(object) Bitfield_mask( 11,  1,object)
+#define Is_dhiddenoverflow(object) Bitfield_mask( 10,  1,object)
+#define Is_dlowp1(object) Bitfield_mask( 31,  1,object)
+#define Is_dhighp1(object) Bitfield_mask( 0,  1,object)
+#define Is_dbit3p1(object) Bitfield_mask( 3,  1,object)
+
+#define Dallp2(object) (object)
+#define Dmantissap2(object) (object)
+#define Dlowp2(object) Bitfield_mask( 31,  1,object)
+#define Dlow4p2(object) Bitfield_mask( 28,  4,object)
+#define Dlow31p2(object) Bitfield_mask( 1, 31,object)
+#define Dhighp2(object) Bitfield_extract( 0,  1,object)
+#define Dhigh31p2(object) Bitfield_extract( 0, 31,object)
+#define Dbit2p2(object) Bitfield_extract( 2,  1,object)
+#define Dbit3p2(object) Bitfield_extract( 3,  1,object)
+#define Dbit21p2(object) Bitfield_extract( 21,  1,object)
+#define Dbit28p2(object) Bitfield_extract( 28,  1,object)
+#define Dbit29p2(object) Bitfield_extract( 29,  1,object)
+#define Dbit30p2(object) Bitfield_extract( 30,  1,object)
+#define Dbit31p2(object) Bitfield_mask( 31,  1,object)
+
+#define Deposit_dlowp2(object,value) Bitfield_deposit(value,31,1,object)
+
+#define Is_dlowp2(object) Bitfield_mask( 31,  1,object)
+#define Is_dhighp2(object) Bitfield_mask( 0,  1,object)
+#define Is_dbit2p2(object) Bitfield_mask( 2,  1,object)
+#define Is_dbit3p2(object) Bitfield_mask( 3,  1,object)
+#define Is_dbit21p2(object) Bitfield_mask( 21,  1,object)
+#define Is_dbit28p2(object) Bitfield_mask( 28,  1,object)
+#define Is_dbit29p2(object) Bitfield_mask( 29,  1,object)
+#define Is_dbit30p2(object) Bitfield_mask( 30,  1,object)
+#define Is_dbit31p2(object) Bitfield_mask( 31,  1,object)
+
+/* 
+ * Quad number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|          exponent           |      mantissa part 1          |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    mantissa part 2                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    mantissa part 3                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    mantissa part 4                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+typedef struct
+    {
+    union
+	{
+	struct { unsigned qallp1; } u_qallp1;
+/* Not needed for now...
+	Bitfield_extract( 0,  1,u_qsign,qsign)
+	Bitfield_signed_extract( 0,  1,u_qsignedsign,qsignedsign)
+	Bitfield_extract( 1, 15,u_qexponent,qexponent)
+	Bitfield_extract(16, 16,u_qmantissap1,qmantissap1)
+	Bitfield_extract(16,  1,u_qsignaling,qsignaling)
+	Bitfield_extract(1,  16,u_qsignalingnan,qsignalingnan)
+	Bitfield_extract(16,  2,u_qhigh2mantissa,qhigh2mantissa)
+	Bitfield_extract( 1, 31,u_qexponentmantissap1,qexponentmantissap1)
+	Bitfield_extract( 0, 16,u_qsignexponent,qsignexponent)
+	Bitfield_extract(15,  1,u_qhidden,qhidden)
+	Bitfield_extract(14,  1,u_qhiddenoverflow,qhiddenoverflow)
+	Bitfield_extract(15,  8,u_qhiddenhigh7mantissa,qhiddenhigh7mantissa)
+	Bitfield_extract(15,  4,u_qhiddenhigh3mantissa,qhiddenhigh3mantissa)
+	Bitfield_extract(31,  1,u_qlowp1,qlowp1)
+	Bitfield_extract( 1, 31,u_qlow31p1,qlow31p1)
+	Bitfield_extract( 0,  1,u_qhighp1,qhighp1)
+	Bitfield_extract( 0,  4,u_qhigh4p1,qhigh4p1)
+	Bitfield_extract( 0, 31,u_qhigh31p1,qhigh31p1)
+  */
+	} quad_u1;
+    union
+	{
+	struct { unsigned qallp2; } u_qallp2;
+  /* Not needed for now...
+	Bitfield_extract(31,  1,u_qlowp2,qlowp2)
+	Bitfield_extract( 1, 31,u_qlow31p2,qlow31p2)
+	Bitfield_extract( 0,  1,u_qhighp2,qhighp2)
+	Bitfield_extract( 0, 31,u_qhigh31p2,qhigh31p2)
+   */
+	} quad_u2;
+    union
+	{
+	struct { unsigned qallp3; } u_qallp3;
+  /* Not needed for now...
+	Bitfield_extract(31,  1,u_qlowp3,qlowp3)
+	Bitfield_extract( 1, 31,u_qlow31p3,qlow31p3)
+	Bitfield_extract( 0,  1,u_qhighp3,qhighp3)
+	Bitfield_extract( 0, 31,u_qhigh31p3,qhigh31p3)
+   */ 
+	} quad_u3;
+    union
+	{
+	struct { unsigned qallp4; } u_qallp4;
+    /* Not need for now...
+	Bitfield_extract(31,  1,u_qlowp4,qlowp4)
+	Bitfield_extract( 1, 31,u_qlow31p4,qlow31p4)
+	Bitfield_extract( 0,  1,u_qhighp4,qhighp4)
+	Bitfield_extract( 0, 31,u_qhigh31p4,qhigh31p4)
+     */
+	} quad_u4;
+    } quad_floating_point;
+
+/* Extension - An additional structure to hold the guard, round and
+ *             sticky bits during computations.
+ */
+#define Extall(object) (object)
+#define Extsign(object) Bitfield_extract( 0,  1,object)
+#define Exthigh31(object) Bitfield_extract( 0, 31,object)
+#define Extlow31(object) Bitfield_extract( 1, 31,object)
+#define Extlow(object) Bitfield_extract( 31,  1,object)
+
+/*
+ * Single extended - The upper word is just like single precision,
+ *                 but one additional word of mantissa is needed.
+ */
+#define Sextallp1(object) (object)
+#define Sextallp2(object) (object)
+#define Sextlowp1(object) Bitfield_extract( 31,  1,object)
+#define Sexthighp2(object) Bitfield_extract( 0,  1,object)
+#define Sextlow31p2(object) Bitfield_extract( 1, 31,object)
+#define Sexthiddenoverflow(object) Bitfield_extract( 4,  1,object)
+#define Is_sexthiddenoverflow(object) Bitfield_mask( 4,  1,object)
+
+/*
+ * Double extended - The upper two words are just like double precision,
+ *		     but two additional words of mantissa are needed.
+ */
+#define Dextallp1(object) (object)
+#define Dextallp2(object) (object)
+#define Dextallp3(object) (object)
+#define Dextallp4(object) (object)
+#define Dextlowp2(object) Bitfield_extract( 31,  1,object)
+#define Dexthighp3(object) Bitfield_extract( 0,  1,object)
+#define Dextlow31p3(object) Bitfield_extract( 1, 31,object)
+#define Dexthiddenoverflow(object) Bitfield_extract( 10,  1,object)
+#define Is_dexthiddenoverflow(object) Bitfield_mask( 10,  1,object)
+#define Deposit_dextlowp4(object,value) Bitfield_deposit(value,31,1,object)
+
+/*
+ * Declare the basic structures for the 3 different
+ * fixed-point precisions.
+ *        
+ * Single number  
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|                    integer                                  |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+typedef int sgl_integer;
+
+/* 
+ * Double number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|                     high integer                            |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                       low integer                             |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+struct dint {
+        int  wd0;
+        unsigned int wd1;
+};
+
+struct dblwd {
+        unsigned int wd0;
+        unsigned int wd1;
+};
+
+/* 
+ * Quad number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s|                  integer part1                              |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    integer part 2                             |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    integer part 3                             |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                    integer part 4                             |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+
+struct quadwd {
+        int  wd0;
+        unsigned int wd1;
+        unsigned int wd2;
+        unsigned int wd3;
+};
+
+typedef struct quadwd quad_integer;
+
+
+/* useful typedefs */
+typedef unsigned int sgl_floating_point;
+typedef struct dblwd dbl_floating_point;
+typedef struct dint dbl_integer;
+typedef struct dblwd dbl_unsigned;
+
+/* 
+ * Define the different precisions' parameters.
+ */
+#define SGL_BITLENGTH 32
+#define SGL_EMAX 127
+#define SGL_EMIN (-126)
+#define SGL_BIAS 127
+#define SGL_WRAP 192
+#define SGL_INFINITY_EXPONENT (SGL_EMAX+SGL_BIAS+1)
+#define SGL_THRESHOLD 32
+#define SGL_EXP_LENGTH 8
+#define SGL_P 24
+
+#define DBL_BITLENGTH 64
+#define DBL_EMAX 1023
+#define DBL_EMIN (-1022)
+#define DBL_BIAS 1023
+#define DBL_WRAP 1536
+#define DBL_INFINITY_EXPONENT (DBL_EMAX+DBL_BIAS+1)
+#define DBL_THRESHOLD 64
+#define DBL_EXP_LENGTH 11
+#define DBL_P 53
+
+#define QUAD_BITLENGTH 128
+#define QUAD_EMAX 16383
+#define QUAD_EMIN (-16382)
+#define QUAD_BIAS 16383
+#define QUAD_WRAP 24576
+#define QUAD_INFINITY_EXPONENT (QUAD_EMAX+QUAD_BIAS+1)
+#define QUAD_P 113
+
+/* Boolean Values etc. */
+#define FALSE 0
+#define TRUE (!FALSE)
+#define NOT !
+#define XOR ^
+
+/* other constants */
+#undef NULL
+#define NULL 0
+#define NIL 0
+#define SGL 0
+#define DBL 1
+#define BADFMT 2
+#define QUAD 3
+
+
+/* Types */
+typedef int boolean;
+typedef int FORMAT;
+typedef int VOID;
+
+
+/* Declare status register equivalent to FPUs architecture.
+ *
+ *  0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 920 1 2 3 4 5 6 7 8 930 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |V|Z|O|U|I|C|  rsv  |  model    | version |RM |rsv|T|r|V|Z|O|U|I|
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Cbit(object) Bitfield_extract( 5, 1,object)
+#define Tbit(object) Bitfield_extract( 25, 1,object)
+#define Roundingmode(object) Bitfield_extract( 21, 2,object)
+#define Invalidtrap(object) Bitfield_extract( 27, 1,object)
+#define Divisionbyzerotrap(object) Bitfield_extract( 28, 1,object)
+#define Overflowtrap(object) Bitfield_extract( 29, 1,object)
+#define Underflowtrap(object) Bitfield_extract( 30, 1,object)
+#define Inexacttrap(object) Bitfield_extract( 31, 1,object)
+#define Invalidflag(object) Bitfield_extract( 0, 1,object)
+#define Divisionbyzeroflag(object) Bitfield_extract( 1, 1,object)
+#define Overflowflag(object) Bitfield_extract( 2, 1,object)
+#define Underflowflag(object) Bitfield_extract( 3, 1,object)
+#define Inexactflag(object) Bitfield_extract( 4, 1,object)
+#define Allflags(object) Bitfield_extract( 0, 5,object)
+
+/* Definitions relevant to the status register */
+
+/* Rounding Modes */
+#define ROUNDNEAREST 0
+#define ROUNDZERO    1
+#define ROUNDPLUS    2
+#define ROUNDMINUS   3
+
+/* Exceptions */
+#define NOEXCEPTION		0x0
+#define INVALIDEXCEPTION	0x20
+#define DIVISIONBYZEROEXCEPTION	0x10
+#define OVERFLOWEXCEPTION	0x08
+#define UNDERFLOWEXCEPTION	0x04
+#define INEXACTEXCEPTION	0x02
+#define UNIMPLEMENTEDEXCEPTION	0x01
+
+/* New exceptions for the 2E Opcode */
+#define OPC_2E_INVALIDEXCEPTION     0x30
+#define OPC_2E_OVERFLOWEXCEPTION    0x18
+#define OPC_2E_UNDERFLOWEXCEPTION   0x0c
+#define OPC_2E_INEXACTEXCEPTION     0x12
+
+/* Declare exception registers equivalent to FPUs architecture 
+ *
+ *  0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 920 1 2 3 4 5 6 7 8 930 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |excepttype |  r1     | r2/ext  |  operation  |parm |n| t/cond  |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Allexception(object) (object)
+#define Exceptiontype(object) Bitfield_extract( 0, 6,object)
+#define Instructionfield(object) Bitfield_mask( 6,26,object)
+#define Parmfield(object) Bitfield_extract( 23, 3,object)
+#define Rabit(object) Bitfield_extract( 24, 1,object)
+#define Ibit(object) Bitfield_extract( 25, 1,object)
+
+#define Set_exceptiontype(object,value) Bitfield_deposit(value, 0, 6,object)
+#define Set_parmfield(object,value) Bitfield_deposit(value, 23, 3,object)
+#define Set_exceptiontype_and_instr_field(exception,instruction,object) \
+    object = exception << 26 | instruction
+
+/* Declare the condition field
+ *
+ *  0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 920 1 2 3 4 5 6 7 8 930 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |                                                     |G|L|E|U|X|
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Allexception(object) (object)
+#define Greaterthanbit(object) Bitfield_extract( 27, 1,object)
+#define Lessthanbit(object) Bitfield_extract( 28, 1,object)
+#define Equalbit(object) Bitfield_extract( 29, 1,object)
+#define Unorderedbit(object) Bitfield_extract( 30, 1,object)
+#define Exceptionbit(object) Bitfield_extract( 31, 1,object)
+
+/* An alias name for the status register */
+#define Fpustatus_register (*status)
+
+/**************************************************
+ * Status register referencing and manipulation.  *
+ **************************************************/
+
+/* Rounding mode */
+#define Rounding_mode()  Roundingmode(Fpustatus_register)
+#define Is_rounding_mode(rmode) \
+    (Roundingmode(Fpustatus_register) == rmode)
+#define Set_rounding_mode(value) \
+    Bitfield_deposit(value,21,2,Fpustatus_register)
+
+/* Boolean testing of the trap enable bits */
+#define Is_invalidtrap_enabled() Invalidtrap(Fpustatus_register)
+#define Is_divisionbyzerotrap_enabled() Divisionbyzerotrap(Fpustatus_register)
+#define Is_overflowtrap_enabled() Overflowtrap(Fpustatus_register)
+#define Is_underflowtrap_enabled() Underflowtrap(Fpustatus_register)
+#define Is_inexacttrap_enabled() Inexacttrap(Fpustatus_register)
+
+/* Set the indicated flags in the status register */
+#define Set_invalidflag() Bitfield_deposit(1,0,1,Fpustatus_register)
+#define Set_divisionbyzeroflag() Bitfield_deposit(1,1,1,Fpustatus_register)
+#define Set_overflowflag() Bitfield_deposit(1,2,1,Fpustatus_register)
+#define Set_underflowflag() Bitfield_deposit(1,3,1,Fpustatus_register)
+#define Set_inexactflag() Bitfield_deposit(1,4,1,Fpustatus_register)
+
+#define Clear_all_flags() Bitfield_deposit(0,0,5,Fpustatus_register)
+
+/* Manipulate the trap and condition code bits (tbit and cbit) */
+#define Set_tbit() Bitfield_deposit(1,25,1,Fpustatus_register)
+#define Clear_tbit() Bitfield_deposit(0,25,1,Fpustatus_register)
+#define Is_tbit_set() Tbit(Fpustatus_register)
+#define Is_cbit_set() Cbit(Fpustatus_register)
+
+#define Set_status_cbit(value)  \
+        Bitfield_deposit(value,5,1,Fpustatus_register)
+
+/*******************************
+ * Condition field referencing *
+ *******************************/
+#define Unordered(cond) Unorderedbit(cond)
+#define Equal(cond) Equalbit(cond)
+#define Lessthan(cond) Lessthanbit(cond)
+#define Greaterthan(cond) Greaterthanbit(cond)
+#define Exception(cond) Exceptionbit(cond)
+
+
+/* Defines for the extension */
+#define Ext_isone_sign(extent) (Extsign(extent))
+#define Ext_isnotzero(extent) \
+    (Extall(extent))
+#define Ext_isnotzero_lower(extent) \
+    (Extlow31(extent))
+#define Ext_leftshiftby1(extent) \
+    Extall(extent) <<= 1
+#define Ext_negate(extent) \
+    (int )Extall(extent) = 0 - (int )Extall(extent)
+#define Ext_setone_low(extent) Bitfield_deposit(1,31,1,extent)
+#define Ext_setzero(extent) Extall(extent) = 0
+
+typedef int operation;
+
+/* error messages */
+
+#define		NONE		0
+#define		UNDEFFPINST	1
+
+/* Function definitions: opcode, opclass */
+#define FTEST	(1<<2) | 0
+#define FCPY	(2<<2) | 0
+#define FABS	(3<<2) | 0
+#define FSQRT   (4<<2) | 0
+#define FRND    (5<<2) | 0
+
+#define FCNVFF	(0<<2) | 1
+#define FCNVXF	(1<<2) | 1
+#define FCNVFX	(2<<2) | 1
+#define FCNVFXT	(3<<2) | 1
+
+#define FCMP    (0<<2) | 2
+
+#define FADD	(0<<2) | 3
+#define FSUB	(1<<2) | 3
+#define FMPY	(2<<2) | 3
+#define FDIV	(3<<2) | 3
+#define FREM	(4<<2) | 3
+
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fmpyfadd.c linux-2.4.20-pre2/arch/parisc/math-emu/fmpyfadd.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/fmpyfadd.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fmpyfadd.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,2655 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/fmpyfadd.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Double Floating-point Multiply Fused Add
+ *	Double Floating-point Multiply Negate Fused Add
+ *	Single Floating-point Multiply Fused Add
+ *	Single Floating-point Multiply Negate Fused Add
+ *
+ *  External Interfaces:
+ *	dbl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ *	dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ *	sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ *	sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+
+
+/*
+ *  Double Floating-point Multiply Fused Add
+ */
+
+int
+dbl_fmpyfadd(
+	    dbl_floating_point *src1ptr,
+	    dbl_floating_point *src2ptr,
+	    dbl_floating_point *src3ptr,
+	    unsigned int *status,
+	    dbl_floating_point *dstptr)
+{
+	unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2, opnd3p1, opnd3p2;
+	register unsigned int tmpresp1, tmpresp2, tmpresp3, tmpresp4;
+	unsigned int rightp1, rightp2, rightp3, rightp4;
+	unsigned int resultp1, resultp2 = 0, resultp3 = 0, resultp4 = 0;
+	register int mpy_exponent, add_exponent, count;
+	boolean inexact = FALSE, is_tiny = FALSE;
+
+	unsigned int signlessleft1, signlessright1, save;
+	register int result_exponent, diff_exponent;
+	int sign_save, jumpsize;
+	
+	Dbl_copyfromptr(src1ptr,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(src2ptr,opnd2p1,opnd2p2);
+	Dbl_copyfromptr(src3ptr,opnd3p1,opnd3p2);
+
+	/* 
+	 * set sign bit of result of multiply
+	 */
+	if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) 
+		Dbl_setnegativezerop1(resultp1); 
+	else Dbl_setzerop1(resultp1);
+
+	/*
+	 * Generate multiply exponent 
+	 */
+	mpy_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) - DBL_BIAS;
+
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd1p1)) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2) &&
+			    Dbl_isnotnan(opnd3p1,opnd3p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+				    (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+			 	 * return infinity
+			 	 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+		 	 * is NaN; signaling or quiet?
+		 	 */
+			if (Dbl_isone_signaling(opnd1p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled()) 
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd1p1);
+			}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd3p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd3p1);
+				Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+		 	 * return quiet NaN
+		 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd2p1)) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			if (Dbl_isnotnan(opnd3p1,opnd3p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+					/* 
+					 * invalid since multiply operands are
+					 * zero & infinity
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(opnd2p1,opnd2p2);
+					Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+				    (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+				       		return(OPC_2E_INVALIDEXCEPTION);
+				       	Set_invalidflag();
+				       	Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * return infinity
+				 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Dbl_isone_signaling(opnd2p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd2p1);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd3p1)) {
+			       	/* trap if INVALIDTRAP enabled */
+			       	if (Is_invalidtrap_enabled())
+				   		return(OPC_2E_INVALIDEXCEPTION);
+			       	/* make NaN quiet */
+			       	Set_invalidflag();
+			       	Dbl_set_quiet(opnd3p1);
+				Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+		       		return(NOEXCEPTION);
+			}
+			/*
+			 * return quiet NaN
+			 */
+			Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check third operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd3p1)) {
+		if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+			/* return infinity */
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		} else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Dbl_isone_signaling(opnd3p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd3p1);
+			}
+			/*
+			 * return quiet NaN
+ 			 */
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+    	}
+
+	/*
+	 * Generate multiply mantissa
+	 */
+	if (Dbl_isnotzero_exponent(opnd1p1)) {
+		/* set hidden bit */
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Dbl_or_signs(opnd3p1,resultp1);
+				} else {
+					Dbl_and_signs(opnd3p1,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Dbl_iszero_exponent(opnd3p1) &&
+			         Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Dbl_signextendedsign(opnd3p1);
+				result_exponent = 0;
+                    		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+                    		Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+                    		Dbl_set_sign(opnd3p1,/*using*/sign_save);
+                    		Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+							unfl);
+                    		Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized, adjust exponent */
+		Dbl_clear_signexponent(opnd1p1);
+		Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_normalize(opnd1p1,opnd1p2,mpy_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Dbl_isnotzero_exponent(opnd2p1)) {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Dbl_or_signs(opnd3p1,resultp1);
+				} else {
+					Dbl_and_signs(opnd3p1,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Dbl_iszero_exponent(opnd3p1) &&
+			    Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Dbl_signextendedsign(opnd3p1);
+				result_exponent = 0;
+                    		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+                    		Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+                    		Dbl_set_sign(opnd3p1,/*using*/sign_save);
+                    		Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+							unfl);
+                    		Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+                    		/* inexact = FALSE */
+				return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized; want to normalize */
+		Dbl_clear_signexponent(opnd2p1);
+		Dbl_leftshiftby1(opnd2p1,opnd2p2);
+		Dbl_normalize(opnd2p1,opnd2p2,mpy_exponent);
+	}
+
+	/* Multiply the first two source mantissas together */
+
+	/* 
+	 * The intermediate result will be kept in tmpres,
+	 * which needs enough room for 106 bits of mantissa,
+	 * so lets call it a Double extended.
+	 */
+	Dblext_setzero(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+
+	/* 
+	 * Four bits at a time are inspected in each loop, and a 
+	 * simple shift and add multiply algorithm is used. 
+	 */ 
+	for (count = DBL_P-1; count >= 0; count -= 4) {
+		Dblext_rightshiftby4(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+		if (Dbit28p2(opnd1p2)) {
+	 		/* Fourword_add should be an ADD followed by 3 ADDC's */
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4, 
+			 opnd2p1<<3 | opnd2p2>>29, opnd2p2<<3, 0, 0);
+		}
+		if (Dbit29p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1<<2 | opnd2p2>>30, opnd2p2<<2, 0, 0);
+		}
+		if (Dbit30p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1<<1 | opnd2p2>>31, opnd2p2<<1, 0, 0);
+		}
+		if (Dbit31p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1, opnd2p2, 0, 0);
+		}
+		Dbl_rightshiftby4(opnd1p1,opnd1p2);
+	}
+	if (Is_dexthiddenoverflow(tmpresp1)) {
+		/* result mantissa >= 2 (mantissa overflow) */
+		mpy_exponent++;
+		Dblext_rightshiftby1(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+	}
+
+	/*
+	 * Restore the sign of the mpy result which was saved in resultp1.
+	 * The exponent will continue to be kept in mpy_exponent.
+	 */
+	Dblext_set_sign(tmpresp1,Dbl_sign(resultp1));
+
+	/* 
+	 * No rounding is required, since the result of the multiply
+	 * is exact in the extended format.
+	 */
+
+	/*
+	 * Now we are ready to perform the add portion of the operation.
+	 *
+	 * The exponents need to be kept as integers for now, since the
+	 * multiply result might not fit into the exponent field.  We
+	 * can't overflow or underflow because of this yet, since the
+	 * add could bring the final result back into range.
+	 */
+	add_exponent = Dbl_exponent(opnd3p1);
+
+	/*
+	 * Check for denormalized or zero add operand.
+	 */
+	if (add_exponent == 0) {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+			/* right is zero */
+			/* Left can't be zero and must be result.
+			 *
+			 * The final result is now in tmpres and mpy_exponent,
+			 * and needs to be rounded and squeezed back into
+			 * double precision format from double extended.
+			 */
+			result_exponent = mpy_exponent;
+			Dblext_copy(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+				resultp1,resultp2,resultp3,resultp4);
+			sign_save = Dbl_signextendedsign(resultp1);/*save sign*/
+			goto round;
+		}
+
+		/* 
+		 * Neither are zeroes.  
+		 * Adjust exponent and normalize add operand.
+		 */
+		sign_save = Dbl_signextendedsign(opnd3p1);	/* save sign */
+		Dbl_clear_signexponent(opnd3p1);
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		Dbl_normalize(opnd3p1,opnd3p2,add_exponent);
+		Dbl_set_sign(opnd3p1,sign_save);	/* restore sign */
+	} else {
+		Dbl_clear_exponent_set_hidden(opnd3p1);
+	}
+	/*
+	 * Copy opnd3 to the double extended variable called right.
+	 */
+	Dbl_copyto_dblext(opnd3p1,opnd3p2,rightp1,rightp2,rightp3,rightp4);
+
+	/*
+	 * A zero "save" helps discover equal operands (for later),
+	 * and is used in swapping operands (if needed).
+	 */
+	Dblext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+	/*
+	 * Compare magnitude of operands.
+	 */
+	Dblext_copytoint_exponentmantissap1(tmpresp1,signlessleft1);
+	Dblext_copytoint_exponentmantissap1(rightp1,signlessright1);
+	if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+	    Dblext_ismagnitudeless(tmpresp2,rightp2,signlessleft1,signlessright1)){
+		/*
+		 * Set the left operand to the larger one by XOR swap.
+		 * First finish the first word "save".
+		 */
+		Dblext_xorfromintp1(save,rightp1,/*to*/rightp1);
+		Dblext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+		Dblext_swap_lower(tmpresp2,tmpresp3,tmpresp4,
+			rightp2,rightp3,rightp4);
+		/* also setup exponents used in rest of routine */
+		diff_exponent = add_exponent - mpy_exponent;
+		result_exponent = add_exponent;
+	} else {
+		/* also setup exponents used in rest of routine */
+		diff_exponent = mpy_exponent - add_exponent;
+		result_exponent = mpy_exponent;
+	}
+	/* Invariant: left is not smaller than right. */
+
+	/*
+	 * Special case alignment of operands that would force alignment
+	 * beyond the extent of the extension.  A further optimization
+	 * could special case this but only reduces the path length for
+	 * this infrequent case.
+	 */
+	if (diff_exponent > DBLEXT_THRESHOLD) {
+		diff_exponent = DBLEXT_THRESHOLD;
+	}
+
+	/* Align right operand by shifting it to the right */
+	Dblext_clear_sign(rightp1);
+	Dblext_right_align(rightp1,rightp2,rightp3,rightp4,
+		/*shifted by*/diff_exponent);
+	
+	/* Treat sum and difference of the operands separately. */
+	if ((int)save < 0) {
+		/*
+		 * Difference of the two operands.  Overflow can occur if the
+		 * multiply overflowed.  A borrow can occur out of the hidden
+		 * bit and force a post normalization phase.
+		 */
+		Dblext_subtract(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+			rightp1,rightp2,rightp3,rightp4,
+			resultp1,resultp2,resultp3,resultp4);
+		sign_save = Dbl_signextendedsign(resultp1);
+		if (Dbl_iszero_hidden(resultp1)) {
+			/* Handle normalization */
+		/* A straight foward algorithm would now shift the
+		 * result and extension left until the hidden bit
+		 * becomes one.  Not all of the extension bits need
+		 * participate in the shift.  Only the two most 
+		 * significant bits (round and guard) are needed.
+		 * If only a single shift is needed then the guard
+		 * bit becomes a significant low order bit and the
+		 * extension must participate in the rounding.
+		 * If more than a single shift is needed, then all
+		 * bits to the right of the guard bit are zeros, 
+		 * and the guard bit may or may not be zero. */
+			Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+				resultp4);
+
+			/* Need to check for a zero result.  The sign and
+			 * exponent fields have already been zeroed.  The more
+			 * efficient test of the full object can be used.
+			 */
+			 if(Dblext_iszero(resultp1,resultp2,resultp3,resultp4)){
+				/* Must have been "x-x" or "x+(-x)". */
+				if (Is_rounding_mode(ROUNDMINUS))
+					Dbl_setone_sign(resultp1);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+			result_exponent--;
+
+			/* Look to see if normalization is finished. */
+			if (Dbl_isone_hidden(resultp1)) {
+				/* No further normalization is needed */
+				goto round;
+			}
+
+			/* Discover first one bit to determine shift amount.
+			 * Use a modified binary search.  We have already
+			 * shifted the result one position right and still
+			 * not found a one so the remainder of the extension
+			 * must be zero and simplifies rounding. */
+			/* Scan bytes */
+			while (Dbl_iszero_hiddenhigh7mantissa(resultp1)) {
+				Dblext_leftshiftby8(resultp1,resultp2,resultp3,resultp4);
+				result_exponent -= 8;
+			}
+			/* Now narrow it down to the nibble */
+			if (Dbl_iszero_hiddenhigh3mantissa(resultp1)) {
+				/* The lower nibble contains the
+				 * normalizing one */
+				Dblext_leftshiftby4(resultp1,resultp2,resultp3,resultp4);
+				result_exponent -= 4;
+			}
+			/* Select case where first bit is set (already
+			 * normalized) otherwise select the proper shift. */
+			jumpsize = Dbl_hiddenhigh3mantissa(resultp1);
+			if (jumpsize <= 7) switch(jumpsize) {
+			case 1:
+				Dblext_leftshiftby3(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 3;
+				break;
+			case 2:
+			case 3:
+				Dblext_leftshiftby2(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 2;
+				break;
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 1;
+				break;
+			}
+		} /* end if (hidden...)... */
+	/* Fall through and round */
+	} /* end if (save < 0)... */
+	else {
+		/* Add magnitudes */
+		Dblext_addition(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+			rightp1,rightp2,rightp3,rightp4,
+			/*to*/resultp1,resultp2,resultp3,resultp4);
+		sign_save = Dbl_signextendedsign(resultp1);
+		if (Dbl_isone_hiddenoverflow(resultp1)) {
+	    		/* Prenormalization required. */
+	    		Dblext_arithrightshiftby1(resultp1,resultp2,resultp3,
+				resultp4);
+	    		result_exponent++;
+		} /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+
+	/* Round the result.  If the extension and lower two words are
+	 * all zeros, then the result is exact.  Otherwise round in the
+	 * correct direction.  Underflow is possible. If a postnormalization
+	 * is necessary, then the mantissa is all zeros so no shift is needed.
+	 */
+  round:
+	if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+		Dblext_denormalize(resultp1,resultp2,resultp3,resultp4,
+			result_exponent,is_tiny);
+	}
+	Dbl_set_sign(resultp1,/*using*/sign_save);
+	if (Dblext_isnotzero_mantissap3(resultp3) || 
+	    Dblext_isnotzero_mantissap4(resultp4)) {
+		inexact = TRUE;
+		switch(Rounding_mode()) {
+		case ROUNDNEAREST: /* The default. */
+			if (Dblext_isone_highp3(resultp3)) {
+				/* at least 1/2 ulp */
+				if (Dblext_isnotzero_low31p3(resultp3) ||
+				    Dblext_isnotzero_mantissap4(resultp4) ||
+				    Dblext_isone_lowp2(resultp2)) {
+					/* either exactly half way and odd or
+					 * more than 1/2ulp */
+					Dbl_increment(resultp1,resultp2);
+				}
+			}
+	    		break;
+
+		case ROUNDPLUS:
+	    		if (Dbl_iszero_sign(resultp1)) {
+				/* Round up positive results */
+				Dbl_increment(resultp1,resultp2);
+			}
+			break;
+	    
+		case ROUNDMINUS:
+	    		if (Dbl_isone_sign(resultp1)) {
+				/* Round down negative results */
+				Dbl_increment(resultp1,resultp2);
+			}
+	    
+		case ROUNDZERO:;
+			/* truncate is simple */
+		} /* end switch... */
+		if (Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+	if (result_exponent >= DBL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_OVERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return (OPC_2E_OVERFLOWEXCEPTION);
+                }
+                inexact = TRUE;
+                Set_overflowflag();
+                /* set result to infinity or largest number */
+                Dbl_setoverflow(resultp1,resultp2);
+
+	} else if (result_exponent <= 0) {	/* underflow case */
+		if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                	Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_UNDERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+	    		return(OPC_2E_UNDERFLOWEXCEPTION);
+		}
+		else if (inexact && is_tiny) Set_underflowflag();
+	}
+	else Dbl_set_exponent(resultp1,result_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) 
+		if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+		else Set_inexactflag();
+    	return(NOEXCEPTION);
+}
+
+/*
+ *  Double Floating-point Multiply Negate Fused Add
+ */
+
+dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+
+dbl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
+unsigned int *status;
+{
+	unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2, opnd3p1, opnd3p2;
+	register unsigned int tmpresp1, tmpresp2, tmpresp3, tmpresp4;
+	unsigned int rightp1, rightp2, rightp3, rightp4;
+	unsigned int resultp1, resultp2 = 0, resultp3 = 0, resultp4 = 0;
+	register int mpy_exponent, add_exponent, count;
+	boolean inexact = FALSE, is_tiny = FALSE;
+
+	unsigned int signlessleft1, signlessright1, save;
+	register int result_exponent, diff_exponent;
+	int sign_save, jumpsize;
+	
+	Dbl_copyfromptr(src1ptr,opnd1p1,opnd1p2);
+	Dbl_copyfromptr(src2ptr,opnd2p1,opnd2p2);
+	Dbl_copyfromptr(src3ptr,opnd3p1,opnd3p2);
+
+	/* 
+	 * set sign bit of result of multiply
+	 */
+	if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) 
+		Dbl_setzerop1(resultp1);
+	else
+		Dbl_setnegativezerop1(resultp1); 
+
+	/*
+	 * Generate multiply exponent 
+	 */
+	mpy_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) - DBL_BIAS;
+
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd1p1)) {
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			if (Dbl_isnotnan(opnd2p1,opnd2p2) &&
+			    Dbl_isnotnan(opnd3p1,opnd3p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+				    (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+			 	 * return infinity
+			 	 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+		 	 * is NaN; signaling or quiet?
+		 	 */
+			if (Dbl_isone_signaling(opnd1p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled()) 
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd1p1);
+			}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd2p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd2p1);
+				Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd3p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd3p1);
+				Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+		 	 * return quiet NaN
+		 	 */
+			Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd2p1)) {
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			if (Dbl_isnotnan(opnd3p1,opnd3p2)) {
+				if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+					/* 
+					 * invalid since multiply operands are
+					 * zero & infinity
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Dbl_makequietnan(opnd2p1,opnd2p2);
+					Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+				    (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+				       		return(OPC_2E_INVALIDEXCEPTION);
+				       	Set_invalidflag();
+				       	Dbl_makequietnan(resultp1,resultp2);
+					Dbl_copytoptr(resultp1,resultp2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * return infinity
+				 */
+				Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Dbl_isone_signaling(opnd2p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd2p1);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Dbl_is_signalingnan(opnd3p1)) {
+			       	/* trap if INVALIDTRAP enabled */
+			       	if (Is_invalidtrap_enabled())
+				   		return(OPC_2E_INVALIDEXCEPTION);
+			       	/* make NaN quiet */
+			       	Set_invalidflag();
+			       	Dbl_set_quiet(opnd3p1);
+				Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+		       		return(NOEXCEPTION);
+			}
+			/*
+			 * return quiet NaN
+			 */
+			Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check third operand for NaN's or infinity
+	 */
+	if (Dbl_isinfinity_exponent(opnd3p1)) {
+		if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+			/* return infinity */
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		} else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Dbl_isone_signaling(opnd3p1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Dbl_set_quiet(opnd3p1);
+			}
+			/*
+			 * return quiet NaN
+ 			 */
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+    	}
+
+	/*
+	 * Generate multiply mantissa
+	 */
+	if (Dbl_isnotzero_exponent(opnd1p1)) {
+		/* set hidden bit */
+		Dbl_clear_signexponent_set_hidden(opnd1p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Dbl_or_signs(opnd3p1,resultp1);
+				} else {
+					Dbl_and_signs(opnd3p1,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Dbl_iszero_exponent(opnd3p1) &&
+			         Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Dbl_signextendedsign(opnd3p1);
+				result_exponent = 0;
+                    		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+                    		Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+                    		Dbl_set_sign(opnd3p1,/*using*/sign_save);
+                    		Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+							unfl);
+                    		Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized, adjust exponent */
+		Dbl_clear_signexponent(opnd1p1);
+		Dbl_leftshiftby1(opnd1p1,opnd1p2);
+		Dbl_normalize(opnd1p1,opnd1p2,mpy_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Dbl_isnotzero_exponent(opnd2p1)) {
+		Dbl_clear_signexponent_set_hidden(opnd2p1);
+	}
+	else {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Dbl_or_signs(opnd3p1,resultp1);
+				} else {
+					Dbl_and_signs(opnd3p1,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Dbl_iszero_exponent(opnd3p1) &&
+			    Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Dbl_signextendedsign(opnd3p1);
+				result_exponent = 0;
+                    		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+                    		Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+                    		Dbl_set_sign(opnd3p1,/*using*/sign_save);
+                    		Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+							unfl);
+                    		Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized; want to normalize */
+		Dbl_clear_signexponent(opnd2p1);
+		Dbl_leftshiftby1(opnd2p1,opnd2p2);
+		Dbl_normalize(opnd2p1,opnd2p2,mpy_exponent);
+	}
+
+	/* Multiply the first two source mantissas together */
+
+	/* 
+	 * The intermediate result will be kept in tmpres,
+	 * which needs enough room for 106 bits of mantissa,
+	 * so lets call it a Double extended.
+	 */
+	Dblext_setzero(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+
+	/* 
+	 * Four bits at a time are inspected in each loop, and a 
+	 * simple shift and add multiply algorithm is used. 
+	 */ 
+	for (count = DBL_P-1; count >= 0; count -= 4) {
+		Dblext_rightshiftby4(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+		if (Dbit28p2(opnd1p2)) {
+	 		/* Fourword_add should be an ADD followed by 3 ADDC's */
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4, 
+			 opnd2p1<<3 | opnd2p2>>29, opnd2p2<<3, 0, 0);
+		}
+		if (Dbit29p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1<<2 | opnd2p2>>30, opnd2p2<<2, 0, 0);
+		}
+		if (Dbit30p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1<<1 | opnd2p2>>31, opnd2p2<<1, 0, 0);
+		}
+		if (Dbit31p2(opnd1p2)) {
+			Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+			 opnd2p1, opnd2p2, 0, 0);
+		}
+		Dbl_rightshiftby4(opnd1p1,opnd1p2);
+	}
+	if (Is_dexthiddenoverflow(tmpresp1)) {
+		/* result mantissa >= 2 (mantissa overflow) */
+		mpy_exponent++;
+		Dblext_rightshiftby1(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+	}
+
+	/*
+	 * Restore the sign of the mpy result which was saved in resultp1.
+	 * The exponent will continue to be kept in mpy_exponent.
+	 */
+	Dblext_set_sign(tmpresp1,Dbl_sign(resultp1));
+
+	/* 
+	 * No rounding is required, since the result of the multiply
+	 * is exact in the extended format.
+	 */
+
+	/*
+	 * Now we are ready to perform the add portion of the operation.
+	 *
+	 * The exponents need to be kept as integers for now, since the
+	 * multiply result might not fit into the exponent field.  We
+	 * can't overflow or underflow because of this yet, since the
+	 * add could bring the final result back into range.
+	 */
+	add_exponent = Dbl_exponent(opnd3p1);
+
+	/*
+	 * Check for denormalized or zero add operand.
+	 */
+	if (add_exponent == 0) {
+		/* check for zero */
+		if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+			/* right is zero */
+			/* Left can't be zero and must be result.
+			 *
+			 * The final result is now in tmpres and mpy_exponent,
+			 * and needs to be rounded and squeezed back into
+			 * double precision format from double extended.
+			 */
+			result_exponent = mpy_exponent;
+			Dblext_copy(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+				resultp1,resultp2,resultp3,resultp4);
+			sign_save = Dbl_signextendedsign(resultp1);/*save sign*/
+			goto round;
+		}
+
+		/* 
+		 * Neither are zeroes.  
+		 * Adjust exponent and normalize add operand.
+		 */
+		sign_save = Dbl_signextendedsign(opnd3p1);	/* save sign */
+		Dbl_clear_signexponent(opnd3p1);
+		Dbl_leftshiftby1(opnd3p1,opnd3p2);
+		Dbl_normalize(opnd3p1,opnd3p2,add_exponent);
+		Dbl_set_sign(opnd3p1,sign_save);	/* restore sign */
+	} else {
+		Dbl_clear_exponent_set_hidden(opnd3p1);
+	}
+	/*
+	 * Copy opnd3 to the double extended variable called right.
+	 */
+	Dbl_copyto_dblext(opnd3p1,opnd3p2,rightp1,rightp2,rightp3,rightp4);
+
+	/*
+	 * A zero "save" helps discover equal operands (for later),
+	 * and is used in swapping operands (if needed).
+	 */
+	Dblext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+	/*
+	 * Compare magnitude of operands.
+	 */
+	Dblext_copytoint_exponentmantissap1(tmpresp1,signlessleft1);
+	Dblext_copytoint_exponentmantissap1(rightp1,signlessright1);
+	if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+	    Dblext_ismagnitudeless(tmpresp2,rightp2,signlessleft1,signlessright1)){
+		/*
+		 * Set the left operand to the larger one by XOR swap.
+		 * First finish the first word "save".
+		 */
+		Dblext_xorfromintp1(save,rightp1,/*to*/rightp1);
+		Dblext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+		Dblext_swap_lower(tmpresp2,tmpresp3,tmpresp4,
+			rightp2,rightp3,rightp4);
+		/* also setup exponents used in rest of routine */
+		diff_exponent = add_exponent - mpy_exponent;
+		result_exponent = add_exponent;
+	} else {
+		/* also setup exponents used in rest of routine */
+		diff_exponent = mpy_exponent - add_exponent;
+		result_exponent = mpy_exponent;
+	}
+	/* Invariant: left is not smaller than right. */
+
+	/*
+	 * Special case alignment of operands that would force alignment
+	 * beyond the extent of the extension.  A further optimization
+	 * could special case this but only reduces the path length for
+	 * this infrequent case.
+	 */
+	if (diff_exponent > DBLEXT_THRESHOLD) {
+		diff_exponent = DBLEXT_THRESHOLD;
+	}
+
+	/* Align right operand by shifting it to the right */
+	Dblext_clear_sign(rightp1);
+	Dblext_right_align(rightp1,rightp2,rightp3,rightp4,
+		/*shifted by*/diff_exponent);
+	
+	/* Treat sum and difference of the operands separately. */
+	if ((int)save < 0) {
+		/*
+		 * Difference of the two operands.  Overflow can occur if the
+		 * multiply overflowed.  A borrow can occur out of the hidden
+		 * bit and force a post normalization phase.
+		 */
+		Dblext_subtract(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+			rightp1,rightp2,rightp3,rightp4,
+			resultp1,resultp2,resultp3,resultp4);
+		sign_save = Dbl_signextendedsign(resultp1);
+		if (Dbl_iszero_hidden(resultp1)) {
+			/* Handle normalization */
+		/* A straight foward algorithm would now shift the
+		 * result and extension left until the hidden bit
+		 * becomes one.  Not all of the extension bits need
+		 * participate in the shift.  Only the two most 
+		 * significant bits (round and guard) are needed.
+		 * If only a single shift is needed then the guard
+		 * bit becomes a significant low order bit and the
+		 * extension must participate in the rounding.
+		 * If more than a single shift is needed, then all
+		 * bits to the right of the guard bit are zeros, 
+		 * and the guard bit may or may not be zero. */
+			Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+				resultp4);
+
+			/* Need to check for a zero result.  The sign and
+			 * exponent fields have already been zeroed.  The more
+			 * efficient test of the full object can be used.
+			 */
+			 if (Dblext_iszero(resultp1,resultp2,resultp3,resultp4)) {
+				/* Must have been "x-x" or "x+(-x)". */
+				if (Is_rounding_mode(ROUNDMINUS))
+					Dbl_setone_sign(resultp1);
+				Dbl_copytoptr(resultp1,resultp2,dstptr);
+				return(NOEXCEPTION);
+			}
+			result_exponent--;
+
+			/* Look to see if normalization is finished. */
+			if (Dbl_isone_hidden(resultp1)) {
+				/* No further normalization is needed */
+				goto round;
+			}
+
+			/* Discover first one bit to determine shift amount.
+			 * Use a modified binary search.  We have already
+			 * shifted the result one position right and still
+			 * not found a one so the remainder of the extension
+			 * must be zero and simplifies rounding. */
+			/* Scan bytes */
+			while (Dbl_iszero_hiddenhigh7mantissa(resultp1)) {
+				Dblext_leftshiftby8(resultp1,resultp2,resultp3,resultp4);
+				result_exponent -= 8;
+			}
+			/* Now narrow it down to the nibble */
+			if (Dbl_iszero_hiddenhigh3mantissa(resultp1)) {
+				/* The lower nibble contains the
+				 * normalizing one */
+				Dblext_leftshiftby4(resultp1,resultp2,resultp3,resultp4);
+				result_exponent -= 4;
+			}
+			/* Select case where first bit is set (already
+			 * normalized) otherwise select the proper shift. */
+			jumpsize = Dbl_hiddenhigh3mantissa(resultp1);
+			if (jumpsize <= 7) switch(jumpsize) {
+			case 1:
+				Dblext_leftshiftby3(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 3;
+				break;
+			case 2:
+			case 3:
+				Dblext_leftshiftby2(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 2;
+				break;
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+					resultp4);
+				result_exponent -= 1;
+				break;
+			}
+		} /* end if (hidden...)... */
+	/* Fall through and round */
+	} /* end if (save < 0)... */
+	else {
+		/* Add magnitudes */
+		Dblext_addition(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+			rightp1,rightp2,rightp3,rightp4,
+			/*to*/resultp1,resultp2,resultp3,resultp4);
+		sign_save = Dbl_signextendedsign(resultp1);
+		if (Dbl_isone_hiddenoverflow(resultp1)) {
+	    		/* Prenormalization required. */
+	    		Dblext_arithrightshiftby1(resultp1,resultp2,resultp3,
+				resultp4);
+	    		result_exponent++;
+		} /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+
+	/* Round the result.  If the extension and lower two words are
+	 * all zeros, then the result is exact.  Otherwise round in the
+	 * correct direction.  Underflow is possible. If a postnormalization
+	 * is necessary, then the mantissa is all zeros so no shift is needed.
+	 */
+  round:
+	if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+		Dblext_denormalize(resultp1,resultp2,resultp3,resultp4,
+			result_exponent,is_tiny);
+	}
+	Dbl_set_sign(resultp1,/*using*/sign_save);
+	if (Dblext_isnotzero_mantissap3(resultp3) || 
+	    Dblext_isnotzero_mantissap4(resultp4)) {
+		inexact = TRUE;
+		switch(Rounding_mode()) {
+		case ROUNDNEAREST: /* The default. */
+			if (Dblext_isone_highp3(resultp3)) {
+				/* at least 1/2 ulp */
+				if (Dblext_isnotzero_low31p3(resultp3) ||
+				    Dblext_isnotzero_mantissap4(resultp4) ||
+				    Dblext_isone_lowp2(resultp2)) {
+					/* either exactly half way and odd or
+					 * more than 1/2ulp */
+					Dbl_increment(resultp1,resultp2);
+				}
+			}
+	    		break;
+
+		case ROUNDPLUS:
+	    		if (Dbl_iszero_sign(resultp1)) {
+				/* Round up positive results */
+				Dbl_increment(resultp1,resultp2);
+			}
+			break;
+	    
+		case ROUNDMINUS:
+	    		if (Dbl_isone_sign(resultp1)) {
+				/* Round down negative results */
+				Dbl_increment(resultp1,resultp2);
+			}
+	    
+		case ROUNDZERO:;
+			/* truncate is simple */
+		} /* end switch... */
+		if (Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+	if (result_exponent >= DBL_INFINITY_EXPONENT) {
+		/* Overflow */
+		if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+                        Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_OVERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return (OPC_2E_OVERFLOWEXCEPTION);
+		}
+		inexact = TRUE;
+		Set_overflowflag();
+		Dbl_setoverflow(resultp1,resultp2);
+	} else if (result_exponent <= 0) {	/* underflow case */
+		if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                	Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+			Dbl_copytoptr(resultp1,resultp2,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_UNDERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+	    		return(OPC_2E_UNDERFLOWEXCEPTION);
+		}
+		else if (inexact && is_tiny) Set_underflowflag();
+	}
+	else Dbl_set_exponent(resultp1,result_exponent);
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) 
+		if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+		else Set_inexactflag();
+    	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point Multiply Fused Add
+ */
+
+sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+
+sgl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
+unsigned int *status;
+{
+	unsigned int opnd1, opnd2, opnd3;
+	register unsigned int tmpresp1, tmpresp2;
+	unsigned int rightp1, rightp2;
+	unsigned int resultp1, resultp2 = 0;
+	register int mpy_exponent, add_exponent, count;
+	boolean inexact = FALSE, is_tiny = FALSE;
+
+	unsigned int signlessleft1, signlessright1, save;
+	register int result_exponent, diff_exponent;
+	int sign_save, jumpsize;
+	
+	Sgl_copyfromptr(src1ptr,opnd1);
+	Sgl_copyfromptr(src2ptr,opnd2);
+	Sgl_copyfromptr(src3ptr,opnd3);
+
+	/* 
+	 * set sign bit of result of multiply
+	 */
+	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) 
+		Sgl_setnegativezero(resultp1); 
+	else Sgl_setzero(resultp1);
+
+	/*
+	 * Generate multiply exponent 
+	 */
+	mpy_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
+
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd1)) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2) && Sgl_isnotnan(opnd3)) {
+				if (Sgl_iszero_exponentmantissa(opnd2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Sgl_isinfinity(opnd3) &&
+				    (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+			 	 * return infinity
+			 	 */
+				Sgl_setinfinity_exponentmantissa(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+		 	 * is NaN; signaling or quiet?
+		 	 */
+			if (Sgl_isone_signaling(opnd1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled()) 
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd1);
+			}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd2);
+				Sgl_copytoptr(opnd2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd3)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd3);
+				Sgl_copytoptr(opnd3,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+		 	 * return quiet NaN
+		 	 */
+			Sgl_copytoptr(opnd1,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd2)) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			if (Sgl_isnotnan(opnd3)) {
+				if (Sgl_iszero_exponentmantissa(opnd1)) {
+					/* 
+					 * invalid since multiply operands are
+					 * zero & infinity
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(opnd2);
+					Sgl_copytoptr(opnd2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Sgl_isinfinity(opnd3) &&
+				    (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+				       		return(OPC_2E_INVALIDEXCEPTION);
+				       	Set_invalidflag();
+				       	Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * return infinity
+				 */
+				Sgl_setinfinity_exponentmantissa(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(opnd2)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd2);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd3)) {
+			       	/* trap if INVALIDTRAP enabled */
+			       	if (Is_invalidtrap_enabled())
+				   		return(OPC_2E_INVALIDEXCEPTION);
+			       	/* make NaN quiet */
+			       	Set_invalidflag();
+			       	Sgl_set_quiet(opnd3);
+				Sgl_copytoptr(opnd3,dstptr);
+		       		return(NOEXCEPTION);
+			}
+			/*
+			 * return quiet NaN
+			 */
+			Sgl_copytoptr(opnd2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check third operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd3)) {
+		if (Sgl_iszero_mantissa(opnd3)) {
+			/* return infinity */
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		} else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(opnd3)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd3);
+			}
+			/*
+			 * return quiet NaN
+ 			 */
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+    	}
+
+	/*
+	 * Generate multiply mantissa
+	 */
+	if (Sgl_isnotzero_exponent(opnd1)) {
+		/* set hidden bit */
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Sgl_iszero_exponentmantissa(opnd3)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Sgl_or_signs(opnd3,resultp1);
+				} else {
+					Sgl_and_signs(opnd3,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Sgl_iszero_exponent(opnd3) &&
+			         Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Sgl_signextendedsign(opnd3);
+				result_exponent = 0;
+                    		Sgl_leftshiftby1(opnd3);
+                    		Sgl_normalize(opnd3,result_exponent);
+                    		Sgl_set_sign(opnd3,/*using*/sign_save);
+                    		Sgl_setwrapped_exponent(opnd3,result_exponent,
+							unfl);
+                    		Sgl_copytoptr(opnd3,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized, adjust exponent */
+		Sgl_clear_signexponent(opnd1);
+		Sgl_leftshiftby1(opnd1);
+		Sgl_normalize(opnd1,mpy_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Sgl_isnotzero_exponent(opnd2)) {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Sgl_iszero_exponentmantissa(opnd3)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Sgl_or_signs(opnd3,resultp1);
+				} else {
+					Sgl_and_signs(opnd3,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Sgl_iszero_exponent(opnd3) &&
+			    Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Sgl_signextendedsign(opnd3);
+				result_exponent = 0;
+                    		Sgl_leftshiftby1(opnd3);
+                    		Sgl_normalize(opnd3,result_exponent);
+                    		Sgl_set_sign(opnd3,/*using*/sign_save);
+                    		Sgl_setwrapped_exponent(opnd3,result_exponent,
+							unfl);
+                    		Sgl_copytoptr(opnd3,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized; want to normalize */
+		Sgl_clear_signexponent(opnd2);
+		Sgl_leftshiftby1(opnd2);
+		Sgl_normalize(opnd2,mpy_exponent);
+	}
+
+	/* Multiply the first two source mantissas together */
+
+	/* 
+	 * The intermediate result will be kept in tmpres,
+	 * which needs enough room for 106 bits of mantissa,
+	 * so lets call it a Double extended.
+	 */
+	Sglext_setzero(tmpresp1,tmpresp2);
+
+	/* 
+	 * Four bits at a time are inspected in each loop, and a 
+	 * simple shift and add multiply algorithm is used. 
+	 */ 
+	for (count = SGL_P-1; count >= 0; count -= 4) {
+		Sglext_rightshiftby4(tmpresp1,tmpresp2);
+		if (Sbit28(opnd1)) {
+	 		/* Twoword_add should be an ADD followed by 2 ADDC's */
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<3, 0);
+		}
+		if (Sbit29(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<2, 0);
+		}
+		if (Sbit30(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<1, 0);
+		}
+		if (Sbit31(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2, 0);
+		}
+		Sgl_rightshiftby4(opnd1);
+	}
+	if (Is_sexthiddenoverflow(tmpresp1)) {
+		/* result mantissa >= 2 (mantissa overflow) */
+		mpy_exponent++;
+		Sglext_rightshiftby4(tmpresp1,tmpresp2);
+	} else {
+		Sglext_rightshiftby3(tmpresp1,tmpresp2);
+	}
+
+	/*
+	 * Restore the sign of the mpy result which was saved in resultp1.
+	 * The exponent will continue to be kept in mpy_exponent.
+	 */
+	Sglext_set_sign(tmpresp1,Sgl_sign(resultp1));
+
+	/* 
+	 * No rounding is required, since the result of the multiply
+	 * is exact in the extended format.
+	 */
+
+	/*
+	 * Now we are ready to perform the add portion of the operation.
+	 *
+	 * The exponents need to be kept as integers for now, since the
+	 * multiply result might not fit into the exponent field.  We
+	 * can't overflow or underflow because of this yet, since the
+	 * add could bring the final result back into range.
+	 */
+	add_exponent = Sgl_exponent(opnd3);
+
+	/*
+	 * Check for denormalized or zero add operand.
+	 */
+	if (add_exponent == 0) {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd3)) {
+			/* right is zero */
+			/* Left can't be zero and must be result.
+			 *
+			 * The final result is now in tmpres and mpy_exponent,
+			 * and needs to be rounded and squeezed back into
+			 * double precision format from double extended.
+			 */
+			result_exponent = mpy_exponent;
+			Sglext_copy(tmpresp1,tmpresp2,resultp1,resultp2);
+			sign_save = Sgl_signextendedsign(resultp1);/*save sign*/
+			goto round;
+		}
+
+		/* 
+		 * Neither are zeroes.  
+		 * Adjust exponent and normalize add operand.
+		 */
+		sign_save = Sgl_signextendedsign(opnd3);	/* save sign */
+		Sgl_clear_signexponent(opnd3);
+		Sgl_leftshiftby1(opnd3);
+		Sgl_normalize(opnd3,add_exponent);
+		Sgl_set_sign(opnd3,sign_save);		/* restore sign */
+	} else {
+		Sgl_clear_exponent_set_hidden(opnd3);
+	}
+	/*
+	 * Copy opnd3 to the double extended variable called right.
+	 */
+	Sgl_copyto_sglext(opnd3,rightp1,rightp2);
+
+	/*
+	 * A zero "save" helps discover equal operands (for later),
+	 * and is used in swapping operands (if needed).
+	 */
+	Sglext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+	/*
+	 * Compare magnitude of operands.
+	 */
+	Sglext_copytoint_exponentmantissa(tmpresp1,signlessleft1);
+	Sglext_copytoint_exponentmantissa(rightp1,signlessright1);
+	if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+	    Sglext_ismagnitudeless(signlessleft1,signlessright1)) {
+		/*
+		 * Set the left operand to the larger one by XOR swap.
+		 * First finish the first word "save".
+		 */
+		Sglext_xorfromintp1(save,rightp1,/*to*/rightp1);
+		Sglext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+		Sglext_swap_lower(tmpresp2,rightp2);
+		/* also setup exponents used in rest of routine */
+		diff_exponent = add_exponent - mpy_exponent;
+		result_exponent = add_exponent;
+	} else {
+		/* also setup exponents used in rest of routine */
+		diff_exponent = mpy_exponent - add_exponent;
+		result_exponent = mpy_exponent;
+	}
+	/* Invariant: left is not smaller than right. */
+
+	/*
+	 * Special case alignment of operands that would force alignment
+	 * beyond the extent of the extension.  A further optimization
+	 * could special case this but only reduces the path length for
+	 * this infrequent case.
+	 */
+	if (diff_exponent > SGLEXT_THRESHOLD) {
+		diff_exponent = SGLEXT_THRESHOLD;
+	}
+
+	/* Align right operand by shifting it to the right */
+	Sglext_clear_sign(rightp1);
+	Sglext_right_align(rightp1,rightp2,/*shifted by*/diff_exponent);
+	
+	/* Treat sum and difference of the operands separately. */
+	if ((int)save < 0) {
+		/*
+		 * Difference of the two operands.  Overflow can occur if the
+		 * multiply overflowed.  A borrow can occur out of the hidden
+		 * bit and force a post normalization phase.
+		 */
+		Sglext_subtract(tmpresp1,tmpresp2, rightp1,rightp2,
+			resultp1,resultp2);
+		sign_save = Sgl_signextendedsign(resultp1);
+		if (Sgl_iszero_hidden(resultp1)) {
+			/* Handle normalization */
+		/* A straight foward algorithm would now shift the
+		 * result and extension left until the hidden bit
+		 * becomes one.  Not all of the extension bits need
+		 * participate in the shift.  Only the two most 
+		 * significant bits (round and guard) are needed.
+		 * If only a single shift is needed then the guard
+		 * bit becomes a significant low order bit and the
+		 * extension must participate in the rounding.
+		 * If more than a single shift is needed, then all
+		 * bits to the right of the guard bit are zeros, 
+		 * and the guard bit may or may not be zero. */
+			Sglext_leftshiftby1(resultp1,resultp2);
+
+			/* Need to check for a zero result.  The sign and
+			 * exponent fields have already been zeroed.  The more
+			 * efficient test of the full object can be used.
+			 */
+			 if (Sglext_iszero(resultp1,resultp2)) {
+				/* Must have been "x-x" or "x+(-x)". */
+				if (Is_rounding_mode(ROUNDMINUS))
+					Sgl_setone_sign(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+			result_exponent--;
+
+			/* Look to see if normalization is finished. */
+			if (Sgl_isone_hidden(resultp1)) {
+				/* No further normalization is needed */
+				goto round;
+			}
+
+			/* Discover first one bit to determine shift amount.
+			 * Use a modified binary search.  We have already
+			 * shifted the result one position right and still
+			 * not found a one so the remainder of the extension
+			 * must be zero and simplifies rounding. */
+			/* Scan bytes */
+			while (Sgl_iszero_hiddenhigh7mantissa(resultp1)) {
+				Sglext_leftshiftby8(resultp1,resultp2);
+				result_exponent -= 8;
+			}
+			/* Now narrow it down to the nibble */
+			if (Sgl_iszero_hiddenhigh3mantissa(resultp1)) {
+				/* The lower nibble contains the
+				 * normalizing one */
+				Sglext_leftshiftby4(resultp1,resultp2);
+				result_exponent -= 4;
+			}
+			/* Select case where first bit is set (already
+			 * normalized) otherwise select the proper shift. */
+			jumpsize = Sgl_hiddenhigh3mantissa(resultp1);
+			if (jumpsize <= 7) switch(jumpsize) {
+			case 1:
+				Sglext_leftshiftby3(resultp1,resultp2);
+				result_exponent -= 3;
+				break;
+			case 2:
+			case 3:
+				Sglext_leftshiftby2(resultp1,resultp2);
+				result_exponent -= 2;
+				break;
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				Sglext_leftshiftby1(resultp1,resultp2);
+				result_exponent -= 1;
+				break;
+			}
+		} /* end if (hidden...)... */
+	/* Fall through and round */
+	} /* end if (save < 0)... */
+	else {
+		/* Add magnitudes */
+		Sglext_addition(tmpresp1,tmpresp2,
+			rightp1,rightp2, /*to*/resultp1,resultp2);
+		sign_save = Sgl_signextendedsign(resultp1);
+		if (Sgl_isone_hiddenoverflow(resultp1)) {
+	    		/* Prenormalization required. */
+	    		Sglext_arithrightshiftby1(resultp1,resultp2);
+	    		result_exponent++;
+		} /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+
+	/* Round the result.  If the extension and lower two words are
+	 * all zeros, then the result is exact.  Otherwise round in the
+	 * correct direction.  Underflow is possible. If a postnormalization
+	 * is necessary, then the mantissa is all zeros so no shift is needed.
+	 */
+  round:
+	if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+		Sglext_denormalize(resultp1,resultp2,result_exponent,is_tiny);
+	}
+	Sgl_set_sign(resultp1,/*using*/sign_save);
+	if (Sglext_isnotzero_mantissap2(resultp2)) {
+		inexact = TRUE;
+		switch(Rounding_mode()) {
+		case ROUNDNEAREST: /* The default. */
+			if (Sglext_isone_highp2(resultp2)) {
+				/* at least 1/2 ulp */
+				if (Sglext_isnotzero_low31p2(resultp2) ||
+				    Sglext_isone_lowp1(resultp1)) {
+					/* either exactly half way and odd or
+					 * more than 1/2ulp */
+					Sgl_increment(resultp1);
+				}
+			}
+	    		break;
+
+		case ROUNDPLUS:
+	    		if (Sgl_iszero_sign(resultp1)) {
+				/* Round up positive results */
+				Sgl_increment(resultp1);
+			}
+			break;
+	    
+		case ROUNDMINUS:
+	    		if (Sgl_isone_sign(resultp1)) {
+				/* Round down negative results */
+				Sgl_increment(resultp1);
+			}
+	    
+		case ROUNDZERO:;
+			/* truncate is simple */
+		} /* end switch... */
+		if (Sgl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+	if (result_exponent >= SGL_INFINITY_EXPONENT) {
+		/* Overflow */
+		if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+                        Sgl_copytoptr(resultp1,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_OVERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return (OPC_2E_OVERFLOWEXCEPTION);
+		}
+		inexact = TRUE;
+		Set_overflowflag();
+		Sgl_setoverflow(resultp1);
+	} else if (result_exponent <= 0) {	/* underflow case */
+		if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                	Sgl_setwrapped_exponent(resultp1,result_exponent,unfl);
+			Sgl_copytoptr(resultp1,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_UNDERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+	    		return(OPC_2E_UNDERFLOWEXCEPTION);
+		}
+		else if (inexact && is_tiny) Set_underflowflag();
+	}
+	else Sgl_set_exponent(resultp1,result_exponent);
+	Sgl_copytoptr(resultp1,dstptr);
+	if (inexact) 
+		if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+		else Set_inexactflag();
+    	return(NOEXCEPTION);
+}
+
+/*
+ *  Single Floating-point Multiply Negate Fused Add
+ */
+
+sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+
+sgl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
+unsigned int *status;
+{
+	unsigned int opnd1, opnd2, opnd3;
+	register unsigned int tmpresp1, tmpresp2;
+	unsigned int rightp1, rightp2;
+	unsigned int resultp1, resultp2 = 0;
+	register int mpy_exponent, add_exponent, count;
+	boolean inexact = FALSE, is_tiny = FALSE;
+
+	unsigned int signlessleft1, signlessright1, save;
+	register int result_exponent, diff_exponent;
+	int sign_save, jumpsize;
+	
+	Sgl_copyfromptr(src1ptr,opnd1);
+	Sgl_copyfromptr(src2ptr,opnd2);
+	Sgl_copyfromptr(src3ptr,opnd3);
+
+	/* 
+	 * set sign bit of result of multiply
+	 */
+	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) 
+		Sgl_setzero(resultp1);
+	else 
+		Sgl_setnegativezero(resultp1); 
+
+	/*
+	 * Generate multiply exponent 
+	 */
+	mpy_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
+
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd1)) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2) && Sgl_isnotnan(opnd3)) {
+				if (Sgl_iszero_exponentmantissa(opnd2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Sgl_isinfinity(opnd3) &&
+				    (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+			 	 * return infinity
+			 	 */
+				Sgl_setinfinity_exponentmantissa(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+		 	 * is NaN; signaling or quiet?
+		 	 */
+			if (Sgl_isone_signaling(opnd1)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled()) 
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd1);
+			}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd2);
+				Sgl_copytoptr(opnd2,dstptr);
+				return(NOEXCEPTION);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd3)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+			    		return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd3);
+				Sgl_copytoptr(opnd3,dstptr);
+				return(NOEXCEPTION);
+			}
+			/*
+		 	 * return quiet NaN
+		 	 */
+			Sgl_copytoptr(opnd1,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd2)) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			if (Sgl_isnotnan(opnd3)) {
+				if (Sgl_iszero_exponentmantissa(opnd1)) {
+					/* 
+					 * invalid since multiply operands are
+					 * zero & infinity
+					 */
+					if (Is_invalidtrap_enabled())
+						return(OPC_2E_INVALIDEXCEPTION);
+					Set_invalidflag();
+					Sgl_makequietnan(opnd2);
+					Sgl_copytoptr(opnd2,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * Check third operand for infinity with a
+				 *  sign opposite of the multiply result
+				 */
+				if (Sgl_isinfinity(opnd3) &&
+				    (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+					/* 
+					 * invalid since attempting a magnitude
+					 * subtraction of infinities
+					 */
+					if (Is_invalidtrap_enabled())
+				       		return(OPC_2E_INVALIDEXCEPTION);
+				       	Set_invalidflag();
+				       	Sgl_makequietnan(resultp1);
+					Sgl_copytoptr(resultp1,dstptr);
+					return(NOEXCEPTION);
+				}
+
+				/*
+				 * return infinity
+				 */
+				Sgl_setinfinity_exponentmantissa(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(opnd2)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd2);
+			}
+			/* 
+			 * is third operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd3)) {
+			       	/* trap if INVALIDTRAP enabled */
+			       	if (Is_invalidtrap_enabled())
+				   		return(OPC_2E_INVALIDEXCEPTION);
+			       	/* make NaN quiet */
+			       	Set_invalidflag();
+			       	Sgl_set_quiet(opnd3);
+				Sgl_copytoptr(opnd3,dstptr);
+		       		return(NOEXCEPTION);
+			}
+			/*
+			 * return quiet NaN
+			 */
+			Sgl_copytoptr(opnd2,dstptr);
+			return(NOEXCEPTION);
+		}
+	}
+
+	/*
+	 * check third operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd3)) {
+		if (Sgl_iszero_mantissa(opnd3)) {
+			/* return infinity */
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		} else {
+			/*
+			 * is NaN; signaling or quiet?
+			 */
+			if (Sgl_isone_signaling(opnd3)) {
+				/* trap if INVALIDTRAP enabled */
+				if (Is_invalidtrap_enabled())
+					return(OPC_2E_INVALIDEXCEPTION);
+				/* make NaN quiet */
+				Set_invalidflag();
+				Sgl_set_quiet(opnd3);
+			}
+			/*
+			 * return quiet NaN
+ 			 */
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+    	}
+
+	/*
+	 * Generate multiply mantissa
+	 */
+	if (Sgl_isnotzero_exponent(opnd1)) {
+		/* set hidden bit */
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Sgl_iszero_exponentmantissa(opnd3)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Sgl_or_signs(opnd3,resultp1);
+				} else {
+					Sgl_and_signs(opnd3,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Sgl_iszero_exponent(opnd3) &&
+			         Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Sgl_signextendedsign(opnd3);
+				result_exponent = 0;
+                    		Sgl_leftshiftby1(opnd3);
+                    		Sgl_normalize(opnd3,result_exponent);
+                    		Sgl_set_sign(opnd3,/*using*/sign_save);
+                    		Sgl_setwrapped_exponent(opnd3,result_exponent,
+							unfl);
+                    		Sgl_copytoptr(opnd3,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized, adjust exponent */
+		Sgl_clear_signexponent(opnd1);
+		Sgl_leftshiftby1(opnd1);
+		Sgl_normalize(opnd1,mpy_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Sgl_isnotzero_exponent(opnd2)) {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd2)) {
+			/*
+			 * Perform the add opnd3 with zero here.
+			 */
+			if (Sgl_iszero_exponentmantissa(opnd3)) {
+				if (Is_rounding_mode(ROUNDMINUS)) {
+					Sgl_or_signs(opnd3,resultp1);
+				} else {
+					Sgl_and_signs(opnd3,resultp1);
+				}
+			}
+			/*
+			 * Now let's check for trapped underflow case.
+			 */
+			else if (Sgl_iszero_exponent(opnd3) &&
+			    Is_underflowtrap_enabled()) {
+                    		/* need to normalize results mantissa */
+                    		sign_save = Sgl_signextendedsign(opnd3);
+				result_exponent = 0;
+                    		Sgl_leftshiftby1(opnd3);
+                    		Sgl_normalize(opnd3,result_exponent);
+                    		Sgl_set_sign(opnd3,/*using*/sign_save);
+                    		Sgl_setwrapped_exponent(opnd3,result_exponent,
+							unfl);
+                    		Sgl_copytoptr(opnd3,dstptr);
+                    		/* inexact = FALSE */
+                    		return(OPC_2E_UNDERFLOWEXCEPTION);
+			}
+			Sgl_copytoptr(opnd3,dstptr);
+			return(NOEXCEPTION);
+		}
+		/* is denormalized; want to normalize */
+		Sgl_clear_signexponent(opnd2);
+		Sgl_leftshiftby1(opnd2);
+		Sgl_normalize(opnd2,mpy_exponent);
+	}
+
+	/* Multiply the first two source mantissas together */
+
+	/* 
+	 * The intermediate result will be kept in tmpres,
+	 * which needs enough room for 106 bits of mantissa,
+	 * so lets call it a Double extended.
+	 */
+	Sglext_setzero(tmpresp1,tmpresp2);
+
+	/* 
+	 * Four bits at a time are inspected in each loop, and a 
+	 * simple shift and add multiply algorithm is used. 
+	 */ 
+	for (count = SGL_P-1; count >= 0; count -= 4) {
+		Sglext_rightshiftby4(tmpresp1,tmpresp2);
+		if (Sbit28(opnd1)) {
+	 		/* Twoword_add should be an ADD followed by 2 ADDC's */
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<3, 0);
+		}
+		if (Sbit29(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<2, 0);
+		}
+		if (Sbit30(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2<<1, 0);
+		}
+		if (Sbit31(opnd1)) {
+			Twoword_add(tmpresp1, tmpresp2, opnd2, 0);
+		}
+		Sgl_rightshiftby4(opnd1);
+	}
+	if (Is_sexthiddenoverflow(tmpresp1)) {
+		/* result mantissa >= 2 (mantissa overflow) */
+		mpy_exponent++;
+		Sglext_rightshiftby4(tmpresp1,tmpresp2);
+	} else {
+		Sglext_rightshiftby3(tmpresp1,tmpresp2);
+	}
+
+	/*
+	 * Restore the sign of the mpy result which was saved in resultp1.
+	 * The exponent will continue to be kept in mpy_exponent.
+	 */
+	Sglext_set_sign(tmpresp1,Sgl_sign(resultp1));
+
+	/* 
+	 * No rounding is required, since the result of the multiply
+	 * is exact in the extended format.
+	 */
+
+	/*
+	 * Now we are ready to perform the add portion of the operation.
+	 *
+	 * The exponents need to be kept as integers for now, since the
+	 * multiply result might not fit into the exponent field.  We
+	 * can't overflow or underflow because of this yet, since the
+	 * add could bring the final result back into range.
+	 */
+	add_exponent = Sgl_exponent(opnd3);
+
+	/*
+	 * Check for denormalized or zero add operand.
+	 */
+	if (add_exponent == 0) {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd3)) {
+			/* right is zero */
+			/* Left can't be zero and must be result.
+			 *
+			 * The final result is now in tmpres and mpy_exponent,
+			 * and needs to be rounded and squeezed back into
+			 * double precision format from double extended.
+			 */
+			result_exponent = mpy_exponent;
+			Sglext_copy(tmpresp1,tmpresp2,resultp1,resultp2);
+			sign_save = Sgl_signextendedsign(resultp1);/*save sign*/
+			goto round;
+		}
+
+		/* 
+		 * Neither are zeroes.  
+		 * Adjust exponent and normalize add operand.
+		 */
+		sign_save = Sgl_signextendedsign(opnd3);	/* save sign */
+		Sgl_clear_signexponent(opnd3);
+		Sgl_leftshiftby1(opnd3);
+		Sgl_normalize(opnd3,add_exponent);
+		Sgl_set_sign(opnd3,sign_save);		/* restore sign */
+	} else {
+		Sgl_clear_exponent_set_hidden(opnd3);
+	}
+	/*
+	 * Copy opnd3 to the double extended variable called right.
+	 */
+	Sgl_copyto_sglext(opnd3,rightp1,rightp2);
+
+	/*
+	 * A zero "save" helps discover equal operands (for later),
+	 * and is used in swapping operands (if needed).
+	 */
+	Sglext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+	/*
+	 * Compare magnitude of operands.
+	 */
+	Sglext_copytoint_exponentmantissa(tmpresp1,signlessleft1);
+	Sglext_copytoint_exponentmantissa(rightp1,signlessright1);
+	if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+	    Sglext_ismagnitudeless(signlessleft1,signlessright1)) {
+		/*
+		 * Set the left operand to the larger one by XOR swap.
+		 * First finish the first word "save".
+		 */
+		Sglext_xorfromintp1(save,rightp1,/*to*/rightp1);
+		Sglext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+		Sglext_swap_lower(tmpresp2,rightp2);
+		/* also setup exponents used in rest of routine */
+		diff_exponent = add_exponent - mpy_exponent;
+		result_exponent = add_exponent;
+	} else {
+		/* also setup exponents used in rest of routine */
+		diff_exponent = mpy_exponent - add_exponent;
+		result_exponent = mpy_exponent;
+	}
+	/* Invariant: left is not smaller than right. */
+
+	/*
+	 * Special case alignment of operands that would force alignment
+	 * beyond the extent of the extension.  A further optimization
+	 * could special case this but only reduces the path length for
+	 * this infrequent case.
+	 */
+	if (diff_exponent > SGLEXT_THRESHOLD) {
+		diff_exponent = SGLEXT_THRESHOLD;
+	}
+
+	/* Align right operand by shifting it to the right */
+	Sglext_clear_sign(rightp1);
+	Sglext_right_align(rightp1,rightp2,/*shifted by*/diff_exponent);
+	
+	/* Treat sum and difference of the operands separately. */
+	if ((int)save < 0) {
+		/*
+		 * Difference of the two operands.  Overflow can occur if the
+		 * multiply overflowed.  A borrow can occur out of the hidden
+		 * bit and force a post normalization phase.
+		 */
+		Sglext_subtract(tmpresp1,tmpresp2, rightp1,rightp2,
+			resultp1,resultp2);
+		sign_save = Sgl_signextendedsign(resultp1);
+		if (Sgl_iszero_hidden(resultp1)) {
+			/* Handle normalization */
+		/* A straight foward algorithm would now shift the
+		 * result and extension left until the hidden bit
+		 * becomes one.  Not all of the extension bits need
+		 * participate in the shift.  Only the two most 
+		 * significant bits (round and guard) are needed.
+		 * If only a single shift is needed then the guard
+		 * bit becomes a significant low order bit and the
+		 * extension must participate in the rounding.
+		 * If more than a single shift is needed, then all
+		 * bits to the right of the guard bit are zeros, 
+		 * and the guard bit may or may not be zero. */
+			Sglext_leftshiftby1(resultp1,resultp2);
+
+			/* Need to check for a zero result.  The sign and
+			 * exponent fields have already been zeroed.  The more
+			 * efficient test of the full object can be used.
+			 */
+			 if (Sglext_iszero(resultp1,resultp2)) {
+				/* Must have been "x-x" or "x+(-x)". */
+				if (Is_rounding_mode(ROUNDMINUS))
+					Sgl_setone_sign(resultp1);
+				Sgl_copytoptr(resultp1,dstptr);
+				return(NOEXCEPTION);
+			}
+			result_exponent--;
+
+			/* Look to see if normalization is finished. */
+			if (Sgl_isone_hidden(resultp1)) {
+				/* No further normalization is needed */
+				goto round;
+			}
+
+			/* Discover first one bit to determine shift amount.
+			 * Use a modified binary search.  We have already
+			 * shifted the result one position right and still
+			 * not found a one so the remainder of the extension
+			 * must be zero and simplifies rounding. */
+			/* Scan bytes */
+			while (Sgl_iszero_hiddenhigh7mantissa(resultp1)) {
+				Sglext_leftshiftby8(resultp1,resultp2);
+				result_exponent -= 8;
+			}
+			/* Now narrow it down to the nibble */
+			if (Sgl_iszero_hiddenhigh3mantissa(resultp1)) {
+				/* The lower nibble contains the
+				 * normalizing one */
+				Sglext_leftshiftby4(resultp1,resultp2);
+				result_exponent -= 4;
+			}
+			/* Select case where first bit is set (already
+			 * normalized) otherwise select the proper shift. */
+			jumpsize = Sgl_hiddenhigh3mantissa(resultp1);
+			if (jumpsize <= 7) switch(jumpsize) {
+			case 1:
+				Sglext_leftshiftby3(resultp1,resultp2);
+				result_exponent -= 3;
+				break;
+			case 2:
+			case 3:
+				Sglext_leftshiftby2(resultp1,resultp2);
+				result_exponent -= 2;
+				break;
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				Sglext_leftshiftby1(resultp1,resultp2);
+				result_exponent -= 1;
+				break;
+			}
+		} /* end if (hidden...)... */
+	/* Fall through and round */
+	} /* end if (save < 0)... */
+	else {
+		/* Add magnitudes */
+		Sglext_addition(tmpresp1,tmpresp2,
+			rightp1,rightp2, /*to*/resultp1,resultp2);
+		sign_save = Sgl_signextendedsign(resultp1);
+		if (Sgl_isone_hiddenoverflow(resultp1)) {
+	    		/* Prenormalization required. */
+	    		Sglext_arithrightshiftby1(resultp1,resultp2);
+	    		result_exponent++;
+		} /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+
+	/* Round the result.  If the extension and lower two words are
+	 * all zeros, then the result is exact.  Otherwise round in the
+	 * correct direction.  Underflow is possible. If a postnormalization
+	 * is necessary, then the mantissa is all zeros so no shift is needed.
+	 */
+  round:
+	if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+		Sglext_denormalize(resultp1,resultp2,result_exponent,is_tiny);
+	}
+	Sgl_set_sign(resultp1,/*using*/sign_save);
+	if (Sglext_isnotzero_mantissap2(resultp2)) {
+		inexact = TRUE;
+		switch(Rounding_mode()) {
+		case ROUNDNEAREST: /* The default. */
+			if (Sglext_isone_highp2(resultp2)) {
+				/* at least 1/2 ulp */
+				if (Sglext_isnotzero_low31p2(resultp2) ||
+				    Sglext_isone_lowp1(resultp1)) {
+					/* either exactly half way and odd or
+					 * more than 1/2ulp */
+					Sgl_increment(resultp1);
+				}
+			}
+	    		break;
+
+		case ROUNDPLUS:
+	    		if (Sgl_iszero_sign(resultp1)) {
+				/* Round up positive results */
+				Sgl_increment(resultp1);
+			}
+			break;
+	    
+		case ROUNDMINUS:
+	    		if (Sgl_isone_sign(resultp1)) {
+				/* Round down negative results */
+				Sgl_increment(resultp1);
+			}
+	    
+		case ROUNDZERO:;
+			/* truncate is simple */
+		} /* end switch... */
+		if (Sgl_isone_hiddenoverflow(resultp1)) result_exponent++;
+	}
+	if (result_exponent >= SGL_INFINITY_EXPONENT) {
+		/* Overflow */
+		if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+                        Sgl_copytoptr(resultp1,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_OVERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return (OPC_2E_OVERFLOWEXCEPTION);
+		}
+		inexact = TRUE;
+		Set_overflowflag();
+		Sgl_setoverflow(resultp1);
+	} else if (result_exponent <= 0) {	/* underflow case */
+		if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                	Sgl_setwrapped_exponent(resultp1,result_exponent,unfl);
+			Sgl_copytoptr(resultp1,dstptr);
+                        if (inexact)
+                            if (Is_inexacttrap_enabled())
+                                return (OPC_2E_UNDERFLOWEXCEPTION |
+					OPC_2E_INEXACTEXCEPTION);
+                            else Set_inexactflag();
+	    		return(OPC_2E_UNDERFLOWEXCEPTION);
+		}
+		else if (inexact && is_tiny) Set_underflowflag();
+	}
+	else Sgl_set_exponent(resultp1,result_exponent);
+	Sgl_copytoptr(resultp1,dstptr);
+	if (inexact) 
+		if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+		else Set_inexactflag();
+    	return(NOEXCEPTION);
+}
+
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fpbits.h linux-2.4.20-pre2/arch/parisc/math-emu/fpbits.h
--- linux-2.4.20-pre1/arch/parisc/math-emu/fpbits.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fpbits.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,65 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+
+/*
+ *  These macros are designed to be portable to all machines that have
+ *  a wordsize greater than or equal to 32 bits that support the portable
+ *  C compiler and the standard C preprocessor.  Wordsize (default 32)
+ *  and bitfield assignment (default left-to-right,  unlike VAX, PDP-11)
+ *  should be predefined using the constants HOSTWDSZ and BITFRL and
+ *  the C compiler "-D" flag (e.g., -DHOSTWDSZ=36 -DBITFLR for the DEC-20).
+ *  Note that the macro arguments assume that the integer being referenced
+ *  is a 32-bit integer (right-justified on the 20) and that bit 0 is the
+ *  most significant bit.
+ */
+
+#ifndef HOSTWDSZ
+#define	HOSTWDSZ	32
+#endif
+
+
+/*###########################  Macros  ######################################*/
+
+/*-------------------------------------------------------------------------
+ * NewDeclareBitField_Reference - Declare a structure similar to the simulator
+ * function "DeclBitfR" except its use is restricted to occur within a larger
+ * enclosing structure or union definition.  This declaration is an unnamed
+ * structure with the argument, name, as the member name and the argument,
+ * uname, as the element name. 
+ *----------------------------------------------------------------------- */
+#define Bitfield_extract(start, length, object) 	\
+    ((object) >> (HOSTWDSZ - (start) - (length)) & 	\
+    ((unsigned)-1 >> (HOSTWDSZ - (length))))
+
+#define Bitfield_signed_extract(start, length, object) \
+    ((int)((object) << start) >> (HOSTWDSZ - (length)))
+
+#define Bitfield_mask(start, len, object)		\
+    ((object) & (((unsigned)-1 >> (HOSTWDSZ-len)) << (HOSTWDSZ-start-len)))
+
+#define Bitfield_deposit(value,start,len,object)  object = \
+    ((object) & ~(((unsigned)-1 >> (HOSTWDSZ-len)) << (HOSTWDSZ-start-len))) | \
+    (((value) & ((unsigned)-1 >> (HOSTWDSZ-len))) << (HOSTWDSZ-start-len))
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fpu.h linux-2.4.20-pre2/arch/parisc/math-emu/fpu.h
--- linux-2.4.20-pre1/arch/parisc/math-emu/fpu.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fpu.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,76 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ * 
+ *  File: 
+ *      @(#)	pa/fp/fpu.h		$Revision: 1.2 $
+ * 
+ *  Purpose:
+ *      <<please update with a synopis of the functionality provided by this file>>
+ * 
+ * 
+ * END_DESC  
+*/
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+
+#ifndef _MACHINE_FPU_INCLUDED /* allows multiple inclusion */
+#define _MACHINE_FPU_INCLUDED
+
+#if 0
+#ifndef _SYS_STDSYMS_INCLUDED
+#    include <sys/stdsyms.h>
+#endif   /* _SYS_STDSYMS_INCLUDED  */
+#include  <machine/pdc/pdc_rqsts.h>
+#endif
+
+#define PA83_FPU_FLAG    0x00000001
+#define PA89_FPU_FLAG    0x00000002
+#define PA2_0_FPU_FLAG   0x00000010
+
+#define TIMEX_EXTEN_FLAG 0x00000004
+
+#define ROLEX_EXTEN_FLAG 0x00000008
+#define COPR_FP 	0x00000080	/* Floating point -- Coprocessor 0 */
+#define SFU_MPY_DIVIDE	0x00008000	/* Multiply/Divide __ SFU 0 */
+
+
+#define EM_FPU_TYPE_OFFSET 272
+
+/* version of EMULATION software for COPR,0,0 instruction */
+#define EMULATION_VERSION 4
+
+/*
+ * The only was to differeniate between TIMEX and ROLEX (or PCX-S and PCX-T)
+ * is thorough the potential type field from the PDC_MODEL call.  The 
+ * following flags are used at assist this differeniation.
+ */
+
+#define ROLEX_POTENTIAL_KEY_FLAGS	PDC_MODEL_CPU_KEY_WORD_TO_IO
+#define TIMEX_POTENTIAL_KEY_FLAGS	(PDC_MODEL_CPU_KEY_QUAD_STORE | \
+					 PDC_MODEL_CPU_KEY_RECIP_SQRT)
+
+
+#endif /* ! _MACHINE_FPU_INCLUDED */
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/fpudispatch.c linux-2.4.20-pre2/arch/parisc/math-emu/fpudispatch.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/fpudispatch.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/fpudispatch.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,1425 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/fp/fpudispatch.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	<<please update with a synopsis of the functionality provided by this file>>
+ *
+ *  External Interfaces:
+ *	<<the following list was autogenerated, please review>>
+ *	emfpudispatch(ir, dummy1, dummy2, fpregs)
+ *	fpudispatch(ir, excp_code, holder, fpregs)
+ *
+ *  Internal Interfaces:
+ *	<<the following list was autogenerated, please review>>
+ *	static u_int decode_06(u_int, u_int *)
+ *	static u_int decode_0c(u_int, u_int, u_int, u_int *)
+ *	static u_int decode_0e(u_int, u_int, u_int, u_int *)
+ *	static u_int decode_26(u_int, u_int *)
+ *	static u_int decode_2e(u_int, u_int *)
+ *	static void update_status_cbit(u_int *, u_int, u_int, u_int)
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+#define FPUDEBUG 0
+
+#include "float.h"
+#include "types.h"
+/* #include <sys/debug.h> */
+/* #include <machine/sys/mdep_private.h> */
+
+#define COPR_INST 0x30000000
+
+/*
+ * definition of extru macro.  If pos and len are constants, the compiler
+ * will generate an extru instruction when optimized
+ */
+#define extru(r,pos,len)	(((r) >> (31-(pos))) & (( 1 << (len)) - 1))
+/* definitions of bit field locations in the instruction */
+#define fpmajorpos 5
+#define fpr1pos	10
+#define fpr2pos 15
+#define fptpos	31
+#define fpsubpos 18
+#define fpclass1subpos 16
+#define fpclasspos 22
+#define fpfmtpos 20
+#define fpdfpos 18
+#define fpnulpos 26
+/*
+ * the following are the extra bits for the 0E major op
+ */
+#define fpxr1pos 24
+#define fpxr2pos 19
+#define fpxtpos 25
+#define fpxpos 23
+#define fp0efmtpos 20
+/*
+ * the following are for the multi-ops
+ */
+#define fprm1pos 10
+#define fprm2pos 15
+#define fptmpos 31
+#define fprapos 25
+#define fptapos 20
+#define fpmultifmt 26
+/*
+ * the following are for the fused FP instructions
+ */
+     /* fprm1pos 10 */
+     /* fprm2pos 15 */
+#define fpraupos 18
+#define fpxrm2pos 19
+     /* fpfmtpos 20 */
+#define fpralpos 23
+#define fpxrm1pos 24
+     /* fpxtpos 25 */
+#define fpfusedsubop 26
+     /* fptpos	31 */
+
+/*
+ * offset to constant zero in the FP emulation registers
+ */
+#define fpzeroreg (32*sizeof(double)/sizeof(u_int))
+
+/*
+ * extract the major opcode from the instruction
+ */
+#define get_major(op) extru(op,fpmajorpos,6)
+/*
+ * extract the two bit class field from the FP instruction. The class is at bit
+ * positions 21-22
+ */
+#define get_class(op) extru(op,fpclasspos,2)
+/*
+ * extract the 3 bit subop field.  For all but class 1 instructions, it is
+ * located at bit positions 16-18
+ */
+#define get_subop(op) extru(op,fpsubpos,3)
+/*
+ * extract the 2 or 3 bit subop field from class 1 instructions.  It is located
+ * at bit positions 15-16 (PA1.1) or 14-16 (PA2.0)
+ */
+#define get_subop1_PA1_1(op) extru(op,fpclass1subpos,2)	/* PA89 (1.1) fmt */
+#define get_subop1_PA2_0(op) extru(op,fpclass1subpos,3)	/* PA 2.0 fmt */
+
+/* definitions of unimplemented exceptions */
+#define MAJOR_0C_EXCP	0x09
+#define MAJOR_0E_EXCP	0x0b
+#define MAJOR_06_EXCP	0x03
+#define MAJOR_26_EXCP	0x23
+#define MAJOR_2E_EXCP	0x2b
+#define PA83_UNIMP_EXCP	0x01
+
+/*
+ * Special Defines for TIMEX specific code
+ */
+
+#define FPU_TYPE_FLAG_POS (EM_FPU_TYPE_OFFSET>>2)
+#define TIMEX_ROLEX_FPU_MASK (TIMEX_EXTEN_FLAG|ROLEX_EXTEN_FLAG)
+
+/*
+ * Static function definitions
+ */
+#define _PROTOTYPES
+#if defined(_PROTOTYPES) || defined(_lint)
+static u_int decode_0c(u_int, u_int, u_int, u_int *);
+static u_int decode_0e(u_int, u_int, u_int, u_int *);
+static u_int decode_06(u_int, u_int *);
+static u_int decode_26(u_int, u_int *);
+static u_int decode_2e(u_int, u_int *);
+static void update_status_cbit(u_int *, u_int, u_int, u_int);
+#else /* !_PROTOTYPES&&!_lint */
+static u_int decode_0c();
+static u_int decode_0e();
+static u_int decode_06();
+static u_int decode_26();
+static u_int decode_2e();
+static void update_status_cbit();
+#endif /* _PROTOTYPES&&!_lint */
+
+#define VASSERT(x)
+
+/*
+ * this routine will decode the excepting floating point instruction and
+ * call the approiate emulation routine.
+ * It is called by decode_fpu with the following parameters:
+ * fpudispatch(current_ir, unimplemented_code, 0, &Fpu_register)
+ * where current_ir is the instruction to be emulated,
+ * unimplemented_code is the exception_code that the hardware generated
+ * and &Fpu_register is the address of emulated FP reg 0.
+ */
+u_int
+fpudispatch(u_int ir, u_int excp_code, u_int holder, u_int fpregs[])
+{
+	u_int class, subop;
+	u_int fpu_type_flags;
+
+	/* All FP emulation code assumes that ints are 4-bytes in length */
+	VASSERT(sizeof(int) == 4);
+
+	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
+
+	class = get_class(ir);
+	if (class == 1) {
+		if  (fpu_type_flags & PA2_0_FPU_FLAG)
+			subop = get_subop1_PA2_0(ir);
+		else
+			subop = get_subop1_PA1_1(ir);
+	}
+	else
+		subop = get_subop(ir);
+
+	if (FPUDEBUG) printk("class %d subop %d\n", class, subop);
+
+	switch (excp_code) {
+		case MAJOR_0C_EXCP:
+		case PA83_UNIMP_EXCP:
+			return(decode_0c(ir,class,subop,fpregs));
+		case MAJOR_0E_EXCP:
+			return(decode_0e(ir,class,subop,fpregs));
+		case MAJOR_06_EXCP:
+			return(decode_06(ir,fpregs));
+		case MAJOR_26_EXCP:
+			return(decode_26(ir,fpregs));
+		case MAJOR_2E_EXCP:
+			return(decode_2e(ir,fpregs));
+		default:
+			/* "crashme Night Gallery painting nr 2. (asm_crash.s).
+			 * This was fixed for multi-user kernels, but
+			 * workstation kernels had a panic here.  This allowed
+			 * any arbitrary user to panic the kernel by executing
+			 * setting the FP exception registers to strange values
+			 * and generating an emulation trap.  The emulation and
+			 * exception code must never be able to panic the
+			 * kernel.
+			 */
+			return(UNIMPLEMENTEDEXCEPTION);
+	}
+}
+
+/*
+ * this routine is called by $emulation_trap to emulate a coprocessor
+ * instruction if one doesn't exist
+ */
+u_int
+emfpudispatch(u_int ir, u_int dummy1, u_int dummy2, u_int fpregs[])
+{
+	u_int class, subop, major;
+	u_int fpu_type_flags;
+
+	/* All FP emulation code assumes that ints are 4-bytes in length */
+	VASSERT(sizeof(int) == 4);
+
+	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
+
+	major = get_major(ir);
+	class = get_class(ir);
+	if (class == 1) {
+		if  (fpu_type_flags & PA2_0_FPU_FLAG)
+			subop = get_subop1_PA2_0(ir);
+		else
+			subop = get_subop1_PA1_1(ir);
+	}
+	else
+		subop = get_subop(ir);
+	switch (major) {
+		case 0x0C:
+			return(decode_0c(ir,class,subop,fpregs));
+		case 0x0E:
+			return(decode_0e(ir,class,subop,fpregs));
+		case 0x06:
+			return(decode_06(ir,fpregs));
+		case 0x26:
+			return(decode_26(ir,fpregs));
+		case 0x2E:
+			return(decode_2e(ir,fpregs));
+		default:
+			return(PA83_UNIMP_EXCP);
+	}
+}
+	
+
+static u_int
+decode_0c(u_int ir, u_int class, u_int subop, u_int fpregs[])
+{
+	u_int r1,r2,t;		/* operand register offsets */ 
+	u_int fmt;		/* also sf for class 1 conversions */
+	u_int  df;		/* for class 1 conversions */
+	u_int *status;
+	u_int retval, local_status;
+	u_int fpu_type_flags;
+
+	if (ir == COPR_INST) {
+		fpregs[0] = EMULATION_VERSION << 11;
+		return(NOEXCEPTION);
+	}
+	status = &fpregs[0];	/* fp status register */
+	local_status = fpregs[0]; /* and local copy */
+	r1 = extru(ir,fpr1pos,5) * sizeof(double)/sizeof(u_int);
+	if (r1 == 0)		/* map fr0 source to constant zero */
+		r1 = fpzeroreg;
+	t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);
+	if (t == 0 && class != 2)	/* don't allow fr0 as a dest */
+		return(MAJOR_0C_EXCP);
+	fmt = extru(ir,fpfmtpos,2);	/* get fmt completer */
+
+	switch (class) {
+	    case 0:
+		switch (subop) {
+			case 0:	/* COPR 0,0 emulated above*/
+			case 1:
+				return(MAJOR_0C_EXCP);
+			case 2:	/* FCPY */
+				switch (fmt) {
+				    case 2: /* illegal */
+					return(MAJOR_0C_EXCP);
+				    case 3: /* quad */
+					t &= ~3;  /* force to even reg #s */
+					r1 &= ~3;
+					fpregs[t+3] = fpregs[r1+3];
+					fpregs[t+2] = fpregs[r1+2];
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1];
+					return(NOEXCEPTION);
+				}
+			case 3: /* FABS */
+				switch (fmt) {
+				    case 2: /* illegal */
+					return(MAJOR_0C_EXCP);
+				    case 3: /* quad */
+					t &= ~3;  /* force to even reg #s */
+					r1 &= ~3;
+					fpregs[t+3] = fpregs[r1+3];
+					fpregs[t+2] = fpregs[r1+2];
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					/* copy and clear sign bit */
+					fpregs[t] = fpregs[r1] & 0x7fffffff;
+					return(NOEXCEPTION);
+				}
+			case 6: /* FNEG */
+				switch (fmt) {
+				    case 2: /* illegal */
+					return(MAJOR_0C_EXCP);
+				    case 3: /* quad */
+					t &= ~3;  /* force to even reg #s */
+					r1 &= ~3;
+					fpregs[t+3] = fpregs[r1+3];
+					fpregs[t+2] = fpregs[r1+2];
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					/* copy and invert sign bit */
+					fpregs[t] = fpregs[r1] ^ 0x80000000;
+					return(NOEXCEPTION);
+				}
+			case 7: /* FNEGABS */
+				switch (fmt) {
+				    case 2: /* illegal */
+					return(MAJOR_0C_EXCP);
+				    case 3: /* quad */
+					t &= ~3;  /* force to even reg #s */
+					r1 &= ~3;
+					fpregs[t+3] = fpregs[r1+3];
+					fpregs[t+2] = fpregs[r1+2];
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					/* copy and set sign bit */
+					fpregs[t] = fpregs[r1] | 0x80000000;
+					return(NOEXCEPTION);
+				}
+			case 4: /* FSQRT */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fsqrt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fsqrt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2:
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 5: /* FRND */
+				switch (fmt) {
+				    case 0:
+					return(sgl_frnd(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_frnd(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2:
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+		} /* end of switch (subop) */
+
+	case 1: /* class 1 */
+		df = extru(ir,fpdfpos,2); /* get dest format */
+		if ((df & 2) || (fmt & 2)) {
+			/*
+			 * fmt's 2 and 3 are illegal of not implemented
+			 * quad conversions
+			 */
+			return(MAJOR_0C_EXCP);
+		}
+		/*
+		 * encode source and dest formats into 2 bits.
+		 * high bit is source, low bit is dest.
+		 * bit = 1 --> double precision
+		 */
+		fmt = (fmt << 1) | df;
+		switch (subop) {
+			case 0: /* FCNVFF */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(MAJOR_0C_EXCP);
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvff(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvff(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(MAJOR_0C_EXCP);
+				}
+			case 1: /* FCNVXF */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 2: /* FCNVFX */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 3: /* FCNVFXT */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 5: /* FCNVUF (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 6: /* FCNVFU (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 7: /* FCNVFUT (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 4: /* undefined */
+				return(MAJOR_0C_EXCP);
+		} /* end of switch subop */
+
+	case 2: /* class 2 */
+		fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];
+		r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(u_int);
+		if (r2 == 0)
+			r2 = fpzeroreg;
+		if  (fpu_type_flags & PA2_0_FPU_FLAG) {
+			/* FTEST if nullify bit set, otherwise FCMP */
+			if (extru(ir, fpnulpos, 1)) {  /* FTEST */
+				switch (fmt) {
+				    case 0:
+					/*
+					 * arg0 is not used
+					 * second param is the t field used for
+					 * ftest,acc and ftest,rej
+					 * third param is the subop (y-field)
+					 */
+					BUG();
+					/* Unsupported
+					 * return(ftest(0L,extru(ir,fptpos,5),
+					 *	 &fpregs[0],subop));
+					 */
+				    case 1:
+				    case 2:
+				    case 3:
+					return(MAJOR_0C_EXCP);
+				}
+			} else {  /* FCMP */
+				switch (fmt) {
+				    case 0:
+					retval = sgl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 1:
+					retval = dbl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			}
+		}  /* end of if for PA2.0 */
+		else {	/* PA1.0 & PA1.1 */
+		    switch (subop) {
+			case 2:
+			case 3:
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				return(MAJOR_0C_EXCP);
+			case 0: /* FCMP */
+				switch (fmt) {
+				    case 0:
+					retval = sgl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 1:
+					retval = dbl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 1: /* FTEST */
+				switch (fmt) {
+				    case 0:
+					/*
+					 * arg0 is not used
+					 * second param is the t field used for
+					 * ftest,acc and ftest,rej
+					 * third param is the subop (y-field)
+					 */
+					BUG();
+					/* unsupported
+					 * return(ftest(0L,extru(ir,fptpos,5),
+					 *     &fpregs[0],subop));
+					 */
+				    case 1:
+				    case 2:
+				    case 3:
+					return(MAJOR_0C_EXCP);
+				}
+		    } /* end of switch subop */
+		} /* end of else for PA1.0 & PA1.1 */
+	case 3: /* class 3 */
+		r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(u_int);
+		if (r2 == 0)
+			r2 = fpzeroreg;
+		switch (subop) {
+			case 5:
+			case 6:
+			case 7:
+				return(MAJOR_0C_EXCP);
+			
+			case 0: /* FADD */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 1: /* FSUB */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 2: /* FMPY */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fmpy(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fmpy(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 3: /* FDIV */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+			case 4: /* FREM */
+				switch (fmt) {
+				    case 0:
+					return(sgl_frem(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_frem(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 2: /* illegal */
+				    case 3: /* quad not implemented */
+					return(MAJOR_0C_EXCP);
+				}
+		} /* end of class 3 switch */
+	} /* end of switch(class) */
+
+	/* If we get here, something is really wrong! */
+	return(MAJOR_0C_EXCP);
+}
+
+static u_int
+decode_0e(ir,class,subop,fpregs)
+u_int ir,class,subop;
+u_int fpregs[];
+{
+	u_int r1,r2,t;		/* operand register offsets */
+	u_int fmt;		/* also sf for class 1 conversions */
+	u_int df;		/* dest format for class 1 conversions */
+	u_int *status;
+	u_int retval, local_status;
+	u_int fpu_type_flags;
+
+	status = &fpregs[0];
+	local_status = fpregs[0];
+	r1 = ((extru(ir,fpr1pos,5)<<1)|(extru(ir,fpxr1pos,1)));
+	if (r1 == 0)
+		r1 = fpzeroreg;
+	t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));
+	if (t == 0 && class != 2)
+		return(MAJOR_0E_EXCP);
+	if (class < 2)		/* class 0 or 1 has 2 bit fmt */
+		fmt = extru(ir,fpfmtpos,2);
+	else 			/* class 2 and 3 have 1 bit fmt */
+		fmt = extru(ir,fp0efmtpos,1);
+	/*
+	 * An undefined combination, double precision accessing the
+	 * right half of a FPR, can get us into trouble.  
+	 * Let's just force proper alignment on it.
+	 */
+	if (fmt == DBL) {
+		r1 &= ~1;
+		if (class != 1)
+			t &= ~1;
+	}
+
+	switch (class) {
+	    case 0:
+		switch (subop) {
+			case 0: /* unimplemented */
+			case 1:
+				return(MAJOR_0E_EXCP);
+			case 2: /* FCPY */
+				switch (fmt) {
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1];
+					return(NOEXCEPTION);
+				}
+			case 3: /* FABS */
+				switch (fmt) {
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1] & 0x7fffffff;
+					return(NOEXCEPTION);
+				}
+			case 6: /* FNEG */
+				switch (fmt) {
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1] ^ 0x80000000;
+					return(NOEXCEPTION);
+				}
+			case 7: /* FNEGABS */
+				switch (fmt) {
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				    case 1: /* double */
+					fpregs[t+1] = fpregs[r1+1];
+				    case 0: /* single */
+					fpregs[t] = fpregs[r1] | 0x80000000;
+					return(NOEXCEPTION);
+				}
+			case 4: /* FSQRT */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fsqrt(&fpregs[r1],0,
+						&fpregs[t], status));
+				    case 1:
+					return(dbl_fsqrt(&fpregs[r1],0,
+						&fpregs[t], status));
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				}
+			case 5: /* FRMD */
+				switch (fmt) {
+				    case 0:
+					return(sgl_frnd(&fpregs[r1],0,
+						&fpregs[t], status));
+				    case 1:
+					return(dbl_frnd(&fpregs[r1],0,
+						&fpregs[t], status));
+				    case 2:
+				    case 3:
+					return(MAJOR_0E_EXCP);
+				}
+		} /* end of switch (subop */
+	
+	case 1: /* class 1 */
+		df = extru(ir,fpdfpos,2); /* get dest format */
+		/*
+		 * Fix Crashme problem (writing to 31R in double precision)
+		 * here too.
+		 */
+		if (df == DBL) {
+			t &= ~1;
+		}
+		if ((df & 2) || (fmt & 2))
+			return(MAJOR_0E_EXCP);
+		
+		fmt = (fmt << 1) | df;
+		switch (subop) {
+			case 0: /* FCNVFF */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(MAJOR_0E_EXCP);
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvff(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvff(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(MAJOR_0E_EXCP);
+				}
+			case 1: /* FCNVXF */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 2: /* FCNVFX */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 3: /* FCNVFXT */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 5: /* FCNVUF (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 6: /* FCNVFU (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 7: /* FCNVFUT (PA2.0 only) */
+				switch(fmt) {
+				    case 0: /* sgl/sgl */
+					return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 1: /* sgl/dbl */
+					return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 2: /* dbl/sgl */
+					return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				    case 3: /* dbl/dbl */
+					return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
+						&fpregs[t],status));
+				}
+			case 4: /* undefined */
+				return(MAJOR_0C_EXCP);
+		} /* end of switch subop */
+	case 2: /* class 2 */
+		/*
+		 * Be careful out there.
+		 * Crashme can generate cases where FR31R is specified
+		 * as the source or target of a double precision operation.
+		 * Since we just pass the address of the floating-point
+		 * register to the emulation routines, this can cause
+		 * corruption of fpzeroreg.
+		 */
+		if (fmt == DBL)
+			r2 = (extru(ir,fpr2pos,5)<<1);
+		else
+			r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
+		fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];
+		if (r2 == 0)
+			r2 = fpzeroreg;
+		if  (fpu_type_flags & PA2_0_FPU_FLAG) {
+			/* FTEST if nullify bit set, otherwise FCMP */
+			if (extru(ir, fpnulpos, 1)) {  /* FTEST */
+				/* not legal */
+				return(MAJOR_0E_EXCP);
+			} else {  /* FCMP */
+			switch (fmt) {
+				    /*
+				     * fmt is only 1 bit long
+				     */
+				    case 0:
+					retval = sgl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 1:
+					retval = dbl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				}
+			}
+		}  /* end of if for PA2.0 */
+		else {  /* PA1.0 & PA1.1 */
+		    switch (subop) {
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+			case 5:
+			case 6:
+			case 7:
+				return(MAJOR_0E_EXCP);
+			case 0: /* FCMP */
+				switch (fmt) {
+				    /*
+				     * fmt is only 1 bit long
+				     */
+				    case 0:
+					retval = sgl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				    case 1:
+					retval = dbl_fcmp(&fpregs[r1],
+						&fpregs[r2],extru(ir,fptpos,5),
+						&local_status);
+					update_status_cbit(status,local_status,
+						fpu_type_flags, subop);
+					return(retval);
+				}
+		    } /* end of switch subop */
+		} /* end of else for PA1.0 & PA1.1 */
+	case 3: /* class 3 */
+		/*
+		 * Be careful out there.
+		 * Crashme can generate cases where FR31R is specified
+		 * as the source or target of a double precision operation.
+		 * Since we just pass the address of the floating-point
+		 * register to the emulation routines, this can cause
+		 * corruption of fpzeroreg.
+		 */
+		if (fmt == DBL)
+			r2 = (extru(ir,fpr2pos,5)<<1);
+		else
+			r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
+		if (r2 == 0)
+			r2 = fpzeroreg;
+		switch (subop) {
+			case 5:
+			case 6:
+			case 7:
+				return(MAJOR_0E_EXCP);
+			
+			/*
+			 * Note that fmt is only 1 bit for class 3 */
+			case 0: /* FADD */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				}
+			case 1: /* FSUB */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				}
+			case 2: /* FMPY or XMPYU */
+				/*
+				 * check for integer multiply (x bit set)
+				 */
+				if (extru(ir,fpxpos,1)) {
+				    /*
+				     * emulate XMPYU
+				     */
+				    switch (fmt) {
+					case 0:
+					    /*
+					     * bad instruction if t specifies
+					     * the right half of a register
+					     */
+					    if (t & 1)
+						return(MAJOR_0E_EXCP);
+					    BUG();
+					    /* unsupported
+					     * impyu(&fpregs[r1],&fpregs[r2],
+						 * &fpregs[t]);
+					     */
+					    return(NOEXCEPTION);
+					case 1:
+						return(MAJOR_0E_EXCP);
+				    }
+				}
+				else { /* FMPY */
+				    switch (fmt) {
+				        case 0:
+					    return(sgl_fmpy(&fpregs[r1],
+					       &fpregs[r2],&fpregs[t],status));
+				        case 1:
+					    return(dbl_fmpy(&fpregs[r1],
+					       &fpregs[r2],&fpregs[t],status));
+				    }
+				}
+			case 3: /* FDIV */
+				switch (fmt) {
+				    case 0:
+					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				}
+			case 4: /* FREM */
+				switch (fmt) {
+				    case 0:
+					return(sgl_frem(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				    case 1:
+					return(dbl_frem(&fpregs[r1],&fpregs[r2],
+						&fpregs[t],status));
+				}
+		} /* end of class 3 switch */
+	} /* end of switch(class) */
+
+	/* If we get here, something is really wrong! */
+	return(MAJOR_0E_EXCP);
+}
+
+
+/*
+ * routine to decode the 06 (FMPYADD and FMPYCFXT) instruction
+ */
+static u_int
+decode_06(ir,fpregs)
+u_int ir;
+u_int fpregs[];
+{
+	u_int rm1, rm2, tm, ra, ta; /* operands */
+	u_int fmt;
+	u_int error = 0;
+	u_int status;
+	u_int fpu_type_flags;
+	union {
+		double dbl;
+		float flt;
+		struct { u_int i1; u_int i2; } ints;
+	} mtmp, atmp;
+
+
+	status = fpregs[0];		/* use a local copy of status reg */
+	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
+	fmt = extru(ir, fpmultifmt, 1);	/* get sgl/dbl flag */
+	if (fmt == 0) { /* DBL */
+		rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);
+		if (rm1 == 0)
+			rm1 = fpzeroreg;
+		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);
+		if (rm2 == 0)
+			rm2 = fpzeroreg;
+		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);
+		if (tm == 0)
+			return(MAJOR_06_EXCP);
+		ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);
+		ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);
+		if (ta == 0)
+			return(MAJOR_06_EXCP);
+
+		if  (fpu_type_flags & TIMEX_ROLEX_FPU_MASK)  {
+
+			if (ra == 0) {
+			 	/* special case FMPYCFXT, see sgl case below */
+				if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],
+					&mtmp.ints.i1,&status))
+					error = 1;
+				if (dbl_to_sgl_fcnvfxt(&fpregs[ta],
+					&atmp.ints.i1,&atmp.ints.i1,&status))
+					error = 1;
+				}
+			else {
+
+			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+					&status))
+				error = 1;
+			if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
+					&status))
+				error = 1;
+				}
+			}
+
+		else
+
+			{
+			if (ra == 0)
+				ra = fpzeroreg;
+
+			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+					&status))
+				error = 1;
+			if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
+					&status))
+				error = 1;
+
+			}
+
+		if (error)
+			return(MAJOR_06_EXCP);
+		else {
+			/* copy results */
+			fpregs[tm] = mtmp.ints.i1;
+			fpregs[tm+1] = mtmp.ints.i2;
+			fpregs[ta] = atmp.ints.i1;
+			fpregs[ta+1] = atmp.ints.i2;
+			fpregs[0] = status;
+			return(NOEXCEPTION);
+		}
+	}
+	else { /* SGL */
+		/*
+		 * calculate offsets for single precision numbers
+		 * See table 6-14 in PA-89 architecture for mapping
+		 */
+		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
+		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
+
+		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
+		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
+
+		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
+		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
+
+		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
+		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
+
+		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
+		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
+		
+		if (ra == 0x20 &&(fpu_type_flags & TIMEX_ROLEX_FPU_MASK)) {
+			/* special case FMPYCFXT (really 0)
+			  * This instruction is only present on the Timex and
+			  * Rolex fpu's in so if it is the special case and
+			  * one of these fpu's we run the FMPYCFXT instruction
+			  */
+			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+					&status))
+				error = 1;
+			if (sgl_to_sgl_fcnvfxt(&fpregs[ta],&atmp.ints.i1,
+				&atmp.ints.i1,&status))
+				error = 1;
+		}
+		else {
+			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+					&status))
+				error = 1;
+			if (sgl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
+					&status))
+				error = 1;
+		}
+		if (error)
+			return(MAJOR_06_EXCP);
+		else {
+			/* copy results */
+			fpregs[tm] = mtmp.ints.i1;
+			fpregs[ta] = atmp.ints.i1;
+			fpregs[0] = status;
+			return(NOEXCEPTION);
+		}
+	}
+}
+
+/*
+ * routine to decode the 26 (FMPYSUB) instruction
+ */
+static u_int
+decode_26(ir,fpregs)
+u_int ir;
+u_int fpregs[];
+{
+	u_int rm1, rm2, tm, ra, ta; /* operands */
+	u_int fmt;
+	u_int error = 0;
+	u_int status;
+	union {
+		double dbl;
+		float flt;
+		struct { u_int i1; u_int i2; } ints;
+	} mtmp, atmp;
+
+
+	status = fpregs[0];
+	fmt = extru(ir, fpmultifmt, 1);	/* get sgl/dbl flag */
+	if (fmt == 0) { /* DBL */
+		rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);
+		if (rm1 == 0)
+			rm1 = fpzeroreg;
+		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);
+		if (rm2 == 0)
+			rm2 = fpzeroreg;
+		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);
+		if (tm == 0)
+			return(MAJOR_26_EXCP);
+		ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);
+		if (ra == 0)
+			return(MAJOR_26_EXCP);
+		ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);
+		if (ta == 0)
+			return(MAJOR_26_EXCP);
+		
+		if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))
+			error = 1;
+		if (dbl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))
+			error = 1;
+		if (error)
+			return(MAJOR_26_EXCP);
+		else {
+			/* copy results */
+			fpregs[tm] = mtmp.ints.i1;
+			fpregs[tm+1] = mtmp.ints.i2;
+			fpregs[ta] = atmp.ints.i1;
+			fpregs[ta+1] = atmp.ints.i2;
+			fpregs[0] = status;
+			return(NOEXCEPTION);
+		}
+	}
+	else { /* SGL */
+		/*
+		 * calculate offsets for single precision numbers
+		 * See table 6-14 in PA-89 architecture for mapping
+		 */
+		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
+		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
+
+		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
+		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
+
+		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
+		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
+
+		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
+		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
+
+		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
+		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
+		
+		if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))
+			error = 1;
+		if (sgl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))
+			error = 1;
+		if (error)
+			return(MAJOR_26_EXCP);
+		else {
+			/* copy results */
+			fpregs[tm] = mtmp.ints.i1;
+			fpregs[ta] = atmp.ints.i1;
+			fpregs[0] = status;
+			return(NOEXCEPTION);
+		}
+	}
+
+}
+
+/*
+ * routine to decode the 2E (FMPYFADD,FMPYNFADD) instructions
+ */
+static u_int
+decode_2e(ir,fpregs)
+u_int ir;
+u_int fpregs[];
+{
+	u_int rm1, rm2, ra, t; /* operands */
+	u_int fmt;
+
+	fmt = extru(ir,fpfmtpos,1);	/* get fmt completer */
+	if (fmt == DBL) { /* DBL */
+		rm1 = extru(ir,fprm1pos,5) * sizeof(double)/sizeof(u_int);
+		if (rm1 == 0)
+			rm1 = fpzeroreg;
+		rm2 = extru(ir,fprm2pos,5) * sizeof(double)/sizeof(u_int);
+		if (rm2 == 0)
+			rm2 = fpzeroreg;
+		ra = ((extru(ir,fpraupos,3)<<2)|(extru(ir,fpralpos,3)>>1)) *
+		     sizeof(double)/sizeof(u_int);
+		if (ra == 0)
+			ra = fpzeroreg;
+		t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);
+		if (t == 0)
+			return(MAJOR_2E_EXCP);
+
+		if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */
+			return(dbl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],
+					&fpregs[ra], &fpregs[0], &fpregs[t]));
+		} else {
+			return(dbl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],
+					&fpregs[ra], &fpregs[0], &fpregs[t]));
+		}
+	} /* end DBL */
+	else { /* SGL */
+		rm1 = (extru(ir,fprm1pos,5)<<1)|(extru(ir,fpxrm1pos,1));
+		if (rm1 == 0)
+			rm1 = fpzeroreg;
+		rm2 = (extru(ir,fprm2pos,5)<<1)|(extru(ir,fpxrm2pos,1));
+		if (rm2 == 0)
+			rm2 = fpzeroreg;
+		ra = (extru(ir,fpraupos,3)<<3)|extru(ir,fpralpos,3);
+		if (ra == 0)
+			ra = fpzeroreg;
+		t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));
+		if (t == 0)
+			return(MAJOR_2E_EXCP);
+
+		if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */
+			return(sgl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],
+					&fpregs[ra], &fpregs[0], &fpregs[t]));
+		} else {
+			return(sgl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],
+					&fpregs[ra], &fpregs[0], &fpregs[t]));
+		}
+	} /* end SGL */
+}
+
+/*
+ * update_status_cbit
+ *
+ *	This routine returns the correct FP status register value in
+ *	*status, based on the C-bit & V-bit returned by the FCMP
+ *	emulation routine in new_status.  The architecture type
+ *	(PA83, PA89 or PA2.0) is available in fpu_type.  The y_field
+ *	and the architecture type are used to determine what flavor
+ *	of FCMP is being emulated.
+ */
+static void
+update_status_cbit(status, new_status, fpu_type, y_field)
+u_int *status, new_status;
+u_int fpu_type;
+u_int y_field;
+{
+	/*
+	 * For PA89 FPU's which implement the Compare Queue and
+	 * for PA2.0 FPU's, update the Compare Queue if the y-field = 0,
+	 * otherwise update the specified bit in the Compare Array.
+	 * Note that the y-field will always be 0 for non-PA2.0 FPU's.
+	 */
+	if ((fpu_type & TIMEX_EXTEN_FLAG) || 
+	    (fpu_type & ROLEX_EXTEN_FLAG) ||
+	    (fpu_type & PA2_0_FPU_FLAG)) {
+		if (y_field == 0) {
+			*status = ((*status & 0x04000000) >> 5) | /* old Cbit */
+				  ((*status & 0x003ff000) >> 1) | /* old CQ   */
+				  (new_status & 0xffc007ff); /* all other bits*/
+		} else {
+			*status = (*status & 0x04000000) |     /* old Cbit */
+				  ((new_status & 0x04000000) >> (y_field+4)) |
+				  (new_status & ~0x04000000 &  /* other bits */
+				   ~(0x04000000 >> (y_field+4)));
+		}
+	}
+	/* if PA83, just update the C-bit */
+	else {
+		*status = new_status;
+	}
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/frnd.c linux-2.4.20-pre2/arch/parisc/math-emu/frnd.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/frnd.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/frnd.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,252 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  Purpose:
+ *	Single Floating-point Round to Integer
+ *	Double Floating-point Round to Integer
+ *	Quad Floating-point Round to Integer (returns unimplemented)
+ *
+ *  External Interfaces:
+ *	dbl_frnd(srcptr,nullptr,dstptr,status)
+ *	sgl_frnd(srcptr,nullptr,dstptr,status)
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ *  Single Floating-point Round to Integer
+ */
+
+/*ARGSUSED*/
+int
+sgl_frnd(sgl_floating_point *srcptr,
+	unsigned int *nullptr,
+	sgl_floating_point *dstptr,
+	unsigned int *status)
+{
+	register unsigned int src, result;
+	register int src_exponent;
+	register boolean inexact = FALSE;
+
+	src = *srcptr;
+        /*
+         * check source operand for NaN or infinity
+         */
+        if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
+                /*
+                 * is signaling NaN?
+                 */
+                if (Sgl_isone_signaling(src)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(src);
+                }
+                /*
+                 * return quiet NaN or infinity
+                 */
+                *dstptr = src;
+                return(NOEXCEPTION);
+        }
+	/* 
+	 * Need to round?
+	 */
+	if ((src_exponent -= SGL_BIAS) >= SGL_P - 1) {
+		*dstptr = src;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		Sgl_clear_exponent_set_hidden(src);
+		result = src;
+		Sgl_rightshift(result,(SGL_P-1) - (src_exponent));
+		/* check for inexact */
+		if (Sgl_isinexact_to_fix(src,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Sgl_iszero_sign(src)) Sgl_increment(result);
+			     break;
+			case ROUNDMINUS:
+			     if (Sgl_isone_sign(src)) Sgl_increment(result);
+			     break;
+			case ROUNDNEAREST:
+			     if (Sgl_isone_roundbit(src,src_exponent))
+			        if (Sgl_isone_stickybit(src,src_exponent) 
+				|| (Sgl_isone_lowmantissa(result))) 
+					Sgl_increment(result);
+			} 
+		}
+		Sgl_leftshift(result,(SGL_P-1) - (src_exponent));
+		if (Sgl_isone_hiddenoverflow(result)) 
+			Sgl_set_exponent(result,src_exponent + (SGL_BIAS+1));
+		else Sgl_set_exponent(result,src_exponent + SGL_BIAS);
+	}
+	else {
+		result = src;  		/* set sign */
+		Sgl_setzero_exponentmantissa(result);
+		/* check for inexact */
+		if (Sgl_isnotzero_exponentmantissa(src)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Sgl_iszero_sign(src)) 
+				Sgl_set_exponent(result,SGL_BIAS);
+			     break;
+			case ROUNDMINUS:
+			     if (Sgl_isone_sign(src)) 
+				Sgl_set_exponent(result,SGL_BIAS);
+			     break;
+			case ROUNDNEAREST:
+			     if (src_exponent == -1)
+			        if (Sgl_isnotzero_mantissa(src))
+				   Sgl_set_exponent(result,SGL_BIAS);
+			} 
+		}
+	}
+	*dstptr = result;
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+} 
+
+/*
+ *  Double Floating-point Round to Integer
+ */
+
+/*ARGSUSED*/
+int
+dbl_frnd(
+	dbl_floating_point *srcptr,
+	unsigned int *nullptr,
+	dbl_floating_point *dstptr,
+	unsigned int *status)
+{
+	register unsigned int srcp1, srcp2, resultp1, resultp2;
+	register int src_exponent;
+	register boolean inexact = FALSE;
+
+	Dbl_copyfromptr(srcptr,srcp1,srcp2);
+        /*
+         * check source operand for NaN or infinity
+         */
+        if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
+                /*
+                 * is signaling NaN?
+                 */
+                if (Dbl_isone_signaling(srcp1)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Dbl_set_quiet(srcp1);
+                }
+                /*
+                 * return quiet NaN or infinity
+                 */
+                Dbl_copytoptr(srcp1,srcp2,dstptr);
+                return(NOEXCEPTION);
+        }
+	/* 
+	 * Need to round?
+	 */
+	if ((src_exponent -= DBL_BIAS) >= DBL_P - 1) {
+		Dbl_copytoptr(srcp1,srcp2,dstptr);
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate result
+	 */
+	if (src_exponent >= 0) {
+		Dbl_clear_exponent_set_hidden(srcp1);
+		resultp1 = srcp1;
+		resultp2 = srcp2;
+		Dbl_rightshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
+		/* check for inexact */
+		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Dbl_iszero_sign(srcp1)) 
+				Dbl_increment(resultp1,resultp2);
+			     break;
+			case ROUNDMINUS:
+			     if (Dbl_isone_sign(srcp1)) 
+				Dbl_increment(resultp1,resultp2);
+			     break;
+			case ROUNDNEAREST:
+			     if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+			      if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) 
+				  || (Dbl_isone_lowmantissap2(resultp2))) 
+					Dbl_increment(resultp1,resultp2);
+			} 
+		}
+		Dbl_leftshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
+		if (Dbl_isone_hiddenoverflow(resultp1))
+			Dbl_set_exponent(resultp1,src_exponent + (DBL_BIAS+1));
+		else Dbl_set_exponent(resultp1,src_exponent + DBL_BIAS);
+	}
+	else {
+		resultp1 = srcp1;  /* set sign */
+		Dbl_setzero_exponentmantissa(resultp1,resultp2);
+		/* check for inexact */
+		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+			inexact = TRUE;
+			/*  round result  */
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+			     if (Dbl_iszero_sign(srcp1)) 
+				Dbl_set_exponent(resultp1,DBL_BIAS);
+			     break;
+			case ROUNDMINUS:
+			     if (Dbl_isone_sign(srcp1)) 
+				Dbl_set_exponent(resultp1,DBL_BIAS);
+			     break;
+			case ROUNDNEAREST:
+			     if (src_exponent == -1)
+			        if (Dbl_isnotzero_mantissa(srcp1,srcp2))
+				   Dbl_set_exponent(resultp1,DBL_BIAS);
+			} 
+		}
+	}
+	Dbl_copytoptr(resultp1,resultp2,dstptr);
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/hppa.h linux-2.4.20-pre2/arch/parisc/math-emu/hppa.h
--- linux-2.4.20-pre1/arch/parisc/math-emu/hppa.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/hppa.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,42 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+
+/* amount is assumed to be a constant between 0 and 32 (non-inclusive) */
+#define Shiftdouble(left,right,amount,dest)			\
+    /* int left, right, amount, dest; */			\
+    dest = ((left) << (32-(amount))) | ((unsigned int)(right) >> (amount))
+
+/* amount must be less than 32 */
+#define Variableshiftdouble(left,right,amount,dest)		\
+    /* unsigned int left, right;  int amount, dest; */		\
+    if (amount == 0) dest = right;				\
+    else dest = ((((unsigned) left)&0x7fffffff) << (32-(amount))) |	\
+          ((unsigned) right >> (amount))
+
+/* amount must be between 0 and 32 (non-inclusive) */
+#define Variable_shift_double(left,right,amount,dest)		\
+    /* unsigned int left, right;  int amount, dest; */		\
+    dest = (left << (32-(amount))) | ((unsigned) right >> (amount))
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/math-emu.h linux-2.4.20-pre2/arch/parisc/math-emu/math-emu.h
--- linux-2.4.20-pre1/arch/parisc/math-emu/math-emu.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/math-emu.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,27 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _PARISC_MATH_EMU_H
+#define _PARISC_MATH_EMU_H
+
+#include <asm/ptrace.h>
+extern int handle_fpe(struct pt_regs *regs);
+
+#endif
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/sfadd.c linux-2.4.20-pre2/arch/parisc/math-emu/sfadd.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/sfadd.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/sfadd.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,518 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfadd.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single_add: add two single precision values.
+ *
+ *  External Interfaces:
+ *	sgl_fadd(leftptr, rightptr, dstptr, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single_add: add two single precision values.
+ */
+int
+sgl_fadd(
+    sgl_floating_point *leftptr,
+    sgl_floating_point *rightptr,
+    sgl_floating_point *dstptr,
+    unsigned int *status)
+    {
+    register unsigned int left, right, result, extent;
+    register unsigned int signless_upper_left, signless_upper_right, save;
+    
+    
+    register int result_exponent, right_exponent, diff_exponent;
+    register int sign_save, jumpsize;
+    register boolean inexact = FALSE;
+    register boolean underflowtrap;
+        
+    /* Create local copies of the numbers */
+    left = *leftptr;
+    right = *rightptr;
+
+    /* A zero "save" helps discover equal operands (for later),  *
+     * and is used in swapping operands (if needed).             */
+    Sgl_xortointp1(left,right,/*to*/save);
+
+    /*
+     * check first operand for NaN's or infinity
+     */
+    if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)
+	{
+	if (Sgl_iszero_mantissa(left)) 
+	    {
+	    if (Sgl_isnotnan(right)) 
+		{
+		if (Sgl_isinfinity(right) && save!=0) 
+		    {
+		    /* 
+		     * invalid since operands are opposite signed infinity's
+		     */
+		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                    Set_invalidflag();
+                    Sgl_makequietnan(result);
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		/*
+	 	 * return infinity
+	 	 */
+		*dstptr = left;
+		return(NOEXCEPTION);
+		}
+	    }
+	else 
+	    {
+            /*
+             * is NaN; signaling or quiet?
+             */
+            if (Sgl_isone_signaling(left)) 
+		{
+               	/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+        	/* make NaN quiet */
+        	Set_invalidflag();
+        	Sgl_set_quiet(left);
+        	}
+	    /* 
+	     * is second operand a signaling NaN? 
+	     */
+	    else if (Sgl_is_signalingnan(right)) 
+		{
+        	/* trap if INVALIDTRAP enabled */
+               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Sgl_set_quiet(right);
+		*dstptr = right;
+		return(NOEXCEPTION);
+		}
+	    /*
+ 	     * return quiet NaN
+ 	     */
+ 	    *dstptr = left;
+ 	    return(NOEXCEPTION);
+	    }
+	} /* End left NaN or Infinity processing */
+    /*
+     * check second operand for NaN's or infinity
+     */
+    if (Sgl_isinfinity_exponent(right)) 
+	{
+	if (Sgl_iszero_mantissa(right)) 
+	    {
+	    /* return infinity */
+	    *dstptr = right;
+	    return(NOEXCEPTION);
+	    }
+        /*
+         * is NaN; signaling or quiet?
+         */
+        if (Sgl_isone_signaling(right)) 
+	    {
+            /* trap if INVALIDTRAP enabled */
+	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+	    /* make NaN quiet */
+	    Set_invalidflag();
+	    Sgl_set_quiet(right);
+	    }
+	/*
+	 * return quiet NaN
+ 	 */
+	*dstptr = right;
+	return(NOEXCEPTION);
+    	} /* End right NaN or Infinity processing */
+
+    /* Invariant: Must be dealing with finite numbers */
+
+    /* Compare operands by removing the sign */
+    Sgl_copytoint_exponentmantissa(left,signless_upper_left);
+    Sgl_copytoint_exponentmantissa(right,signless_upper_right);
+
+    /* sign difference selects add or sub operation. */
+    if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))
+	{
+	/* Set the left operand to the larger one by XOR swap *
+	 *  First finish the first word using "save"          */
+	Sgl_xorfromintp1(save,right,/*to*/right);
+	Sgl_xorfromintp1(save,left,/*to*/left);
+	result_exponent = Sgl_exponent(left);
+	}
+    /* Invariant:  left is not smaller than right. */ 
+
+    if((right_exponent = Sgl_exponent(right)) == 0)
+        {
+	/* Denormalized operands.  First look for zeroes */
+	if(Sgl_iszero_mantissa(right)) 
+	    {
+	    /* right is zero */
+	    if(Sgl_iszero_exponentmantissa(left))
+		{
+		/* Both operands are zeros */
+		if(Is_rounding_mode(ROUNDMINUS))
+		    {
+		    Sgl_or_signs(left,/*with*/right);
+		    }
+		else
+		    {
+		    Sgl_and_signs(left,/*with*/right);
+		    }
+		}
+	    else 
+		{
+		/* Left is not a zero and must be the result.  Trapped
+		 * underflows are signaled if left is denormalized.  Result
+		 * is always exact. */
+		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+		    {
+		    /* need to normalize results mantissa */
+	    	    sign_save = Sgl_signextendedsign(left);
+		    Sgl_leftshiftby1(left);
+		    Sgl_normalize(left,result_exponent);
+		    Sgl_set_sign(left,/*using*/sign_save);
+		    Sgl_setwrapped_exponent(left,result_exponent,unfl);
+		    *dstptr = left;
+		    return(UNDERFLOWEXCEPTION);
+		    }
+		}
+	    *dstptr = left;
+	    return(NOEXCEPTION);
+	    }
+
+	/* Neither are zeroes */
+	Sgl_clear_sign(right);	/* Exponent is already cleared */
+	if(result_exponent == 0 )
+	    {
+	    /* Both operands are denormalized.  The result must be exact
+	     * and is simply calculated.  A sum could become normalized and a
+	     * difference could cancel to a true zero. */
+	    if( (/*signed*/int) save < 0 )
+		{
+		Sgl_subtract(left,/*minus*/right,/*into*/result);
+		if(Sgl_iszero_mantissa(result))
+		    {
+		    if(Is_rounding_mode(ROUNDMINUS))
+			{
+			Sgl_setone_sign(result);
+			}
+		    else
+			{
+			Sgl_setzero_sign(result);
+			}
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		}
+	    else
+		{
+		Sgl_addition(left,right,/*into*/result);
+		if(Sgl_isone_hidden(result))
+		    {
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		}
+	    if(Is_underflowtrap_enabled())
+		{
+		/* need to normalize result */
+	    	sign_save = Sgl_signextendedsign(result);
+		Sgl_leftshiftby1(result);
+		Sgl_normalize(result,result_exponent);
+		Sgl_set_sign(result,/*using*/sign_save);
+                Sgl_setwrapped_exponent(result,result_exponent,unfl);
+		*dstptr = result;
+		return(UNDERFLOWEXCEPTION);
+		}
+	    *dstptr = result;
+	    return(NOEXCEPTION);
+	    }
+	right_exponent = 1;	/* Set exponent to reflect different bias
+				 * with denomalized numbers. */
+	}
+    else
+	{
+	Sgl_clear_signexponent_set_hidden(right);
+	}
+    Sgl_clear_exponent_set_hidden(left);
+    diff_exponent = result_exponent - right_exponent;
+
+    /* 
+     * Special case alignment of operands that would force alignment 
+     * beyond the extent of the extension.  A further optimization
+     * could special case this but only reduces the path length for this
+     * infrequent case.
+     */
+    if(diff_exponent > SGL_THRESHOLD)
+	{
+	diff_exponent = SGL_THRESHOLD;
+	}
+    
+    /* Align right operand by shifting to right */
+    Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,
+     /*and lower to*/extent);
+
+    /* Treat sum and difference of the operands separately. */
+    if( (/*signed*/int) save < 0 )
+	{
+	/*
+	 * Difference of the two operands.  Their can be no overflow.  A
+	 * borrow can occur out of the hidden bit and force a post
+	 * normalization phase.
+	 */
+	Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);
+	if(Sgl_iszero_hidden(result))
+	    {
+	    /* Handle normalization */
+	    /* A straight foward algorithm would now shift the result
+	     * and extension left until the hidden bit becomes one.  Not
+	     * all of the extension bits need participate in the shift.
+	     * Only the two most significant bits (round and guard) are
+	     * needed.  If only a single shift is needed then the guard
+	     * bit becomes a significant low order bit and the extension
+	     * must participate in the rounding.  If more than a single 
+	     * shift is needed, then all bits to the right of the guard 
+	     * bit are zeros, and the guard bit may or may not be zero. */
+	    sign_save = Sgl_signextendedsign(result);
+            Sgl_leftshiftby1_withextent(result,extent,result);
+
+            /* Need to check for a zero result.  The sign and exponent
+	     * fields have already been zeroed.  The more efficient test
+	     * of the full object can be used.
+	     */
+    	    if(Sgl_iszero(result))
+		/* Must have been "x-x" or "x+(-x)". */
+		{
+		if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+		}
+	    result_exponent--;
+	    /* Look to see if normalization is finished. */
+	    if(Sgl_isone_hidden(result))
+		{
+		if(result_exponent==0)
+		    {
+		    /* Denormalized, exponent should be zero.  Left operand *
+ 		     * was normalized, so extent (guard, round) was zero    */
+		    goto underflow;
+		    }
+		else
+		    {
+		    /* No further normalization is needed. */
+		    Sgl_set_sign(result,/*using*/sign_save);
+	    	    Ext_leftshiftby1(extent);
+		    goto round;
+		    }
+		}
+
+	    /* Check for denormalized, exponent should be zero.  Left    * 
+	     * operand was normalized, so extent (guard, round) was zero */
+	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+	       result_exponent==0) goto underflow;
+
+	    /* Shift extension to complete one bit of normalization and
+	     * update exponent. */
+	    Ext_leftshiftby1(extent);
+
+	    /* Discover first one bit to determine shift amount.  Use a
+	     * modified binary search.  We have already shifted the result
+	     * one position right and still not found a one so the remainder
+	     * of the extension must be zero and simplifies rounding. */
+	    /* Scan bytes */
+	    while(Sgl_iszero_hiddenhigh7mantissa(result))
+		{
+		Sgl_leftshiftby8(result);
+		if((result_exponent -= 8) <= 0  && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Now narrow it down to the nibble */
+	    if(Sgl_iszero_hiddenhigh3mantissa(result))
+		{
+		/* The lower nibble contains the normalizing one */
+		Sgl_leftshiftby4(result);
+		if((result_exponent -= 4) <= 0 && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Select case were first bit is set (already normalized)
+	     * otherwise select the proper shift. */
+	    if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)
+		{
+		/* Already normalized */
+		if(result_exponent <= 0) goto underflow;
+		Sgl_set_sign(result,/*using*/sign_save);
+		Sgl_set_exponent(result,/*using*/result_exponent);
+		*dstptr = result;
+		return(NOEXCEPTION);
+		}
+	    Sgl_sethigh4bits(result,/*using*/sign_save);
+	    switch(jumpsize) 
+		{
+		case 1:
+		    {
+		    Sgl_leftshiftby3(result);
+		    result_exponent -= 3;
+		    break;
+		    }
+		case 2:
+		case 3:
+		    {
+		    Sgl_leftshiftby2(result);
+		    result_exponent -= 2;
+		    break;
+		    }
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+		    {
+		    Sgl_leftshiftby1(result);
+		    result_exponent -= 1;
+		    break;
+		    }
+		}
+	    if(result_exponent > 0) 
+		{
+		Sgl_set_exponent(result,/*using*/result_exponent);
+		*dstptr = result;
+		return(NOEXCEPTION); /* Sign bit is already set */
+		}
+	    /* Fixup potential underflows */
+	  underflow:
+	    if(Is_underflowtrap_enabled())
+		{
+		Sgl_set_sign(result,sign_save);
+                Sgl_setwrapped_exponent(result,result_exponent,unfl);
+		*dstptr = result;
+		/* inexact = FALSE; */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    /* 
+	     * Since we cannot get an inexact denormalized result,
+	     * we can now return.
+	     */
+	    Sgl_right_align(result,/*by*/(1-result_exponent),extent);
+	    Sgl_clear_signexponent(result);
+	    Sgl_set_sign(result,sign_save);
+	    *dstptr = result;
+	    return(NOEXCEPTION);
+	    } /* end if(hidden...)... */
+	/* Fall through and round */
+	} /* end if(save < 0)... */
+    else 
+	{
+	/* Add magnitudes */
+	Sgl_addition(left,right,/*to*/result);
+	if(Sgl_isone_hiddenoverflow(result))
+	    {
+	    /* Prenormalization required. */
+	    Sgl_rightshiftby1_withextent(result,extent,extent);
+	    Sgl_arithrightshiftby1(result);
+	    result_exponent++;
+	    } /* end if hiddenoverflow... */
+	} /* end else ...add magnitudes... */
+    
+    /* Round the result.  If the extension is all zeros,then the result is
+     * exact.  Otherwise round in the correct direction.  No underflow is
+     * possible. If a postnormalization is necessary, then the mantissa is
+     * all zeros so no shift is needed. */
+  round:
+    if(Ext_isnotzero(extent))
+	{
+	inexact = TRUE;
+	switch(Rounding_mode())
+	    {
+	    case ROUNDNEAREST: /* The default. */
+	    if(Ext_isone_sign(extent))
+		{
+		/* at least 1/2 ulp */
+		if(Ext_isnotzero_lower(extent)  ||
+		  Sgl_isone_lowmantissa(result))
+		    {
+		    /* either exactly half way and odd or more than 1/2ulp */
+		    Sgl_increment(result);
+		    }
+		}
+	    break;
+
+	    case ROUNDPLUS:
+	    if(Sgl_iszero_sign(result))
+		{
+		/* Round up positive results */
+		Sgl_increment(result);
+		}
+	    break;
+	    
+	    case ROUNDMINUS:
+	    if(Sgl_isone_sign(result))
+		{
+		/* Round down negative results */
+		Sgl_increment(result);
+		}
+	    
+	    case ROUNDZERO:;
+	    /* truncate is simple */
+	    } /* end switch... */
+	if(Sgl_isone_hiddenoverflow(result)) result_exponent++;
+	}
+    if(result_exponent == SGL_INFINITY_EXPONENT)
+        {
+        /* Overflow */
+        if(Is_overflowtrap_enabled())
+	    {
+	    Sgl_setwrapped_exponent(result,result_exponent,ovfl);
+	    *dstptr = result;
+	    if (inexact)
+		if (Is_inexacttrap_enabled())
+		    return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+		else Set_inexactflag();
+	    return(OVERFLOWEXCEPTION);
+	    }
+        else
+	    {
+	    Set_overflowflag();
+	    inexact = TRUE;
+	    Sgl_setoverflow(result);
+	    }
+	}
+    else Sgl_set_exponent(result,result_exponent);
+    *dstptr = result;
+    if(inexact) 
+	if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+	else Set_inexactflag();
+    return(NOEXCEPTION);
+    }
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/sfcmp.c linux-2.4.20-pre2/arch/parisc/math-emu/sfcmp.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/sfcmp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/sfcmp.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,155 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfcmp.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	sgl_cmp: compare two values
+ *
+ *  External Interfaces:
+ *	sgl_fcmp(leftptr, rightptr, cond, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+    
+/*
+ * sgl_cmp: compare two values
+ */
+int
+sgl_fcmp (sgl_floating_point * leftptr, sgl_floating_point * rightptr,
+	  unsigned int cond, unsigned int *status)
+                                           
+                       /* The predicate to be tested */
+                         
+    {
+    register unsigned int left, right;
+    register int xorresult;
+        
+    /* Create local copies of the numbers */
+    left = *leftptr;
+    right = *rightptr;
+
+    /*
+     * Test for NaN
+     */
+    if(    (Sgl_exponent(left) == SGL_INFINITY_EXPONENT)
+        || (Sgl_exponent(right) == SGL_INFINITY_EXPONENT) )
+	{
+	/* Check if a NaN is involved.  Signal an invalid exception when 
+	 * comparing a signaling NaN or when comparing quiet NaNs and the
+	 * low bit of the condition is set */
+        if( (  (Sgl_exponent(left) == SGL_INFINITY_EXPONENT)
+	    && Sgl_isnotzero_mantissa(left) 
+	    && (Exception(cond) || Sgl_isone_signaling(left)))
+	   ||
+	    (  (Sgl_exponent(right) == SGL_INFINITY_EXPONENT)
+	    && Sgl_isnotzero_mantissa(right) 
+	    && (Exception(cond) || Sgl_isone_signaling(right)) ) )
+	    {
+	    if( Is_invalidtrap_enabled() ) {
+	    	Set_status_cbit(Unordered(cond));
+		return(INVALIDEXCEPTION);
+	    }
+	    else Set_invalidflag();
+	    Set_status_cbit(Unordered(cond));
+	    return(NOEXCEPTION);
+	    }
+	/* All the exceptional conditions are handled, now special case
+	   NaN compares */
+        else if( ((Sgl_exponent(left) == SGL_INFINITY_EXPONENT)
+	    && Sgl_isnotzero_mantissa(left))
+	   ||
+	    ((Sgl_exponent(right) == SGL_INFINITY_EXPONENT)
+	    && Sgl_isnotzero_mantissa(right)) )
+	    {
+	    /* NaNs always compare unordered. */
+	    Set_status_cbit(Unordered(cond));
+	    return(NOEXCEPTION);
+	    }
+	/* infinities will drop down to the normal compare mechanisms */
+	}
+    /* First compare for unequal signs => less or greater or
+     * special equal case */
+    Sgl_xortointp1(left,right,xorresult);
+    if( xorresult < 0 )
+        {
+        /* left negative => less, left positive => greater.
+         * equal is possible if both operands are zeros. */
+        if( Sgl_iszero_exponentmantissa(left) 
+	  && Sgl_iszero_exponentmantissa(right) )
+            {
+	    Set_status_cbit(Equal(cond));
+	    }
+	else if( Sgl_isone_sign(left) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+        }
+    /* Signs are the same.  Treat negative numbers separately
+     * from the positives because of the reversed sense.  */
+    else if( Sgl_all(left) == Sgl_all(right) )
+        {
+        Set_status_cbit(Equal(cond));
+        }
+    else if( Sgl_iszero_sign(left) )
+        {
+        /* Positive compare */
+        if( Sgl_all(left) < Sgl_all(right) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+	else
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+	}
+    else
+        {
+        /* Negative compare.  Signed or unsigned compares
+         * both work the same.  That distinction is only
+         * important when the sign bits differ. */
+        if( Sgl_all(left) > Sgl_all(right) )
+	    {
+	    Set_status_cbit(Lessthan(cond));
+	    }
+        else
+	    {
+	    Set_status_cbit(Greaterthan(cond));
+	    }
+        }
+	return(NOEXCEPTION);
+    }
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/sfdiv.c linux-2.4.20-pre2/arch/parisc/math-emu/sfdiv.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/sfdiv.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/sfdiv.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,392 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfdiv.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Precision Floating-point Divide
+ *
+ *  External Interfaces:
+ *	sgl_fdiv(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ *  Single Precision Floating-point Divide
+ */
+
+int
+sgl_fdiv (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
+	  sgl_floating_point * dstptr, unsigned int *status)
+{
+	register unsigned int opnd1, opnd2, opnd3, result;
+	register int dest_exponent, count;
+	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	boolean is_tiny;
+
+	opnd1 = *srcptr1;
+	opnd2 = *srcptr2;
+	/* 
+	 * set sign bit of result 
+	 */
+	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);  
+	else Sgl_setzero(result);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd1)) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2)) {
+				if (Sgl_isinfinity(opnd2)) {
+					/* 
+					 * invalid since both operands 
+					 * are infinity 
+					 */
+					if (Is_invalidtrap_enabled()) 
+                                		return(INVALIDEXCEPTION);
+                                	Set_invalidflag();
+                                	Sgl_makequietnan(result);
+					*dstptr = result;
+					return(NOEXCEPTION);
+				}
+				/*
+			 	 * return infinity
+			 	 */
+				Sgl_setinfinity_exponentmantissa(result);
+				*dstptr = result;
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Sgl_isone_signaling(opnd1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled())
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd2);
+                		*dstptr = opnd2;
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+                	*dstptr = opnd1;
+                	return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd2)) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			/*
+			 * return zero
+			 */
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Sgl_isone_signaling(opnd2)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(opnd2);
+                }
+                /*
+                 * return quiet NaN
+                 */
+                *dstptr = opnd2;
+                return(NOEXCEPTION);
+	}
+	/*
+	 * check for division by zero
+	 */
+	if (Sgl_iszero_exponentmantissa(opnd2)) {
+		if (Sgl_iszero_exponentmantissa(opnd1)) {
+			/* invalid since both operands are zero */
+			if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        Set_invalidflag();
+                        Sgl_makequietnan(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+		if (Is_divisionbyzerotrap_enabled())
+                        return(DIVISIONBYZEROEXCEPTION);
+                Set_divisionbyzeroflag();
+                Sgl_setinfinity_exponentmantissa(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent 
+	 */
+	dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS;
+
+	/*
+	 * Generate mantissa
+	 */
+	if (Sgl_isnotzero_exponent(opnd1)) {
+		/* set hidden bit */
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /* is denormalized; want to normalize */
+                Sgl_clear_signexponent(opnd1);
+                Sgl_leftshiftby1(opnd1);
+		Sgl_normalize(opnd1,dest_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Sgl_isnotzero_exponent(opnd2)) {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+	else {
+                /* is denormalized; want to normalize */
+                Sgl_clear_signexponent(opnd2);
+                Sgl_leftshiftby1(opnd2);
+		while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) {
+			Sgl_leftshiftby8(opnd2);
+			dest_exponent += 8;
+		}
+		if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) {
+			Sgl_leftshiftby4(opnd2);
+			dest_exponent += 4;
+		}
+		while(Sgl_iszero_hidden(opnd2)) {
+			Sgl_leftshiftby1(opnd2);
+			dest_exponent += 1;
+		}
+	}
+
+	/* Divide the source mantissas */
+
+	/*
+	 * A non_restoring divide algorithm is used.
+	 */
+	Sgl_subtract(opnd1,opnd2,opnd1);
+	Sgl_setzero(opnd3);
+	for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) {
+		Sgl_leftshiftby1(opnd1);
+		Sgl_leftshiftby1(opnd3);
+		if (Sgl_iszero_sign(opnd1)) {
+			Sgl_setone_lowmantissa(opnd3);
+			Sgl_subtract(opnd1,opnd2,opnd1);
+		}
+		else Sgl_addition(opnd1,opnd2,opnd1);
+	}
+	if (count <= SGL_P) {
+		Sgl_leftshiftby1(opnd3);
+		Sgl_setone_lowmantissa(opnd3);
+		Sgl_leftshift(opnd3,SGL_P-count);
+		if (Sgl_iszero_hidden(opnd3)) {
+			Sgl_leftshiftby1(opnd3);
+			dest_exponent--;
+		}
+	}
+	else {
+		if (Sgl_iszero_hidden(opnd3)) {
+			/* need to get one more bit of result */
+			Sgl_leftshiftby1(opnd1);
+			Sgl_leftshiftby1(opnd3);
+			if (Sgl_iszero_sign(opnd1)) {
+				Sgl_setone_lowmantissa(opnd3);
+				Sgl_subtract(opnd1,opnd2,opnd1);
+			}
+			else Sgl_addition(opnd1,opnd2,opnd1);
+			dest_exponent--;
+		}
+		if (Sgl_iszero_sign(opnd1)) guardbit = TRUE;
+		stickybit = Sgl_all(opnd1);
+	}
+	inexact = guardbit | stickybit;
+
+	/* 
+	 * round result 
+	 */
+	if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
+		Sgl_clear_signexponent(opnd3);
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) 
+					Sgl_increment_mantissa(opnd3);
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) 
+					Sgl_increment_mantissa(opnd3);
+				break;
+			case ROUNDNEAREST:
+				if (guardbit) {
+			   	if (stickybit || Sgl_isone_lowmantissa(opnd3))
+			      	    Sgl_increment_mantissa(opnd3);
+				}
+		}
+		if (Sgl_isone_hidden(opnd3)) dest_exponent++;
+	}
+	Sgl_set_mantissa(result,opnd3);
+
+        /* 
+         * Test for overflow
+         */
+	if (dest_exponent >= SGL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
+                        *dstptr = result;
+                        if (inexact) 
+                            if (Is_inexacttrap_enabled())
+                                return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return(OVERFLOWEXCEPTION);
+                }
+		Set_overflowflag();
+                /* set result to infinity or largest number */
+		Sgl_setoverflow(result);
+		inexact = TRUE;
+	}
+        /* 
+         * Test for underflow
+         */
+	else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+                        *dstptr = result;
+                        if (inexact) 
+                            if (Is_inexacttrap_enabled())
+                                return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+                            else Set_inexactflag();
+                        return(UNDERFLOWEXCEPTION);
+                }
+
+		/* Determine if should set underflow flag */
+		is_tiny = TRUE;
+		if (dest_exponent == 0 && inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) {
+					Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) {
+					Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Sgl_isone_lowmantissa(opnd3))) {
+				      	Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			}
+		}
+
+                /*
+                 * denormalize result or set to signed zero
+                 */
+		stickybit = inexact;
+		Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
+
+		/* return rounded number */ 
+		if (inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS:
+				if (Sgl_iszero_sign(result)) {
+					Sgl_increment(opnd3);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result))  {
+					Sgl_increment(opnd3);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Sgl_isone_lowmantissa(opnd3))) {
+			      		Sgl_increment(opnd3);
+				}
+				break;
+			}
+                	if (is_tiny) Set_underflowflag();
+                }
+		Sgl_set_exponentmantissa(result,opnd3);
+	}
+	else Sgl_set_exponent(result,dest_exponent);
+	*dstptr = result;
+	/* check for inexact */
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else  Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/sfmpy.c linux-2.4.20-pre2/arch/parisc/math-emu/sfmpy.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/sfmpy.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/sfmpy.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,380 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfmpy.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Precision Floating-point Multiply
+ *
+ *  External Interfaces:
+ *	sgl_fmpy(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ *  Single Precision Floating-point Multiply
+ */
+
+int
+sgl_fmpy(
+    sgl_floating_point *srcptr1,
+    sgl_floating_point *srcptr2,
+    sgl_floating_point *dstptr,
+    unsigned int *status)
+{
+	register unsigned int opnd1, opnd2, opnd3, result;
+	register int dest_exponent, count;
+	register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+	boolean is_tiny;
+
+	opnd1 = *srcptr1;
+	opnd2 = *srcptr2;
+	/* 
+	 * set sign bit of result 
+	 */
+	if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);  
+	else Sgl_setzero(result);
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd1)) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2)) {
+				if (Sgl_iszero_exponentmantissa(opnd2)) {
+					/* 
+					 * invalid since operands are infinity 
+					 * and zero 
+					 */
+					if (Is_invalidtrap_enabled()) 
+                                		return(INVALIDEXCEPTION);
+                                	Set_invalidflag();
+                                	Sgl_makequietnan(result);
+					*dstptr = result;
+					return(NOEXCEPTION);
+				}
+				/*
+			 	 * return infinity
+			 	 */
+				Sgl_setinfinity_exponentmantissa(result);
+				*dstptr = result;
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Sgl_isone_signaling(opnd1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd2);
+                		*dstptr = opnd2;
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+                	*dstptr = opnd1;
+                	return(NOEXCEPTION);
+		}
+	}
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if (Sgl_isinfinity_exponent(opnd2)) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			if (Sgl_iszero_exponentmantissa(opnd1)) {
+				/* invalid since operands are zero & infinity */
+				if (Is_invalidtrap_enabled()) 
+                                	return(INVALIDEXCEPTION);
+                                Set_invalidflag();
+                                Sgl_makequietnan(opnd2);
+				*dstptr = opnd2;
+				return(NOEXCEPTION);
+			}
+			/*
+			 * return infinity
+			 */
+			Sgl_setinfinity_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Sgl_isone_signaling(opnd2)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(opnd2);
+                }
+                /*
+                 * return quiet NaN
+                 */
+                *dstptr = opnd2;
+                return(NOEXCEPTION);
+	}
+	/*
+	 * Generate exponent 
+	 */
+	dest_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
+
+	/*
+	 * Generate mantissa
+	 */
+	if (Sgl_isnotzero_exponent(opnd1)) {
+		/* set hidden bit */
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /* is denormalized, adjust exponent */
+                Sgl_clear_signexponent(opnd1);
+		Sgl_leftshiftby1(opnd1);
+		Sgl_normalize(opnd1,dest_exponent);
+	}
+	/* opnd2 needs to have hidden bit set with msb in hidden bit */
+	if (Sgl_isnotzero_exponent(opnd2)) {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+	else {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd2)) {
+			Sgl_setzero_exponentmantissa(result);
+			*dstptr = result;
+			return(NOEXCEPTION);
+		}
+                /* is denormalized; want to normalize */
+                Sgl_clear_signexponent(opnd2);
+                Sgl_leftshiftby1(opnd2);
+		Sgl_normalize(opnd2,dest_exponent);
+	}
+
+	/* Multiply two source mantissas together */
+
+	Sgl_leftshiftby4(opnd2);     /* make room for guard bits */
+	Sgl_setzero(opnd3);
+	/*
+	 * Four bits at a time are inspected in each loop, and a
+	 * simple shift and add multiply algorithm is used.
+	 */
+	for (count=1;count<SGL_P;count+=4) {
+		stickybit |= Slow4(opnd3);
+		Sgl_rightshiftby4(opnd3);
+		if (Sbit28(opnd1)) Sall(opnd3) += (Sall(opnd2) << 3);
+		if (Sbit29(opnd1)) Sall(opnd3) += (Sall(opnd2) << 2);
+		if (Sbit30(opnd1)) Sall(opnd3) += (Sall(opnd2) << 1);
+		if (Sbit31(opnd1)) Sall(opnd3) += Sall(opnd2);
+		Sgl_rightshiftby4(opnd1);
+	}
+	/* make sure result is left-justified */
+	if (Sgl_iszero_sign(opnd3)) {
+		Sgl_leftshiftby1(opnd3);
+	}
+	else {
+		/* result mantissa >= 2. */
+		dest_exponent++;
+	}
+	/* check for denormalized result */
+	while (Sgl_iszero_sign(opnd3)) {
+		Sgl_leftshiftby1(opnd3);
+		dest_exponent--;
+	}
+	/*
+	 * check for guard, sticky and inexact bits
+	 */
+	stickybit |= Sgl_all(opnd3) << (SGL_BITLENGTH - SGL_EXP_LENGTH + 1);
+	guardbit = Sbit24(opnd3);
+	inexact = guardbit | stickybit;
+
+	/* re-align mantissa */
+	Sgl_rightshiftby8(opnd3);
+
+	/* 
+	 * round result 
+	 */
+	if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
+		Sgl_clear_signexponent(opnd3);
+		switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) 
+					Sgl_increment(opnd3);
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) 
+					Sgl_increment(opnd3);
+				break;
+			case ROUNDNEAREST:
+				if (guardbit) {
+			   	if (stickybit || Sgl_isone_lowmantissa(opnd3))
+			      	Sgl_increment(opnd3);
+				}
+		}
+		if (Sgl_isone_hidden(opnd3)) dest_exponent++;
+	}
+	Sgl_set_mantissa(result,opnd3);
+
+        /* 
+         * Test for overflow
+         */
+	if (dest_exponent >= SGL_INFINITY_EXPONENT) {
+                /* trap if OVERFLOWTRAP enabled */
+                if (Is_overflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+			Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
+			*dstptr = result;
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+			    else Set_inexactflag();
+			return(OVERFLOWEXCEPTION);
+                }
+		inexact = TRUE;
+		Set_overflowflag();
+                /* set result to infinity or largest number */
+		Sgl_setoverflow(result);
+	}
+        /* 
+         * Test for underflow
+         */
+	else if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+			Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+			*dstptr = result;
+			if (inexact) 
+			    if (Is_inexacttrap_enabled())
+				return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+			    else Set_inexactflag();
+			return(UNDERFLOWEXCEPTION);
+                }
+
+		/* Determine if should set underflow flag */
+		is_tiny = TRUE;
+		if (dest_exponent == 0 && inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) {
+					Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) {
+					Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Sgl_isone_lowmantissa(opnd3))) {
+				      	Sgl_increment(opnd3);
+					if (Sgl_isone_hiddenoverflow(opnd3))
+                			    is_tiny = FALSE;
+					Sgl_decrement(opnd3);
+				}
+				break;
+			}
+		}
+
+                /*
+                 * denormalize result or set to signed zero
+                 */
+		stickybit = inexact;
+		Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
+
+		/* return zero or smallest number */
+		if (inexact) {
+			switch (Rounding_mode()) {
+			case ROUNDPLUS: 
+				if (Sgl_iszero_sign(result)) {
+					Sgl_increment(opnd3);
+				}
+				break;
+			case ROUNDMINUS: 
+				if (Sgl_isone_sign(result)) {
+					Sgl_increment(opnd3);
+				}
+				break;
+			case ROUNDNEAREST:
+				if (guardbit && (stickybit || 
+				    Sgl_isone_lowmantissa(opnd3))) {
+			      		Sgl_increment(opnd3);
+				}
+				break;
+			}
+                if (is_tiny) Set_underflowflag();
+		}
+		Sgl_set_exponentmantissa(result,opnd3);
+	}
+	else Sgl_set_exponent(result,dest_exponent);
+	*dstptr = result;
+
+	/* check for inexact */
+	if (inexact) {
+		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+		else Set_inexactflag();
+	}
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/sfrem.c linux-2.4.20-pre2/arch/parisc/math-emu/sfrem.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/sfrem.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/sfrem.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,290 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfrem.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Precision Floating-point Remainder
+ *
+ *  External Interfaces:
+ *	sgl_frem(srcptr1,srcptr2,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ *  Single Precision Floating-point Remainder
+ */
+
+int
+sgl_frem (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
+	  sgl_floating_point * dstptr, unsigned int *status)
+{
+	register unsigned int opnd1, opnd2, result;
+	register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
+	register boolean roundup = FALSE;
+
+	opnd1 = *srcptr1;
+	opnd2 = *srcptr2;
+	/*
+	 * check first operand for NaN's or infinity
+	 */
+	if ((opnd1_exponent = Sgl_exponent(opnd1)) == SGL_INFINITY_EXPONENT) {
+		if (Sgl_iszero_mantissa(opnd1)) {
+			if (Sgl_isnotnan(opnd2)) {
+				/* invalid since first operand is infinity */
+				if (Is_invalidtrap_enabled()) 
+                                	return(INVALIDEXCEPTION);
+                                Set_invalidflag();
+                                Sgl_makequietnan(result);
+				*dstptr = result;
+				return(NOEXCEPTION);
+			}
+		}
+		else {
+                	/*
+                 	 * is NaN; signaling or quiet?
+                 	 */
+                	if (Sgl_isone_signaling(opnd1)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd1);
+                	}
+			/* 
+			 * is second operand a signaling NaN? 
+			 */
+			else if (Sgl_is_signalingnan(opnd2)) {
+                        	/* trap if INVALIDTRAP enabled */
+                        	if (Is_invalidtrap_enabled()) 
+                            		return(INVALIDEXCEPTION);
+                        	/* make NaN quiet */
+                        	Set_invalidflag();
+                        	Sgl_set_quiet(opnd2);
+                		*dstptr = opnd2;
+                		return(NOEXCEPTION);
+			}
+                	/*
+                 	 * return quiet NaN
+                 	 */
+                	*dstptr = opnd1;
+                	return(NOEXCEPTION);
+		}
+	} 
+	/*
+	 * check second operand for NaN's or infinity
+	 */
+	if ((opnd2_exponent = Sgl_exponent(opnd2)) == SGL_INFINITY_EXPONENT) {
+		if (Sgl_iszero_mantissa(opnd2)) {
+			/*
+			 * return first operand
+			 */
+                	*dstptr = opnd1;
+			return(NOEXCEPTION);
+		}
+                /*
+                 * is NaN; signaling or quiet?
+                 */
+                if (Sgl_isone_signaling(opnd2)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(opnd2);
+                }
+                /*
+                 * return quiet NaN
+                 */
+                *dstptr = opnd2;
+                return(NOEXCEPTION);
+	}
+	/*
+	 * check second operand for zero
+	 */
+	if (Sgl_iszero_exponentmantissa(opnd2)) {
+		/* invalid since second operand is zero */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                Set_invalidflag();
+                Sgl_makequietnan(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+
+	/* 
+	 * get sign of result
+	 */
+	result = opnd1;  
+
+	/* 
+	 * check for denormalized operands
+	 */
+	if (opnd1_exponent == 0) {
+		/* check for zero */
+		if (Sgl_iszero_mantissa(opnd1)) {
+			*dstptr = opnd1;
+			return(NOEXCEPTION);
+		}
+		/* normalize, then continue */
+		opnd1_exponent = 1;
+		Sgl_normalize(opnd1,opnd1_exponent);
+	}
+	else {
+		Sgl_clear_signexponent_set_hidden(opnd1);
+	}
+	if (opnd2_exponent == 0) {
+		/* normalize, then continue */
+		opnd2_exponent = 1;
+		Sgl_normalize(opnd2,opnd2_exponent);
+	}
+	else {
+		Sgl_clear_signexponent_set_hidden(opnd2);
+	}
+
+	/* find result exponent and divide step loop count */
+	dest_exponent = opnd2_exponent - 1;
+	stepcount = opnd1_exponent - opnd2_exponent;
+
+	/*
+	 * check for opnd1/opnd2 < 1
+	 */
+	if (stepcount < 0) {
+		/*
+		 * check for opnd1/opnd2 > 1/2
+		 *
+		 * In this case n will round to 1, so 
+		 *    r = opnd1 - opnd2 
+		 */
+		if (stepcount == -1 && Sgl_isgreaterthan(opnd1,opnd2)) {
+			Sgl_all(result) = ~Sgl_all(result);   /* set sign */
+			/* align opnd2 with opnd1 */
+			Sgl_leftshiftby1(opnd2); 
+			Sgl_subtract(opnd2,opnd1,opnd2);
+			/* now normalize */
+                	while (Sgl_iszero_hidden(opnd2)) {
+                        	Sgl_leftshiftby1(opnd2);
+                        	dest_exponent--;
+			}
+			Sgl_set_exponentmantissa(result,opnd2);
+			goto testforunderflow;
+		}
+		/*
+		 * opnd1/opnd2 <= 1/2
+		 *
+		 * In this case n will round to zero, so 
+		 *    r = opnd1
+		 */
+		Sgl_set_exponentmantissa(result,opnd1);
+		dest_exponent = opnd1_exponent;
+		goto testforunderflow;
+	}
+
+	/*
+	 * Generate result
+	 *
+	 * Do iterative subtract until remainder is less than operand 2.
+	 */
+	while (stepcount-- > 0 && Sgl_all(opnd1)) {
+		if (Sgl_isnotlessthan(opnd1,opnd2))
+			Sgl_subtract(opnd1,opnd2,opnd1);
+		Sgl_leftshiftby1(opnd1);
+	}
+	/*
+	 * Do last subtract, then determine which way to round if remainder 
+	 * is exactly 1/2 of opnd2 
+	 */
+	if (Sgl_isnotlessthan(opnd1,opnd2)) {
+		Sgl_subtract(opnd1,opnd2,opnd1);
+		roundup = TRUE;
+	}
+	if (stepcount > 0 || Sgl_iszero(opnd1)) {
+		/* division is exact, remainder is zero */
+		Sgl_setzero_exponentmantissa(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+	}
+
+	/* 
+	 * Check for cases where opnd1/opnd2 < n 
+	 *
+	 * In this case the result's sign will be opposite that of
+	 * opnd1.  The mantissa also needs some correction.
+	 */
+	Sgl_leftshiftby1(opnd1);
+	if (Sgl_isgreaterthan(opnd1,opnd2)) {
+		Sgl_invert_sign(result);
+		Sgl_subtract((opnd2<<1),opnd1,opnd1);
+	}
+	/* check for remainder being exactly 1/2 of opnd2 */
+	else if (Sgl_isequal(opnd1,opnd2) && roundup) { 
+		Sgl_invert_sign(result);
+	}
+
+	/* normalize result's mantissa */
+        while (Sgl_iszero_hidden(opnd1)) {
+                dest_exponent--;
+                Sgl_leftshiftby1(opnd1);
+        }
+	Sgl_set_exponentmantissa(result,opnd1);
+
+        /* 
+         * Test for underflow
+         */
+    testforunderflow:
+	if (dest_exponent <= 0) {
+                /* trap if UNDERFLOWTRAP enabled */
+                if (Is_underflowtrap_enabled()) {
+                        /*
+                         * Adjust bias of result
+                         */
+                        Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+			*dstptr = result;
+			/* frem is always exact */
+			return(UNDERFLOWEXCEPTION);
+                }
+                /*
+                 * denormalize result or set to signed zero
+                 */
+                if (dest_exponent >= (1 - SGL_P)) {
+			Sgl_rightshift_exponentmantissa(result,1-dest_exponent);
+                }
+                else {
+			Sgl_setzero_exponentmantissa(result);
+		}
+	}
+	else Sgl_set_exponent(result,dest_exponent);
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/sfsqrt.c linux-2.4.20-pre2/arch/parisc/math-emu/sfsqrt.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/sfsqrt.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/sfsqrt.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,187 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfsqrt.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single Floating-point Square Root
+ *
+ *  External Interfaces:
+ *	sgl_fsqrt(srcptr,nullptr,dstptr,status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ *  Single Floating-point Square Root
+ */
+
+/*ARGSUSED*/
+unsigned int
+sgl_fsqrt(
+    sgl_floating_point *srcptr,
+    unsigned int *nullptr,
+    sgl_floating_point *dstptr,
+    unsigned int *status)
+{
+	register unsigned int src, result;
+	register int src_exponent;
+	register unsigned int newbit, sum;
+	register boolean guardbit = FALSE, even_exponent;
+
+	src = *srcptr;
+        /*
+         * check source operand for NaN or infinity
+         */
+        if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
+                /*
+                 * is signaling NaN?
+                 */
+                if (Sgl_isone_signaling(src)) {
+                        /* trap if INVALIDTRAP enabled */
+                        if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                        /* make NaN quiet */
+                        Set_invalidflag();
+                        Sgl_set_quiet(src);
+                }
+                /*
+                 * Return quiet NaN or positive infinity.
+		 *  Fall thru to negative test if negative infinity.
+                 */
+		if (Sgl_iszero_sign(src) || Sgl_isnotzero_mantissa(src)) {
+                	*dstptr = src;
+                	return(NOEXCEPTION);
+		}
+        }
+
+        /*
+         * check for zero source operand
+         */
+	if (Sgl_iszero_exponentmantissa(src)) {
+		*dstptr = src;
+		return(NOEXCEPTION);
+	}
+
+        /*
+         * check for negative source operand 
+         */
+	if (Sgl_isone_sign(src)) {
+		/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Sgl_makequietnan(src);
+		*dstptr = src;
+		return(NOEXCEPTION);
+	}
+
+	/*
+	 * Generate result
+	 */
+	if (src_exponent > 0) {
+		even_exponent = Sgl_hidden(src);
+		Sgl_clear_signexponent_set_hidden(src);
+	}
+	else {
+		/* normalize operand */
+		Sgl_clear_signexponent(src);
+		src_exponent++;
+		Sgl_normalize(src,src_exponent);
+		even_exponent = src_exponent & 1;
+	}
+	if (even_exponent) {
+		/* exponent is even */
+		/* Add comment here.  Explain why odd exponent needs correction */
+		Sgl_leftshiftby1(src);
+	}
+	/*
+	 * Add comment here.  Explain following algorithm.
+	 * 
+	 * Trust me, it works.
+	 *
+	 */
+	Sgl_setzero(result);
+	newbit = 1 << SGL_P;
+	while (newbit && Sgl_isnotzero(src)) {
+		Sgl_addition(result,newbit,sum);
+		if(sum <= Sgl_all(src)) {
+			/* update result */
+			Sgl_addition(result,(newbit<<1),result);
+			Sgl_subtract(src,sum,src);
+		}
+		Sgl_rightshiftby1(newbit);
+		Sgl_leftshiftby1(src);
+	}
+	/* correct exponent for pre-shift */
+	if (even_exponent) {
+		Sgl_rightshiftby1(result);
+	}
+
+	/* check for inexact */
+	if (Sgl_isnotzero(src)) {
+		if (!even_exponent && Sgl_islessthan(result,src)) 
+			Sgl_increment(result);
+		guardbit = Sgl_lowmantissa(result);
+		Sgl_rightshiftby1(result);
+
+		/*  now round result  */
+		switch (Rounding_mode()) {
+		case ROUNDPLUS:
+		     Sgl_increment(result);
+		     break;
+		case ROUNDNEAREST:
+		     /* stickybit is always true, so guardbit 
+		      * is enough to determine rounding */
+		     if (guardbit) {
+			Sgl_increment(result);
+		     }
+		     break;
+		}
+		/* increment result exponent by 1 if mantissa overflowed */
+		if (Sgl_isone_hiddenoverflow(result)) src_exponent+=2;
+
+		if (Is_inexacttrap_enabled()) {
+			Sgl_set_exponent(result,
+			 ((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
+			*dstptr = result;
+			return(INEXACTEXCEPTION);
+		}
+		else Set_inexactflag();
+	}
+	else {
+		Sgl_rightshiftby1(result);
+	}
+	Sgl_set_exponent(result,((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
+	*dstptr = result;
+	return(NOEXCEPTION);
+}
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/sfsub.c linux-2.4.20-pre2/arch/parisc/math-emu/sfsub.c
--- linux-2.4.20-pre1/arch/parisc/math-emu/sfsub.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/sfsub.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,521 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * BEGIN_DESC
+ *
+ *  File:
+ *	@(#)	pa/spmath/sfsub.c		$Revision: 1.1 $
+ *
+ *  Purpose:
+ *	Single_subtract: subtract two single precision values.
+ *
+ *  External Interfaces:
+ *	sgl_fsub(leftptr, rightptr, dstptr, status)
+ *
+ *  Internal Interfaces:
+ *
+ *  Theory:
+ *	<<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single_subtract: subtract two single precision values.
+ */
+int
+sgl_fsub(
+	    sgl_floating_point *leftptr,
+	    sgl_floating_point *rightptr,
+	    sgl_floating_point *dstptr,
+	    unsigned int *status)
+    {
+    register unsigned int left, right, result, extent;
+    register unsigned int signless_upper_left, signless_upper_right, save;
+    
+    register int result_exponent, right_exponent, diff_exponent;
+    register int sign_save, jumpsize;
+    register boolean inexact = FALSE, underflowtrap;
+        
+    /* Create local copies of the numbers */
+    left = *leftptr;
+    right = *rightptr;
+
+    /* A zero "save" helps discover equal operands (for later),  *
+     * and is used in swapping operands (if needed).             */
+    Sgl_xortointp1(left,right,/*to*/save);
+
+    /*
+     * check first operand for NaN's or infinity
+     */
+    if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)
+	{
+	if (Sgl_iszero_mantissa(left)) 
+	    {
+	    if (Sgl_isnotnan(right)) 
+		{
+		if (Sgl_isinfinity(right) && save==0) 
+		    {
+		    /* 
+		     * invalid since operands are same signed infinity's
+		     */
+		    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+                    Set_invalidflag();
+                    Sgl_makequietnan(result);
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		/*
+	 	 * return infinity
+	 	 */
+		*dstptr = left;
+		return(NOEXCEPTION);
+		}
+	    }
+	else 
+	    {
+            /*
+             * is NaN; signaling or quiet?
+             */
+            if (Sgl_isone_signaling(left)) 
+		{
+               	/* trap if INVALIDTRAP enabled */
+		if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+        	/* make NaN quiet */
+        	Set_invalidflag();
+        	Sgl_set_quiet(left);
+        	}
+	    /* 
+	     * is second operand a signaling NaN? 
+	     */
+	    else if (Sgl_is_signalingnan(right)) 
+		{
+        	/* trap if INVALIDTRAP enabled */
+               	if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+		/* make NaN quiet */
+		Set_invalidflag();
+		Sgl_set_quiet(right);
+		*dstptr = right;
+		return(NOEXCEPTION);
+		}
+	    /*
+ 	     * return quiet NaN
+ 	     */
+ 	    *dstptr = left;
+ 	    return(NOEXCEPTION);
+	    }
+	} /* End left NaN or Infinity processing */
+    /*
+     * check second operand for NaN's or infinity
+     */
+    if (Sgl_isinfinity_exponent(right)) 
+	{
+	if (Sgl_iszero_mantissa(right)) 
+	    {
+	    /* return infinity */
+	    Sgl_invert_sign(right);
+	    *dstptr = right;
+	    return(NOEXCEPTION);
+	    }
+        /*
+         * is NaN; signaling or quiet?
+         */
+        if (Sgl_isone_signaling(right)) 
+	    {
+            /* trap if INVALIDTRAP enabled */
+	    if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+	    /* make NaN quiet */
+	    Set_invalidflag();
+	    Sgl_set_quiet(right);
+	    }
+	/*
+	 * return quiet NaN
+ 	 */
+	*dstptr = right;
+	return(NOEXCEPTION);
+    	} /* End right NaN or Infinity processing */
+
+    /* Invariant: Must be dealing with finite numbers */
+
+    /* Compare operands by removing the sign */
+    Sgl_copytoint_exponentmantissa(left,signless_upper_left);
+    Sgl_copytoint_exponentmantissa(right,signless_upper_right);
+
+    /* sign difference selects sub or add operation. */
+    if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))
+	{
+	/* Set the left operand to the larger one by XOR swap *
+	 *  First finish the first word using "save"          */
+	Sgl_xorfromintp1(save,right,/*to*/right);
+	Sgl_xorfromintp1(save,left,/*to*/left);
+	result_exponent = Sgl_exponent(left);
+	Sgl_invert_sign(left);
+	}
+    /* Invariant:  left is not smaller than right. */ 
+
+    if((right_exponent = Sgl_exponent(right)) == 0)
+        {
+	/* Denormalized operands.  First look for zeroes */
+	if(Sgl_iszero_mantissa(right)) 
+	    {
+	    /* right is zero */
+	    if(Sgl_iszero_exponentmantissa(left))
+		{
+		/* Both operands are zeros */
+		Sgl_invert_sign(right);
+		if(Is_rounding_mode(ROUNDMINUS))
+		    {
+		    Sgl_or_signs(left,/*with*/right);
+		    }
+		else
+		    {
+		    Sgl_and_signs(left,/*with*/right);
+		    }
+		}
+	    else 
+		{
+		/* Left is not a zero and must be the result.  Trapped
+		 * underflows are signaled if left is denormalized.  Result
+		 * is always exact. */
+		if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+		    {
+		    /* need to normalize results mantissa */
+	    	    sign_save = Sgl_signextendedsign(left);
+		    Sgl_leftshiftby1(left);
+		    Sgl_normalize(left,result_exponent);
+		    Sgl_set_sign(left,/*using*/sign_save);
+                    Sgl_setwrapped_exponent(left,result_exponent,unfl);
+		    *dstptr = left;
+		    /* inexact = FALSE */
+		    return(UNDERFLOWEXCEPTION);
+		    }
+		}
+	    *dstptr = left;
+	    return(NOEXCEPTION);
+	    }
+
+	/* Neither are zeroes */
+	Sgl_clear_sign(right);	/* Exponent is already cleared */
+	if(result_exponent == 0 )
+	    {
+	    /* Both operands are denormalized.  The result must be exact
+	     * and is simply calculated.  A sum could become normalized and a
+	     * difference could cancel to a true zero. */
+	    if( (/*signed*/int) save >= 0 )
+		{
+		Sgl_subtract(left,/*minus*/right,/*into*/result);
+		if(Sgl_iszero_mantissa(result))
+		    {
+		    if(Is_rounding_mode(ROUNDMINUS))
+			{
+			Sgl_setone_sign(result);
+			}
+		    else
+			{
+			Sgl_setzero_sign(result);
+			}
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		}
+	    else
+		{
+		Sgl_addition(left,right,/*into*/result);
+		if(Sgl_isone_hidden(result))
+		    {
+		    *dstptr = result;
+		    return(NOEXCEPTION);
+		    }
+		}
+	    if(Is_underflowtrap_enabled())
+		{
+		/* need to normalize result */
+	    	sign_save = Sgl_signextendedsign(result);
+		Sgl_leftshiftby1(result);
+		Sgl_normalize(result,result_exponent);
+		Sgl_set_sign(result,/*using*/sign_save);
+                Sgl_setwrapped_exponent(result,result_exponent,unfl);
+		*dstptr = result;
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    *dstptr = result;
+	    return(NOEXCEPTION);
+	    }
+	right_exponent = 1;	/* Set exponent to reflect different bias
+				 * with denomalized numbers. */
+	}
+    else
+	{
+	Sgl_clear_signexponent_set_hidden(right);
+	}
+    Sgl_clear_exponent_set_hidden(left);
+    diff_exponent = result_exponent - right_exponent;
+
+    /* 
+     * Special case alignment of operands that would force alignment 
+     * beyond the extent of the extension.  A further optimization
+     * could special case this but only reduces the path length for this
+     * infrequent case.
+     */
+    if(diff_exponent > SGL_THRESHOLD)
+	{
+	diff_exponent = SGL_THRESHOLD;
+	}
+    
+    /* Align right operand by shifting to right */
+    Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,
+      /*and lower to*/extent);
+
+    /* Treat sum and difference of the operands separately. */
+    if( (/*signed*/int) save >= 0 )
+	{
+	/*
+	 * Difference of the two operands.  Their can be no overflow.  A
+	 * borrow can occur out of the hidden bit and force a post
+	 * normalization phase.
+	 */
+	Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);
+	if(Sgl_iszero_hidden(result))
+	    {
+	    /* Handle normalization */
+	    /* A straight foward algorithm would now shift the result
+	     * and extension left until the hidden bit becomes one.  Not
+	     * all of the extension bits need participate in the shift.
+	     * Only the two most significant bits (round and guard) are
+	     * needed.  If only a single shift is needed then the guard
+	     * bit becomes a significant low order bit and the extension
+	     * must participate in the rounding.  If more than a single 
+	     * shift is needed, then all bits to the right of the guard 
+	     * bit are zeros, and the guard bit may or may not be zero. */
+	    sign_save = Sgl_signextendedsign(result);
+            Sgl_leftshiftby1_withextent(result,extent,result);
+
+            /* Need to check for a zero result.  The sign and exponent
+	     * fields have already been zeroed.  The more efficient test
+	     * of the full object can be used.
+	     */
+    	    if(Sgl_iszero(result))
+		/* Must have been "x-x" or "x+(-x)". */
+		{
+		if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);
+		*dstptr = result;
+		return(NOEXCEPTION);
+		}
+	    result_exponent--;
+	    /* Look to see if normalization is finished. */
+	    if(Sgl_isone_hidden(result))
+		{
+		if(result_exponent==0)
+		    {
+		    /* Denormalized, exponent should be zero.  Left operand *
+ 		     * was normalized, so extent (guard, round) was zero    */
+		    goto underflow;
+		    }
+		else
+		    {
+		    /* No further normalization is needed. */
+		    Sgl_set_sign(result,/*using*/sign_save);
+	    	    Ext_leftshiftby1(extent);
+		    goto round;
+		    }
+		}
+
+	    /* Check for denormalized, exponent should be zero.  Left    *
+	     * operand was normalized, so extent (guard, round) was zero */
+	    if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+	       result_exponent==0) goto underflow;
+
+	    /* Shift extension to complete one bit of normalization and
+	     * update exponent. */
+	    Ext_leftshiftby1(extent);
+
+	    /* Discover first one bit to determine shift amount.  Use a
+	     * modified binary search.  We have already shifted the result
+	     * one position right and still not found a one so the remainder
+	     * of the extension must be zero and simplifies rounding. */
+	    /* Scan bytes */
+	    while(Sgl_iszero_hiddenhigh7mantissa(result))
+		{
+		Sgl_leftshiftby8(result);
+		if((result_exponent -= 8) <= 0  && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Now narrow it down to the nibble */
+	    if(Sgl_iszero_hiddenhigh3mantissa(result))
+		{
+		/* The lower nibble contains the normalizing one */
+		Sgl_leftshiftby4(result);
+		if((result_exponent -= 4) <= 0 && !underflowtrap)
+		    goto underflow;
+		}
+	    /* Select case were first bit is set (already normalized)
+	     * otherwise select the proper shift. */
+	    if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)
+		{
+		/* Already normalized */
+		if(result_exponent <= 0) goto underflow;
+		Sgl_set_sign(result,/*using*/sign_save);
+		Sgl_set_exponent(result,/*using*/result_exponent);
+		*dstptr = result;
+		return(NOEXCEPTION);
+		}
+	    Sgl_sethigh4bits(result,/*using*/sign_save);
+	    switch(jumpsize) 
+		{
+		case 1:
+		    {
+		    Sgl_leftshiftby3(result);
+		    result_exponent -= 3;
+		    break;
+		    }
+		case 2:
+		case 3:
+		    {
+		    Sgl_leftshiftby2(result);
+		    result_exponent -= 2;
+		    break;
+		    }
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+		    {
+		    Sgl_leftshiftby1(result);
+		    result_exponent -= 1;
+		    break;
+		    }
+		}
+	    if(result_exponent > 0) 
+		{
+		Sgl_set_exponent(result,/*using*/result_exponent);
+		*dstptr = result;	/* Sign bit is already set */
+		return(NOEXCEPTION);
+		}
+	    /* Fixup potential underflows */
+	  underflow:
+	    if(Is_underflowtrap_enabled())
+		{
+		Sgl_set_sign(result,sign_save);
+                Sgl_setwrapped_exponent(result,result_exponent,unfl);
+		*dstptr = result;
+		/* inexact = FALSE */
+		return(UNDERFLOWEXCEPTION);
+		}
+	    /*
+	     * Since we cannot get an inexact denormalized result,
+	     * we can now return.
+	     */
+	    Sgl_right_align(result,/*by*/(1-result_exponent),extent);
+	    Sgl_clear_signexponent(result);
+	    Sgl_set_sign(result,sign_save);
+	    *dstptr = result;
+	    return(NOEXCEPTION);
+	    } /* end if(hidden...)... */
+	/* Fall through and round */
+	} /* end if(save >= 0)... */
+    else 
+	{
+	/* Add magnitudes */
+	Sgl_addition(left,right,/*to*/result);
+	if(Sgl_isone_hiddenoverflow(result))
+	    {
+	    /* Prenormalization required. */
+	    Sgl_rightshiftby1_withextent(result,extent,extent);
+	    Sgl_arithrightshiftby1(result);
+	    result_exponent++;
+	    } /* end if hiddenoverflow... */
+	} /* end else ...sub magnitudes... */
+    
+    /* Round the result.  If the extension is all zeros,then the result is
+     * exact.  Otherwise round in the correct direction.  No underflow is
+     * possible. If a postnormalization is necessary, then the mantissa is
+     * all zeros so no shift is needed. */
+  round:
+    if(Ext_isnotzero(extent))
+	{
+	inexact = TRUE;
+	switch(Rounding_mode())
+	    {
+	    case ROUNDNEAREST: /* The default. */
+	    if(Ext_isone_sign(extent))
+		{
+		/* at least 1/2 ulp */
+		if(Ext_isnotzero_lower(extent)  ||
+		  Sgl_isone_lowmantissa(result))
+		    {
+		    /* either exactly half way and odd or more than 1/2ulp */
+		    Sgl_increment(result);
+		    }
+		}
+	    break;
+
+	    case ROUNDPLUS:
+	    if(Sgl_iszero_sign(result))
+		{
+		/* Round up positive results */
+		Sgl_increment(result);
+		}
+	    break;
+	    
+	    case ROUNDMINUS:
+	    if(Sgl_isone_sign(result))
+		{
+		/* Round down negative results */
+		Sgl_increment(result);
+		}
+	    
+	    case ROUNDZERO:;
+	    /* truncate is simple */
+	    } /* end switch... */
+	if(Sgl_isone_hiddenoverflow(result)) result_exponent++;
+	}
+    if(result_exponent == SGL_INFINITY_EXPONENT)
+        {
+        /* Overflow */
+        if(Is_overflowtrap_enabled())
+	    {
+	    Sgl_setwrapped_exponent(result,result_exponent,ovfl);
+	    *dstptr = result;
+	    if (inexact)
+		if (Is_inexacttrap_enabled())
+		    return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+		else Set_inexactflag();
+	    return(OVERFLOWEXCEPTION);
+	    }
+        else
+	    {
+	    Set_overflowflag();
+	    inexact = TRUE;
+	    Sgl_setoverflow(result);
+	    }
+	}
+    else Sgl_set_exponent(result,result_exponent);
+    *dstptr = result;
+    if(inexact) 
+	if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+	else Set_inexactflag();
+    return(NOEXCEPTION);
+    }
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/sgl_float.h linux-2.4.20-pre2/arch/parisc/math-emu/sgl_float.h
--- linux-2.4.20-pre1/arch/parisc/math-emu/sgl_float.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/sgl_float.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,486 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __NO_PA_HDRS
+    PA header file -- do not include this header file for non-PA builds.
+#endif
+
+/* 32-bit word grabing functions */
+#define Sgl_firstword(value) Sall(value)
+#define Sgl_secondword(value) dummy_location
+#define Sgl_thirdword(value) dummy_location
+#define Sgl_fourthword(value) dummy_location
+
+#define Sgl_sign(object) Ssign(object)
+#define Sgl_exponent(object) Sexponent(object)
+#define Sgl_signexponent(object) Ssignexponent(object)
+#define Sgl_mantissa(object) Smantissa(object)
+#define Sgl_exponentmantissa(object) Sexponentmantissa(object)
+#define Sgl_all(object) Sall(object)
+
+/* sgl_and_signs ands the sign bits of each argument and puts the result
+ * into the first argument. sgl_or_signs ors those same sign bits */
+#define Sgl_and_signs( src1dst, src2)		\
+    Sall(src1dst) = (Sall(src2)|~((unsigned int)1<<31)) & Sall(src1dst)
+#define Sgl_or_signs( src1dst, src2)		\
+    Sall(src1dst) = (Sall(src2)&((unsigned int)1<<31)) | Sall(src1dst)
+
+/* The hidden bit is always the low bit of the exponent */
+#define Sgl_clear_exponent_set_hidden(srcdst) Deposit_sexponent(srcdst,1)
+#define Sgl_clear_signexponent_set_hidden(srcdst) \
+    Deposit_ssignexponent(srcdst,1)
+#define Sgl_clear_sign(srcdst) Sall(srcdst) &= ~((unsigned int)1<<31)
+#define Sgl_clear_signexponent(srcdst) Sall(srcdst) &= 0x007fffff
+
+/* varamount must be less than 32 for the next three functions */
+#define Sgl_rightshift(srcdst, varamount)	\
+    Sall(srcdst) >>= varamount
+#define Sgl_leftshift(srcdst, varamount)	\
+    Sall(srcdst) <<= varamount
+#define Sgl_rightshift_exponentmantissa(srcdst, varamount) \
+    Sall(srcdst) = \
+	(Sexponentmantissa(srcdst) >> varamount) | \
+	(Sall(srcdst) & ((unsigned int)1<<31))
+
+#define Sgl_leftshiftby1_withextent(left,right,result) \
+    Shiftdouble(Sall(left),Extall(right),31,Sall(result))
+    
+#define Sgl_rightshiftby1_withextent(left,right,dst)		\
+    Shiftdouble(Sall(left),Extall(right),1,Extall(right))
+#define Sgl_arithrightshiftby1(srcdst)	\
+    Sall(srcdst) = (int)Sall(srcdst) >> 1
+    
+/* Sign extend the sign bit with an integer destination */
+#define Sgl_signextendedsign(value) Ssignedsign(value)
+
+#define Sgl_isone_hidden(sgl_value) (Shidden(sgl_value))
+#define Sgl_increment(sgl_value) Sall(sgl_value) += 1
+#define Sgl_increment_mantissa(sgl_value) \
+    Deposit_smantissa(sgl_value,sgl_value+1)
+#define Sgl_decrement(sgl_value) Sall(sgl_value) -= 1
+
+#define Sgl_isone_sign(sgl_value) (Is_ssign(sgl_value)!=0)
+#define Sgl_isone_hiddenoverflow(sgl_value) \
+    (Is_shiddenoverflow(sgl_value)!=0)
+#define Sgl_isone_lowmantissa(sgl_value) (Is_slow(sgl_value)!=0)
+#define Sgl_isone_signaling(sgl_value) (Is_ssignaling(sgl_value)!=0)
+#define Sgl_is_signalingnan(sgl_value) (Ssignalingnan(sgl_value)==0x1ff)
+#define Sgl_isnotzero(sgl_value) (Sall(sgl_value)!=0)
+#define Sgl_isnotzero_hiddenhigh7mantissa(sgl_value) \
+    (Shiddenhigh7mantissa(sgl_value)!=0)
+#define Sgl_isnotzero_low4(sgl_value) (Slow4(sgl_value)!=0)
+#define Sgl_isnotzero_exponent(sgl_value) (Sexponent(sgl_value)!=0)
+#define Sgl_isnotzero_mantissa(sgl_value) (Smantissa(sgl_value)!=0)
+#define Sgl_isnotzero_exponentmantissa(sgl_value) \
+    (Sexponentmantissa(sgl_value)!=0)
+#define Sgl_iszero(sgl_value) (Sall(sgl_value)==0)
+#define Sgl_iszero_signaling(sgl_value) (Is_ssignaling(sgl_value)==0)
+#define Sgl_iszero_hidden(sgl_value) (Is_shidden(sgl_value)==0)
+#define Sgl_iszero_hiddenoverflow(sgl_value) \
+    (Is_shiddenoverflow(sgl_value)==0)
+#define Sgl_iszero_hiddenhigh3mantissa(sgl_value) \
+    (Shiddenhigh3mantissa(sgl_value)==0)
+#define Sgl_iszero_hiddenhigh7mantissa(sgl_value) \
+    (Shiddenhigh7mantissa(sgl_value)==0)
+#define Sgl_iszero_sign(sgl_value) (Is_ssign(sgl_value)==0)
+#define Sgl_iszero_exponent(sgl_value) (Sexponent(sgl_value)==0)
+#define Sgl_iszero_mantissa(sgl_value) (Smantissa(sgl_value)==0)
+#define Sgl_iszero_exponentmantissa(sgl_value) \
+    (Sexponentmantissa(sgl_value)==0)
+#define Sgl_isinfinity_exponent(sgl_value) 		\
+    (Sgl_exponent(sgl_value)==SGL_INFINITY_EXPONENT)
+#define Sgl_isnotinfinity_exponent(sgl_value) 		\
+    (Sgl_exponent(sgl_value)!=SGL_INFINITY_EXPONENT)
+#define Sgl_isinfinity(sgl_value)			\
+    (Sgl_exponent(sgl_value)==SGL_INFINITY_EXPONENT &&	\
+    Sgl_mantissa(sgl_value)==0)
+#define Sgl_isnan(sgl_value)				\
+    (Sgl_exponent(sgl_value)==SGL_INFINITY_EXPONENT &&	\
+    Sgl_mantissa(sgl_value)!=0)
+#define Sgl_isnotnan(sgl_value)				\
+    (Sgl_exponent(sgl_value)!=SGL_INFINITY_EXPONENT ||	\
+    Sgl_mantissa(sgl_value)==0)
+#define Sgl_islessthan(sgl_op1,sgl_op2)			\
+    (Sall(sgl_op1) < Sall(sgl_op2))
+#define Sgl_isgreaterthan(sgl_op1,sgl_op2)		\
+    (Sall(sgl_op1) > Sall(sgl_op2))
+#define Sgl_isnotlessthan(sgl_op1,sgl_op2)		\
+    (Sall(sgl_op1) >= Sall(sgl_op2))
+#define Sgl_isequal(sgl_op1,sgl_op2)			\
+    (Sall(sgl_op1) == Sall(sgl_op2))
+
+#define Sgl_leftshiftby8(sgl_value) \
+    Sall(sgl_value) <<= 8
+#define Sgl_leftshiftby4(sgl_value) \
+    Sall(sgl_value) <<= 4
+#define Sgl_leftshiftby3(sgl_value) \
+    Sall(sgl_value) <<= 3
+#define Sgl_leftshiftby2(sgl_value) \
+    Sall(sgl_value) <<= 2
+#define Sgl_leftshiftby1(sgl_value) \
+    Sall(sgl_value) <<= 1
+#define Sgl_rightshiftby1(sgl_value) \
+    Sall(sgl_value) >>= 1
+#define Sgl_rightshiftby4(sgl_value) \
+    Sall(sgl_value) >>= 4
+#define Sgl_rightshiftby8(sgl_value) \
+    Sall(sgl_value) >>= 8
+    
+#define Sgl_ismagnitudeless(signlessleft,signlessright)			\
+/*  unsigned int signlessleft, signlessright; */			\
+      (signlessleft < signlessright)  
+    
+
+#define Sgl_copytoint_exponentmantissa(source,dest)     \
+    dest = Sexponentmantissa(source)
+
+/* A quiet NaN has the high mantissa bit clear and at least on other (in this
+ * case the adjacent bit) bit set. */
+#define Sgl_set_quiet(sgl_value) Deposit_shigh2mantissa(sgl_value,1)
+#define Sgl_set_exponent(sgl_value,exp) Deposit_sexponent(sgl_value,exp)
+
+#define Sgl_set_mantissa(dest,value) Deposit_smantissa(dest,value)
+#define Sgl_set_exponentmantissa(dest,value) \
+    Deposit_sexponentmantissa(dest,value)
+
+/*  An infinity is represented with the max exponent and a zero mantissa */
+#define Sgl_setinfinity_exponent(sgl_value) \
+    Deposit_sexponent(sgl_value,SGL_INFINITY_EXPONENT)
+#define Sgl_setinfinity_exponentmantissa(sgl_value)	\
+    Deposit_sexponentmantissa(sgl_value, \
+	(SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH))))
+#define Sgl_setinfinitypositive(sgl_value)		\
+    Sall(sgl_value) = (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH)))
+#define Sgl_setinfinitynegative(sgl_value)		\
+    Sall(sgl_value) = (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH))) \
+    | ((unsigned int)1<<31)
+#define Sgl_setinfinity(sgl_value,sign)					\
+    Sall(sgl_value) = (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH))) | \
+     ((unsigned int)sign << 31)
+#define Sgl_sethigh4bits(sgl_value, extsign)  \
+    Deposit_shigh4(sgl_value,extsign)
+#define Sgl_set_sign(sgl_value,sign) Deposit_ssign(sgl_value,sign)
+#define Sgl_invert_sign(sgl_value)  \
+    Deposit_ssign(sgl_value,~Ssign(sgl_value))
+#define Sgl_setone_sign(sgl_value) Deposit_ssign(sgl_value,1)
+#define Sgl_setone_lowmantissa(sgl_value) Deposit_slow(sgl_value,1)
+#define Sgl_setzero_sign(sgl_value)  Sall(sgl_value) &= 0x7fffffff
+#define Sgl_setzero_exponent(sgl_value) Sall(sgl_value) &= 0x807fffff
+#define Sgl_setzero_mantissa(sgl_value) Sall(sgl_value) &= 0xff800000
+#define Sgl_setzero_exponentmantissa(sgl_value)  Sall(sgl_value) &= 0x80000000
+#define Sgl_setzero(sgl_value) Sall(sgl_value) = 0
+#define Sgl_setnegativezero(sgl_value) Sall(sgl_value) = (unsigned int)1 << 31
+
+/* Use following macro for both overflow & underflow conditions */
+#define ovfl -
+#define unfl +
+#define Sgl_setwrapped_exponent(sgl_value,exponent,op) \
+    Deposit_sexponent(sgl_value,(exponent op SGL_WRAP))
+
+#define Sgl_setlargestpositive(sgl_value) 				\
+    Sall(sgl_value) = ((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH)))	\
+                      | ((1<<(32-(1+SGL_EXP_LENGTH))) - 1 )
+#define Sgl_setlargestnegative(sgl_value)				\
+    Sall(sgl_value) = ((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH)))	\
+                      | ((1<<(32-(1+SGL_EXP_LENGTH))) - 1 )		\
+		      | ((unsigned int)1<<31)
+
+#define Sgl_setnegativeinfinity(sgl_value)	\
+    Sall(sgl_value) = 				\
+    ((1<<SGL_EXP_LENGTH) | SGL_INFINITY_EXPONENT) << (32-(1+SGL_EXP_LENGTH))
+#define Sgl_setlargest(sgl_value,sign) 					\
+    Sall(sgl_value) = (unsigned int)sign << 31 |			\
+        (((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH)))		\
+	  | ((1 << (32-(1+SGL_EXP_LENGTH))) - 1 ))
+#define Sgl_setlargest_exponentmantissa(sgl_value)			\
+    Sall(sgl_value) = Sall(sgl_value) & ((unsigned int)1<<31) |		\
+        (((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH)))		\
+	  | ((1 << (32-(1+SGL_EXP_LENGTH))) - 1 ))
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Sgl_right_align(srcdst,shift,extent)				\
+    /* sgl_floating_point srcdst; int shift; extension extent */	\
+    if (shift < 32) {							\
+	Extall(extent) = Sall(srcdst) << (32-(shift));			\
+    	Sall(srcdst) >>= shift;						\
+    }									\
+    else {								\
+	Extall(extent) = Sall(srcdst);					\
+	Sall(srcdst) = 0;						\
+    }
+#define Sgl_hiddenhigh3mantissa(sgl_value) Shiddenhigh3mantissa(sgl_value)
+#define Sgl_hidden(sgl_value) Shidden(sgl_value)
+#define Sgl_lowmantissa(sgl_value) Slow(sgl_value)
+
+/* The left argument is never smaller than the right argument */
+#define Sgl_subtract(sgl_left,sgl_right,sgl_result) \
+    Sall(sgl_result) = Sall(sgl_left) - Sall(sgl_right)
+
+/* Subtract right augmented with extension from left augmented with zeros and
+ * store into result and extension. */
+#define Sgl_subtract_withextension(left,right,extent,result)		\
+    /* sgl_floating_point left,right,result; extension extent */	\
+  Sgl_subtract(left,right,result);					\
+  if((Extall(extent) = 0-Extall(extent)))				\
+      Sall(result) = Sall(result)-1
+
+#define Sgl_addition(sgl_left,sgl_right,sgl_result) \
+    Sall(sgl_result) = Sall(sgl_left) + Sall(sgl_right)
+
+#define Sgl_xortointp1(left,right,result)			\
+    result = Sall(left) XOR Sall(right);
+
+#define Sgl_xorfromintp1(left,right,result)			\
+    Sall(result) = left XOR Sall(right)
+
+/* Need to Initialize */
+#define Sgl_makequietnan(dest)						\
+    Sall(dest) = ((SGL_EMAX+SGL_BIAS)+1)<< (32-(1+SGL_EXP_LENGTH))	\
+                 | (1<<(32-(1+SGL_EXP_LENGTH+2)))
+#define Sgl_makesignalingnan(dest)					\
+    Sall(dest) = ((SGL_EMAX+SGL_BIAS)+1)<< (32-(1+SGL_EXP_LENGTH))	\
+                 | (1<<(32-(1+SGL_EXP_LENGTH+1)))
+
+#define Sgl_normalize(sgl_opnd,exponent)			\
+	while(Sgl_iszero_hiddenhigh7mantissa(sgl_opnd)) {	\
+		Sgl_leftshiftby8(sgl_opnd);			\
+		exponent -= 8;					\
+	}							\
+	if(Sgl_iszero_hiddenhigh3mantissa(sgl_opnd)) {		\
+		Sgl_leftshiftby4(sgl_opnd);			\
+		exponent -= 4;					\
+	}							\
+	while(Sgl_iszero_hidden(sgl_opnd)) {			\
+		Sgl_leftshiftby1(sgl_opnd);			\
+		exponent -= 1;					\
+	}
+
+#define Sgl_setoverflow(sgl_opnd)				\
+	/* set result to infinity or largest number */		\
+	switch (Rounding_mode()) {				\
+		case ROUNDPLUS:					\
+			if (Sgl_isone_sign(sgl_opnd)) {		\
+				Sgl_setlargestnegative(sgl_opnd); \
+			}					\
+			else {					\
+				Sgl_setinfinitypositive(sgl_opnd); \
+			}					\
+			break;					\
+		case ROUNDMINUS:				\
+			if (Sgl_iszero_sign(sgl_opnd)) {	\
+				Sgl_setlargestpositive(sgl_opnd); \
+			}					\
+			else {					\
+				Sgl_setinfinitynegative(sgl_opnd); \
+			}					\
+			break;					\
+		case ROUNDNEAREST:				\
+			Sgl_setinfinity_exponentmantissa(sgl_opnd); \
+			break;					\
+		case ROUNDZERO:					\
+			Sgl_setlargest_exponentmantissa(sgl_opnd); \
+	}
+
+#define Sgl_denormalize(opnd,exponent,guard,sticky,inexact)		\
+	Sgl_clear_signexponent_set_hidden(opnd);			\
+	if (exponent >= (1 - SGL_P)) {					\
+		guard = (Sall(opnd) >> -exponent) & 1;			\
+		if (exponent < 0) sticky |= Sall(opnd) << (32+exponent); \
+		inexact = guard | sticky;				\
+		Sall(opnd) >>= (1-exponent);				\
+	}								\
+	else {								\
+		guard = 0;						\
+		sticky |= Sall(opnd);					\
+		inexact = sticky;					\
+		Sgl_setzero(opnd);					\
+	}
+
+/* 
+ * The fused multiply add instructions requires a single extended format,
+ * with 48 bits of mantissa.
+ */
+#define SGLEXT_THRESHOLD 48
+
+#define Sglext_setzero(valA,valB)	\
+    Sextallp1(valA) = 0; Sextallp2(valB) = 0
+
+#define Sglext_isnotzero_mantissap2(valB) (Sextallp2(valB)!=0)
+#define Sglext_isone_lowp1(val) (Sextlowp1(val)!=0)
+#define Sglext_isone_highp2(val) (Sexthighp2(val)!=0)
+#define Sglext_isnotzero_low31p2(val) (Sextlow31p2(val)!=0)
+#define Sglext_iszero(valA,valB) (Sextallp1(valA)==0 && Sextallp2(valB)==0)
+
+#define Sgl_copytoptr(src,destptr) *destptr = src
+#define Sgl_copyfromptr(srcptr,dest) dest = *srcptr
+#define Sglext_copy(srca,srcb,desta,destb) \
+    Sextallp1(desta) = Sextallp1(srca);	\
+    Sextallp2(destb) = Sextallp2(srcb)
+#define Sgl_copyto_sglext(src1,dest1,dest2) \
+	Sextallp1(dest1) = Sall(src1); Sextallp2(dest2) = 0
+
+#define Sglext_swap_lower(leftp2,rightp2)  \
+    Sextallp2(leftp2)  = Sextallp2(leftp2) XOR Sextallp2(rightp2);  \
+    Sextallp2(rightp2) = Sextallp2(leftp2) XOR Sextallp2(rightp2);  \
+    Sextallp2(leftp2)  = Sextallp2(leftp2) XOR Sextallp2(rightp2)
+
+#define Sglext_setone_lowmantissap2(value) Deposit_dlowp2(value,1)
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Sglext_right_align(srcdstA,srcdstB,shift) \
+  {int shiftamt, sticky;						\
+    shiftamt = shift % 32;						\
+    sticky = 0;								\
+    switch (shift/32) {							\
+     case 0: if (shiftamt > 0) {					\
+	        sticky = Sextallp2(srcdstB) << 32 - (shiftamt);		\
+                Variable_shift_double(Sextallp1(srcdstA),		\
+		 Sextallp2(srcdstB),shiftamt,Sextallp2(srcdstB));	\
+	        Sextallp1(srcdstA) >>= shiftamt;			\
+	     }								\
+	     break;							\
+     case 1: if (shiftamt > 0) {					\
+	        sticky = (Sextallp1(srcdstA) << 32 - (shiftamt)) |	\
+			 Sextallp2(srcdstB);				\
+	     }								\
+	     else {							\
+		sticky = Sextallp2(srcdstB);				\
+	     }								\
+	     Sextallp2(srcdstB) = Sextallp1(srcdstA) >> shiftamt;	\
+	     Sextallp1(srcdstA) = 0;					\
+	     break;							\
+    }									\
+    if (sticky) Sglext_setone_lowmantissap2(srcdstB);			\
+  }
+
+/* The left argument is never smaller than the right argument */
+#define Sglext_subtract(lefta,leftb,righta,rightb,resulta,resultb) \
+    if( Sextallp2(rightb) > Sextallp2(leftb) ) Sextallp1(lefta)--; \
+    Sextallp2(resultb) = Sextallp2(leftb) - Sextallp2(rightb);	\
+    Sextallp1(resulta) = Sextallp1(lefta) - Sextallp1(righta)
+
+#define Sglext_addition(lefta,leftb,righta,rightb,resulta,resultb) \
+    /* If the sum of the low words is less than either source, then \
+     * an overflow into the next word occurred. */ \
+    if ((Sextallp2(resultb) = Sextallp2(leftb)+Sextallp2(rightb)) < \
+        Sextallp2(rightb)) \
+	    Sextallp1(resulta) = Sextallp1(lefta)+Sextallp1(righta)+1; \
+    else Sextallp1(resulta) = Sextallp1(lefta)+Sextallp1(righta)
+
+
+#define Sglext_arithrightshiftby1(srcdstA,srcdstB)	\
+    Shiftdouble(Sextallp1(srcdstA),Sextallp2(srcdstB),1,Sextallp2(srcdstB)); \
+    Sextallp1(srcdstA) = (int)Sextallp1(srcdstA) >> 1
+   
+#define Sglext_leftshiftby8(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),24,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 8
+#define Sglext_leftshiftby4(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),28,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 4
+#define Sglext_leftshiftby3(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),29,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 3
+#define Sglext_leftshiftby2(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),30,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 2
+#define Sglext_leftshiftby1(valA,valB) \
+    Shiftdouble(Sextallp1(valA),Sextallp2(valB),31,Sextallp1(valA)); \
+    Sextallp2(valB) <<= 1
+
+#define Sglext_rightshiftby4(valueA,valueB) \
+    Shiftdouble(Sextallp1(valueA),Sextallp2(valueB),4,Sextallp2(valueB)); \
+    Sextallp1(valueA) >>= 4
+#define Sglext_rightshiftby3(valueA,valueB) \
+    Shiftdouble(Sextallp1(valueA),Sextallp2(valueB),3,Sextallp2(valueB)); \
+    Sextallp1(valueA) >>= 3
+#define Sglext_rightshiftby1(valueA,valueB) \
+    Shiftdouble(Sextallp1(valueA),Sextallp2(valueB),1,Sextallp2(valueB)); \
+    Sextallp1(valueA) >>= 1
+
+#define Sglext_xortointp1(left,right,result) Sgl_xortointp1(left,right,result)
+#define Sglext_xorfromintp1(left,right,result) \
+	Sgl_xorfromintp1(left,right,result)
+#define Sglext_copytoint_exponentmantissa(src,dest) \
+	Sgl_copytoint_exponentmantissa(src,dest)
+#define Sglext_ismagnitudeless(signlessleft,signlessright) \
+	Sgl_ismagnitudeless(signlessleft,signlessright)
+
+#define Sglext_set_sign(dbl_value,sign)  Sgl_set_sign(dbl_value,sign)  
+#define Sglext_clear_signexponent_set_hidden(srcdst) \
+	Sgl_clear_signexponent_set_hidden(srcdst) 
+#define Sglext_clear_signexponent(srcdst) Sgl_clear_signexponent(srcdst) 
+#define Sglext_clear_sign(srcdst) Sgl_clear_sign(srcdst) 
+#define Sglext_isone_hidden(dbl_value) Sgl_isone_hidden(dbl_value) 
+
+#define Sglext_denormalize(opndp1,opndp2,exponent,is_tiny)		\
+  {int sticky;								\
+    is_tiny = TRUE;							\
+    if (exponent == 0 && Sextallp2(opndp2)) {				\
+	switch (Rounding_mode()) {					\
+	case ROUNDPLUS:							\
+		if (Sgl_iszero_sign(opndp1))				\
+			if (Sgl_isone_hiddenoverflow(opndp1 + 1))	\
+				is_tiny = FALSE;			\
+		break;							\
+	case ROUNDMINUS:						\
+		if (Sgl_isone_sign(opndp1)) {				\
+			if (Sgl_isone_hiddenoverflow(opndp1 + 1))	\
+				is_tiny = FALSE;			\
+		}							\
+		break;							\
+	case ROUNDNEAREST:						\
+		if (Sglext_isone_highp2(opndp2) &&			\
+		    (Sglext_isone_lowp1(opndp1) || 			\
+		     Sglext_isnotzero_low31p2(opndp2)))			\
+			if (Sgl_isone_hiddenoverflow(opndp1 + 1))	\
+				is_tiny = FALSE;			\
+		break;							\
+	}								\
+    }									\
+    Sglext_clear_signexponent_set_hidden(opndp1);			\
+    if (exponent >= (1-DBL_P)) {					\
+	if (exponent >= -31) {						\
+	    if (exponent > -31) {					\
+		sticky = Sextallp2(opndp2) << 31+exponent;		\
+		Variable_shift_double(opndp1,opndp2,1-exponent,opndp2);	\
+		Sextallp1(opndp1) >>= 1-exponent;			\
+	    }								\
+	    else {							\
+		sticky = Sextallp2(opndp2);				\
+		Sextallp2(opndp2) = Sextallp1(opndp1);			\
+		Sextallp1(opndp1) = 0;					\
+	    }								\
+	}								\
+	else {								\
+	    sticky = (Sextallp1(opndp1) << 31+exponent) | 		\
+		     Sextallp2(opndp2);					\
+	    Sextallp2(opndp2) = Sextallp1(opndp1) >> -31-exponent;	\
+	    Sextallp1(opndp1) = 0;					\
+	}								\
+    }									\
+    else {								\
+	sticky = Sextallp1(opndp1) | Sextallp2(opndp2);			\
+	Sglext_setzero(opndp1,opndp2);					\
+    }									\
+    if (sticky) Sglext_setone_lowmantissap2(opndp2);			\
+    exponent = 0;							\
+  }
diff -urN linux-2.4.20-pre1/arch/parisc/math-emu/types.h linux-2.4.20-pre2/arch/parisc/math-emu/types.h
--- linux-2.4.20-pre1/arch/parisc/math-emu/types.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/math-emu/types.h	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,25 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.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, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#define BUG() do { \
+        printk(KERN_ERR "floating-pt emulation BUG at %s:%d!\n", __FILE__, __LINE__); \
+} while (0)
diff -urN linux-2.4.20-pre1/arch/parisc/mm/Makefile linux-2.4.20-pre2/arch/parisc/mm/Makefile
--- linux-2.4.20-pre1/arch/parisc/mm/Makefile	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/mm/Makefile	Mon Aug 12 16:34:14 2002
@@ -8,6 +8,6 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS	 := init.o fault.o kmap.o extable.o
+obj-y	 := init.o fault.o extable.o ioremap.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/arch/parisc/mm/extable.c linux-2.4.20-pre2/arch/parisc/mm/extable.c
--- linux-2.4.20-pre1/arch/parisc/mm/extable.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/mm/extable.c	Mon Aug 12 16:34:14 2002
@@ -46,17 +46,17 @@
 const struct exception_table_entry *
 search_exception_table (unsigned long addr)
 {
-#ifndef CONFIG_MODULE
+#ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	return search_one_table(__start___ex_table, 
                                 __stop___ex_table - 1, 
                                 addr);
 #else
-	struct exception_table_entry *ret;
 	/* The kernel is the last "module" -- no need to treat it special. */
 	struct module *mp;
 
 	for (mp = module_list; mp ; mp = mp->next) {
+		const struct exception_table_entry *ret;
 		if (!mp->ex_table_start)
 			continue;
 		ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1,
diff -urN linux-2.4.20-pre1/arch/parisc/mm/fault.c linux-2.4.20-pre2/arch/parisc/mm/fault.c
--- linux-2.4.20-pre1/arch/parisc/mm/fault.c	Mon Mar 19 12:37:16 2001
+++ linux-2.4.20-pre2/arch/parisc/mm/fault.c	Mon Aug 12 16:34:14 2002
@@ -17,6 +17,10 @@
 #include <linux/interrupt.h>
 
 #include <asm/uaccess.h>
+#include <asm/traps.h>
+
+#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
+			 /*  dumped to the console via printk)          */
 
 
 /* Defines for parisc_acctyp()	*/
@@ -114,59 +118,31 @@
 #undef isGraphicsFlushRead
 #undef BITSSET
 
-/* This is similar to expand_stack(), except that it is for stacks
- * that grow upwards.
- */
-
-static inline int expand_stackup(struct vm_area_struct * vma, unsigned long address)
-{
-	unsigned long grow;
-
-	address += 4 + PAGE_SIZE - 1;
-	address &= PAGE_MASK;
-	grow = (address - vma->vm_end) >> PAGE_SHIFT;
-	if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur ||
-	    ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)
-		return -ENOMEM;
-	vma->vm_end = address;
-	vma->vm_mm->total_vm += grow;
-	if (vma->vm_flags & VM_LOCKED)
-		vma->vm_mm->locked_vm += grow;
-	return 0;
-}
-
-
-/* This is similar to find_vma(), except that it understands that stacks
- * grow up rather than down.
- * XXX Optimise by making use of cache and avl tree as per find_vma().
- */
 
-struct vm_area_struct * pa_find_vma(struct mm_struct * mm, unsigned long addr)
-{
-	struct vm_area_struct *vma = NULL;
-
-	if (mm) {
-		vma = mm->mmap;
-		if (!vma || addr < vma->vm_start)
-			return NULL;
-		while (vma->vm_next && addr >= vma->vm_next->vm_start)
-			vma = vma->vm_next;
-	}
-	return vma;
-}
-
-
-/*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long);
+#if 0
+/* This is the treewalk to find a vma which is the highest that has
+ * a start < addr.  We're using find_vma_prev instead right now, but
+ * we might want to use this at some point in the future.  Probably
+ * not, but I want it committed to CVS so I don't lose it :-)
+ */
+			while (tree != vm_avl_empty) {
+				if (tree->vm_start > addr) {
+					tree = tree->vm_avl_left;
+				} else {
+					prev = tree;
+					if (prev->vm_next == NULL)
+						break;
+					if (prev->vm_next->vm_start > addr)
+						break;
+					tree = tree->vm_avl_right;
+				}
+			}
+#endif
 
 void do_page_fault(struct pt_regs *regs, unsigned long code,
 			      unsigned long address)
 {
-	struct vm_area_struct * vma;
+	struct vm_area_struct *vma, *prev_vma;
 	struct task_struct *tsk = current;
 	struct mm_struct *mm = tsk->mm;
 	const struct exception_table_entry *fix;
@@ -176,13 +152,9 @@
 		goto no_context;
 
 	down_read(&mm->mmap_sem);
-	vma = pa_find_vma(mm, address);
-	if (!vma)
-		goto bad_area;
-	if (address < vma->vm_end)
-		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSUP) || expand_stackup(vma, address))
-		goto bad_area;
+	vma = find_vma_prev(mm, address, &prev_vma);
+	if (!vma || address < vma->vm_start)
+		goto check_expansion;
 /*
  * Ok, we have a good vm_area for this memory access. We still need to
  * check the access permissions.
@@ -221,6 +193,11 @@
 	up_read(&mm->mmap_sem);
 	return;
 
+check_expansion:
+	vma = prev_vma;
+	if (vma && (expand_stack(vma, address) == 0))
+		goto good_area;
+
 /*
  * Something tried to access memory that isn't in our memory map..
  */
@@ -230,9 +207,16 @@
 	if (user_mode(regs)) {
 		struct siginfo si;
 
-		printk("\ndo_page_fault() pid=%d command='%s'\n",
-		    tsk->pid, tsk->comm);
+#ifdef PRINT_USER_FAULTS
+		printk(KERN_DEBUG "\n");
+		printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n",
+		    tsk->pid, tsk->comm, code, address);
+		if (vma) {
+			printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n",
+					vma->vm_start, vma->vm_end);
+		}
 		show_regs(regs);
+#endif
 		/* FIXME: actually we need to get the signo and code correct */
 		si.si_signo = SIGSEGV;
 		si.si_errno = 0;
@@ -272,11 +256,11 @@
 		}
 	}
 
-	parisc_terminate("Bad Address (null pointer deref?)",regs,code,address);
+	parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);
 
   out_of_memory:
 	up_read(&mm->mmap_sem);
-	printk("VM: killing process %s\n", current->comm);
+	printk(KERN_CRIT "VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
 	goto no_context;
diff -urN linux-2.4.20-pre1/arch/parisc/mm/init.c linux-2.4.20-pre2/arch/parisc/mm/init.c
--- linux-2.4.20-pre1/arch/parisc/mm/init.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/mm/init.c	Mon Aug 12 16:34:14 2002
@@ -15,15 +15,400 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>		/* for hppa_dma_ops and pcxl_dma_ops */
+#include <linux/blk.h>          /* for initrd_start and initrd_end */
 #include <linux/swap.h>
 #include <linux/unistd.h>
 
 #include <asm/pgalloc.h>
+#include <asm/tlb.h>
 
-static unsigned long totalram_pages;
-extern unsigned long max_pfn, mem_max;
+mmu_gather_t mmu_gathers[NR_CPUS];
 
-void free_initmem(void)  {
+extern char _text;	/* start of kernel code, defined by linker */
+extern int  data_start;
+extern char _end;	/* end of BSS, defined by linker */
+extern char __init_begin, __init_end;
+
+#ifdef CONFIG_DISCONTIGMEM
+struct node_map_data node_data[MAX_PHYSMEM_RANGES];
+bootmem_data_t bmem_data[MAX_PHYSMEM_RANGES];
+unsigned char *chunkmap;
+unsigned int maxchunkmap;
+#endif
+
+static struct resource data_resource = {
+	name:	"Kernel data",
+	flags:	IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource code_resource = {
+	name:	"Kernel code",
+	flags:	IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource pdcdata_resource = {
+	name:	"PDC data (Page Zero)",
+	start:	0,
+	end:	0x9ff,
+	flags:	IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource sysram_resources[MAX_PHYSMEM_RANGES];
+
+static unsigned long max_pfn;
+
+/* The following array is initialized from the firmware specific
+ * information retrieved in kernel/inventory.c.
+ */
+
+physmem_range_t pmem_ranges[MAX_PHYSMEM_RANGES];
+int npmem_ranges;
+
+#ifdef __LP64__
+#define MAX_MEM         (~0UL)
+#else /* !__LP64__ */
+#define MAX_MEM         (3584U*1024U*1024U)
+#endif /* !__LP64__ */
+
+static unsigned long mem_limit = MAX_MEM;
+
+static void __init mem_limit_func(void)
+{
+	char *cp, *end;
+	unsigned long limit;
+	extern char saved_command_line[];
+
+	/* We need this before __setup() functions are called */
+
+	limit = MAX_MEM;
+	for (cp = saved_command_line; *cp; ) {
+		if (memcmp(cp, "mem=", 4) == 0) {
+			cp += 4;
+			limit = memparse(cp, &end);
+			if (end != cp)
+				break;
+			cp = end;
+		} else {
+			while (*cp != ' ' && *cp)
+				++cp;
+			while (*cp == ' ')
+				++cp;
+		}
+	}
+
+	if (limit < mem_limit)
+		mem_limit = limit;
+}
+
+#define MAX_GAP (0x40000000UL >> PAGE_SHIFT)
+
+static void __init setup_bootmem(void)
+{
+	unsigned long bootmap_size;
+	unsigned long mem_max;
+	unsigned long bootmap_pages;
+	unsigned long bootmap_start_pfn;
+	unsigned long bootmap_pfn;
+#ifndef CONFIG_DISCONTIGMEM
+	physmem_range_t pmem_holes[MAX_PHYSMEM_RANGES - 1];
+	int npmem_holes;
+#endif
+	int i, sysram_resource_count;
+
+	disable_sr_hashing(); /* Turn off space register hashing */
+
+#ifdef CONFIG_DISCONTIGMEM
+	/*
+	 * The below is still true as of 2.4.2. If this is ever fixed,
+	 * we can remove this warning!
+	 */
+
+	printk(KERN_WARNING "\n\n");
+	printk(KERN_WARNING "CONFIG_DISCONTIGMEM is enabled, which is probably a mistake. This\n");
+	printk(KERN_WARNING "option can lead to heavy swapping, even when there are gigabytes\n");
+	printk(KERN_WARNING "of free memory.\n\n");
+#endif
+
+#ifdef __LP64__
+
+#ifndef CONFIG_DISCONTIGMEM
+	/*
+	 * Sort the ranges. Since the number of ranges is typically
+	 * small, and performance is not an issue here, just do
+	 * a simple insertion sort.
+	 */
+
+	for (i = 1; i < npmem_ranges; i++) {
+		int j;
+
+		for (j = i; j > 0; j--) {
+			unsigned long tmp;
+
+			if (pmem_ranges[j-1].start_pfn <
+			    pmem_ranges[j].start_pfn) {
+
+				break;
+			}
+			tmp = pmem_ranges[j-1].start_pfn;
+			pmem_ranges[j-1].start_pfn = pmem_ranges[j].start_pfn;
+			pmem_ranges[j].start_pfn = tmp;
+			tmp = pmem_ranges[j-1].pages;
+			pmem_ranges[j-1].pages = pmem_ranges[j].pages;
+			pmem_ranges[j].pages = tmp;
+		}
+	}
+
+	/*
+	 * Throw out ranges that are too far apart (controlled by
+	 * MAX_GAP). If CONFIG_DISCONTIGMEM wasn't implemented so
+	 * poorly, we would recommend enabling that option, but,
+	 * until it is fixed, this is the best way to go.
+	 */
+
+	for (i = 1; i < npmem_ranges; i++) {
+		if (pmem_ranges[i].start_pfn -
+			(pmem_ranges[i-1].start_pfn +
+			 pmem_ranges[i-1].pages) > MAX_GAP) {
+			npmem_ranges = i;
+			break;
+		}
+	}
+#endif
+
+	if (npmem_ranges > 1) {
+
+		/* Print the memory ranges */
+
+		printk(KERN_INFO "Memory Ranges:\n");
+
+		for (i = 0; i < npmem_ranges; i++) {
+			unsigned long start;
+			unsigned long size;
+
+			size = (pmem_ranges[i].pages << PAGE_SHIFT);
+			start = (pmem_ranges[i].start_pfn << PAGE_SHIFT);
+			printk(KERN_INFO "%2d) Start 0x%016lx End 0x%016lx Size %6ld Mb\n",
+				i,start, start + (size - 1), size >> 20);
+		}
+	}
+
+#endif /* __LP64__ */
+
+#if 1
+	/* KLUGE! this really belongs in kernel/resource.c! */
+	iomem_resource.end = ~0UL;
+#endif
+
+	sysram_resource_count = npmem_ranges;
+	for (i = 0; i < sysram_resource_count; i++) {
+		struct resource *res = &sysram_resources[i];
+		res->name = "System RAM";
+		res->start = pmem_ranges[i].start_pfn << PAGE_SHIFT;
+		res->end = res->start + (pmem_ranges[i].pages << PAGE_SHIFT)-1;
+		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+		request_resource(&iomem_resource, res);
+	}
+
+	/*
+	 * For 32 bit kernels we limit the amount of memory we can
+	 * support, in order to preserve enough kernel address space
+	 * for other purposes. For 64 bit kernels we don't normally
+	 * limit the memory, but this mechanism can be used to
+	 * artificially limit the amount of memory (and it is written
+	 * to work with multiple memory ranges).
+	 */
+
+	mem_limit_func();       /* check for "mem=" argument */
+
+	mem_max = 0;
+	for (i = 0; i < npmem_ranges; i++) {
+		unsigned long rsize;
+
+		rsize = pmem_ranges[i].pages << PAGE_SHIFT;
+		if ((mem_max + rsize) > mem_limit) {
+			printk(KERN_WARNING "Memory truncated to %ld Mb\n", mem_limit >> 20);
+			if (mem_max == mem_limit)
+				npmem_ranges = i;
+			else {
+				pmem_ranges[i].pages =   (mem_limit >> PAGE_SHIFT)
+						       - (mem_max >> PAGE_SHIFT);
+				npmem_ranges = i + 1;
+				mem_max = mem_limit;
+			}
+			break;
+		}
+		mem_max += rsize;
+	}
+
+	printk(KERN_INFO "Total Memory: %ld Mb\n",mem_max >> 20);
+
+#ifndef CONFIG_DISCONTIGMEM
+
+	/* Merge the ranges, keeping track of the holes */
+
+	{
+		unsigned long end_pfn;
+		unsigned long hole_pages;
+
+		npmem_holes = 0;
+		end_pfn = pmem_ranges[0].start_pfn + pmem_ranges[0].pages;
+		for (i = 1; i < npmem_ranges; i++) {
+
+			hole_pages = pmem_ranges[i].start_pfn - end_pfn;
+			if (hole_pages) {
+				pmem_holes[npmem_holes].start_pfn = end_pfn;
+				pmem_holes[npmem_holes++].pages = hole_pages;
+				end_pfn += hole_pages;
+			}
+			end_pfn += pmem_ranges[i].pages;
+		}
+
+		pmem_ranges[0].pages = end_pfn - pmem_ranges[0].start_pfn;
+		npmem_ranges = 1;
+	}
+#endif
+
+	bootmap_pages = 0;
+	for (i = 0; i < npmem_ranges; i++)
+		bootmap_pages += bootmem_bootmap_pages(pmem_ranges[i].pages);
+
+	bootmap_start_pfn = PAGE_ALIGN(__pa((unsigned long) &_end)) >> PAGE_SHIFT;
+
+#ifdef CONFIG_DISCONTIGMEM
+	for (i = 0; i < npmem_ranges; i++)
+		node_data[i].pg_data.bdata = &bmem_data[i];
+#endif
+	/*
+	 * Initialize and free the full range of memory in each range.
+	 * Note that the only writing these routines do are to the bootmap,
+	 * and we've made sure to locate the bootmap properly so that they
+	 * won't be writing over anything important.
+	 */
+
+	bootmap_pfn = bootmap_start_pfn;
+	max_pfn = 0;
+	for (i = 0; i < npmem_ranges; i++) {
+		unsigned long start_pfn;
+		unsigned long npages;
+
+		start_pfn = pmem_ranges[i].start_pfn;
+		npages = pmem_ranges[i].pages;
+
+		bootmap_size = init_bootmem_node(NODE_DATA(i),
+						bootmap_pfn,
+						start_pfn,
+						(start_pfn + npages) );
+		free_bootmem_node(NODE_DATA(i),
+				  (start_pfn << PAGE_SHIFT),
+				  (npages << PAGE_SHIFT) );
+		bootmap_pfn += (bootmap_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+		if ((start_pfn + npages) > max_pfn)
+			max_pfn = start_pfn + npages;
+	}
+
+	if ((bootmap_pfn - bootmap_start_pfn) != bootmap_pages) {
+		printk(KERN_WARNING "WARNING! bootmap sizing is messed up!\n");
+		BUG();
+	}
+
+	/* reserve PAGE0 pdc memory, kernel text/data/bss & bootmap */
+
+#define PDC_CONSOLE_IO_IODC_SIZE 32768
+
+	reserve_bootmem_node(NODE_DATA(0), 0UL,
+			(unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
+	reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text),
+			(unsigned long)(&_end - &_text));
+	reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
+			((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
+
+#ifndef CONFIG_DISCONTIGMEM
+
+	/* reserve the holes */
+
+	for (i = 0; i < npmem_holes; i++) {
+		reserve_bootmem_node(NODE_DATA(0),
+				(pmem_holes[i].start_pfn << PAGE_SHIFT),
+				(pmem_holes[i].pages << PAGE_SHIFT));
+	}
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start) {
+		printk(KERN_INFO "initrd: %08lx-%08lx\n", initrd_start, initrd_end);
+		if (__pa(initrd_start) < mem_max) {
+			unsigned long initrd_reserve;
+
+			if (__pa(initrd_end) > mem_max) {
+				initrd_reserve = mem_max - __pa(initrd_start);
+			} else {
+				initrd_reserve = initrd_end - initrd_start;
+			}
+			initrd_below_start_ok = 1;
+			printk(KERN_INFO "initrd: reserving %08lx-%08lx (mem_max %08lx)\n", __pa(initrd_start), __pa(initrd_start) + initrd_reserve, mem_max);
+
+			reserve_bootmem_node(NODE_DATA(0),__pa(initrd_start), initrd_reserve);
+		}
+	}
+#endif
+
+	data_resource.start =  virt_to_phys(&data_start);
+	data_resource.end = virt_to_phys(&_end)-1;
+	code_resource.start = virt_to_phys(&_text);
+	code_resource.end = virt_to_phys(&data_start)-1;
+
+	/* We don't know which region the kernel will be in, so try
+	 * all of them.
+	 */
+	for (i = 0; i < sysram_resource_count; i++) {
+		struct resource *res = &sysram_resources[i];
+		request_resource(res, &code_resource);
+		request_resource(res, &data_resource);
+	}
+	request_resource(&sysram_resources[0], &pdcdata_resource);
+}
+
+void free_initmem(void)
+{
+	/* FIXME: */
+#if 0
+	printk(KERN_INFO "NOT FREEING INITMEM (%dk)\n",
+			(&__init_end - &__init_begin) >> 10);
+	return;
+#endif
+	unsigned long addr;
+	
+	printk(KERN_INFO "Freeing unused kernel memory: ");
+
+#if 1
+	/* Attempt to catch anyone trying to execute code here
+	 * by filling the page with BRK insns.
+	 * 
+	 * If we disable interrupts for all CPUs, then IPI stops working.
+	 * Kinda breaks the global cache flushing.
+	 */
+	local_irq_disable();
+
+	memset(&__init_begin, 0x00, 
+		(unsigned long)&__init_end - (unsigned long)&__init_begin);
+
+	flush_data_cache();
+	asm volatile("sync" : : );
+	flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end);
+	asm volatile("sync" : : );
+
+	local_irq_enable();
+#endif
+	
+	addr = (unsigned long)(&__init_begin);
+	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(addr));
+		set_page_count(virt_to_page(addr), 1);
+		free_page(addr);
+		num_physpages++;
+	}
+
+	printk("%luk freed\n", (unsigned long)(&__init_end - &__init_begin) >> 10);
 }
 
 /*
@@ -37,67 +422,42 @@
  * a hole of 4kB between each vmalloced area for the same reason.
  */
 
+#define MAP_START 0x4000 /* Leave room for gateway page expansion */
 #define VM_MAP_OFFSET  (32*1024)
 #define SET_MAP_OFFSET(x) ((void *)(((unsigned long)(x) + VM_MAP_OFFSET) \
 				     & ~(VM_MAP_OFFSET-1)))
 
 void *vmalloc_start;
+#ifdef CONFIG_PA11
 unsigned long pcxl_dma_start;
+#endif
 
 void __init mem_init(void)
 {
-	max_mapnr = num_physpages = max_low_pfn;
-	high_memory = __va(max_low_pfn * PAGE_SIZE);
+	int i;
+
+	high_memory = __va((max_pfn << PAGE_SHIFT));
+	max_mapnr = (virt_to_page(high_memory - 1) - mem_map) + 1;
+
+	num_physpages = 0;
+	for (i = 0; i < npmem_ranges; i++)
+		num_physpages += free_all_bootmem_node(NODE_DATA(i));
 
-	totalram_pages += free_all_bootmem();
-	printk("Memory: %luk available\n", totalram_pages << (PAGE_SHIFT-10));
+	printk(KERN_INFO "Memory: %luk available\n", num_physpages << (PAGE_SHIFT-10));
 
+#ifdef CONFIG_PA11
 	if (hppa_dma_ops == &pcxl_dma_ops) {
-	    pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(high_memory);
+	    pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START);
 	    vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start + PCXL_DMA_MAP_SIZE);
 	}
 	else {
 	    pcxl_dma_start = 0;
-	    vmalloc_start = SET_MAP_OFFSET(high_memory);
-	}
-}
-
-void __bad_pgd(pgd_t *pgd)
-{
-	printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-	pgd_val(*pgd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
-}
-
-void __bad_pmd(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			clear_page(pte);
-			pmd_val(*pmd) = _PAGE_TABLE + __pa((unsigned long)pte);
-			return pte + offset;
-		}
-		pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
-		return NULL;
-	}
-
-	free_page((unsigned long)pte);
-
-	if (pmd_bad(*pmd)) {
-		__bad_pmd(pmd);
-		return NULL;
+	    vmalloc_start = SET_MAP_OFFSET(MAP_START);
 	}
+#else
+	vmalloc_start = SET_MAP_OFFSET(MAP_START);
+#endif
 
-	return (pte_t *) pmd_page(*pmd) + offset;
 }
 
 int do_check_pgt_cache(int low, int high)
@@ -105,40 +465,16 @@
 	return 0;
 }
 
-/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving an inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-pte_t * __bad_pagetable(void)
-{
-	return (pte_t *) NULL;
-}
-
 unsigned long *empty_zero_page;
-unsigned long *empty_bad_page;
-
-pte_t __bad_page(void)
-{
-	return *(pte_t *)NULL;
-}
 
 void show_mem(void)
 {
 	int i,free = 0,total = 0,reserved = 0;
 	int shared = 0, cached = 0;
 
-	printk("Mem-info:\n");
+	printk(KERN_INFO "Mem-info:\n");
 	show_free_areas();
-	printk("Free swap:	 %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+	printk(KERN_INFO "Free swap:	 %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
 	i = max_mapnr;
 	while (i-- > 0) {
 		total++;
@@ -151,54 +487,50 @@
 		else
 			shared += atomic_read(&mem_map[i].count) - 1;
 	}
-	printk("%d pages of RAM\n",total);
-	printk("%d reserved pages\n",reserved);
-	printk("%d pages shared\n",shared);
-	printk("%d pages swap cached\n",cached);
+	printk(KERN_INFO "%d pages of RAM\n", total);
+	printk(KERN_INFO "%d reserved pages\n", reserved);
+	printk(KERN_INFO "%d pages shared\n", shared);
+	printk(KERN_INFO "%d pages swap cached\n", cached);
 	show_buffers();
 }
 
-void set_pte_phys (unsigned long vaddr, unsigned long phys)
-{
-}
-
 
-/*
- * pagetable_init() sets up the page tables
- *
- * Note that gateway_init() places the Linux gateway page at page 0.
- * Since gateway pages cannot be dereferenced this has the desirable
- * side effect of trapping those pesky NULL-reference errors in the
- * kernel.
- */
-static void __init pagetable_init(void)
+static void __init map_pages(unsigned long start_vaddr, unsigned long start_paddr, unsigned long size, pgprot_t pgprot)
 {
 	pgd_t *pg_dir;
 	pmd_t *pmd;
 	pte_t *pg_table;
+	unsigned long end_paddr;
+	unsigned long start_pmd;
+	unsigned long start_pte;
 	unsigned long tmp1;
 	unsigned long tmp2;
 	unsigned long address;
 	unsigned long ro_start;
 	unsigned long ro_end;
 	unsigned long fv_addr;
-	extern  const int stext;
-	extern  int data_start;
-	extern  const unsigned long fault_vector_20;
+	unsigned long gw_addr;
+	extern const unsigned long fault_vector_20;
+	extern void * const linux_gateway_page;
 
-	ro_start = __pa((unsigned long)&stext);
+	ro_start = __pa((unsigned long)&_text);
 	ro_end   = __pa((unsigned long)&data_start);
 	fv_addr  = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
+	gw_addr  = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
 
-	printk("pagetable_init\n");
+	end_paddr = start_paddr + size;
 
-	/* Map whole memory from PAGE_OFFSET */
-	pg_dir = (pgd_t *)swapper_pg_dir + USER_PGD_PTRS;
+	pg_dir = pgd_offset_k(start_vaddr);
 
-	address = 0;
-	while (address < mem_max) {
-		/* XXX: BTLB should be done here */
+#if PTRS_PER_PMD == 1
+	start_pmd = 0;
+#else
+	start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
+#endif
+	start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 
+	address = start_paddr;
+	while (address < end_paddr) {
 #if PTRS_PER_PMD == 1
 		pmd = (pmd_t *)__pa(pg_dir);
 #else
@@ -209,7 +541,7 @@
 		 */
 
 		if (!pmd) {
-			pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+			pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
 			pmd = (pmd_t *) __pa(pmd);
 		}
 
@@ -219,8 +551,8 @@
 
 		/* now change pmd to kernel virtual addresses */
 
-		pmd = (pmd_t *) __va(pmd);
-		for (tmp1 = 0 ; tmp1 < PTRS_PER_PMD ; tmp1++,pmd++) {
+		pmd = (pmd_t *)__va(pmd) + start_pmd;
+		for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++,pmd++) {
 
 			/*
 			 * pg_table is physical at this point
@@ -229,7 +561,7 @@
 			pg_table = (pte_t *) (PAGE_MASK & pmd_val(*pmd));
 			if (!pg_table) {
 				pg_table = (pte_t *)
-					alloc_bootmem_low_pages(PAGE_SIZE);
+					alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
 				pg_table = (pte_t *) __pa(pg_table);
 			}
 
@@ -238,8 +570,8 @@
 
 			/* now change pg_table to kernel virtual addresses */
 
-			pg_table = (pte_t *) __va(pg_table);
-			for (tmp2=0; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
+			pg_table = (pte_t *) __va(pg_table) + start_pte;
+			for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
 				pte_t pte;
 
 #if !defined(CONFIG_KWDB) && !defined(CONFIG_STI_CONSOLE)
@@ -249,53 +581,84 @@
 ** The right thing to do seems like KWDB modify only the pte which
 ** has a break point on it...otherwise we might mask worse bugs.
 */
+				/*
+				 * Map the fault vector writable so we can
+				 * write the HPMC checksum.
+				 */
 				if (address >= ro_start && address < ro_end
-							&& address != fv_addr)
+							&& address != fv_addr
+							&& address != gw_addr)
 				    pte = __mk_pte(address, PAGE_KERNEL_RO);
 				else
 #endif
-				    pte = __mk_pte(address, PAGE_KERNEL);
+				    pte = __mk_pte(address, pgprot);
 
-				if (address >= mem_max)
+				if (address >= end_paddr)
 					pte_val(pte) = 0;
 
 				set_pte(pg_table, pte);
 
 				address += PAGE_SIZE;
 			}
+			start_pte = 0;
 
-			if (address >= mem_max)
+			if (address >= end_paddr)
 			    break;
 		}
+		start_pmd = 0;
 	}
+}
+
+/*
+ * pagetable_init() sets up the page tables
+ *
+ * Note that gateway_init() places the Linux gateway page at page 0.
+ * Since gateway pages cannot be dereferenced this has the desirable
+ * side effect of trapping those pesky NULL-reference errors in the
+ * kernel.
+ */
+static void __init pagetable_init(void)
+{
+	int range;
+
+	printk("pagetable_init\n");
+
+	/* Map each physical memory range to its kernel vaddr */
+
+	for (range = 0; range < npmem_ranges; range++) {
+		unsigned long start_paddr;
+		unsigned long end_paddr;
+		unsigned long size;
+
+		start_paddr = pmem_ranges[range].start_pfn << PAGE_SHIFT;
+		end_paddr = start_paddr + (pmem_ranges[range].pages << PAGE_SHIFT);
+		size = pmem_ranges[range].pages << PAGE_SHIFT;
+
+		map_pages((unsigned long)__va(start_paddr), start_paddr,
+			size, PAGE_KERNEL);
+	}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_end && initrd_end > mem_limit) {
+		printk("initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end);
+		map_pages(initrd_start, __pa(initrd_start),
+			initrd_end - initrd_start, PAGE_KERNEL);
+	}
+#endif
 
 	empty_zero_page = alloc_bootmem_pages(PAGE_SIZE);
 	memset(empty_zero_page, 0, PAGE_SIZE);
 }
 
-unsigned long gateway_pgd_offset;
-unsigned long gateway_pgd_entry;
-
 static void __init gateway_init(void)
 {
-	unsigned long hpux_gateway_page_addr;
 	unsigned long linux_gateway_page_addr;
-	pgd_t *pg_dir;
-	pmd_t *pmd_base;
-	pmd_t *pmd;
-	pte_t *pg_table_base;
-	pte_t *pg_table;
-	/* FIXME: These are 'const' in order to trick the compiler
-           into not treating them as DP-relative data. */
-	extern void * const hpux_gateway_page;
+	/* FIXME: This is 'const' in order to trick the compiler
+	   into not treating it as DP-relative data. */
 	extern void * const linux_gateway_page;
-	pte_t pte;
 
-	hpux_gateway_page_addr = HPUX_GATEWAY_ADDR & PAGE_MASK;
 	linux_gateway_page_addr = LINUX_GATEWAY_ADDR & PAGE_MASK;
 
-	gateway_pgd_offset = hpux_gateway_page_addr >> PGDIR_SHIFT;
-
 	/*
 	 * Setup Linux Gateway page.
 	 *
@@ -303,177 +666,356 @@
 	 * page 0), so it doesn't need to be aliased into user space.
 	 */
 
-	pg_dir = (pgd_t *)swapper_pg_dir;
-
-#if PTRS_PER_PMD == 1
-	pmd_base = (pmd_t *)pg_dir;
-	pmd = pmd_base +
-		((linux_gateway_page_addr) >> PGDIR_SHIFT);
-
-#else
-	pmd_base = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
-	pgd_val(*(pg_dir + (linux_gateway_page_addr >> PGDIR_SHIFT))) =
-		_PAGE_TABLE | __pa(pmd_base);
+	map_pages(linux_gateway_page_addr, __pa(&linux_gateway_page),
+		PAGE_SIZE, PAGE_GATEWAY);
+}
 
-	pmd = pmd_base +
-		((linux_gateway_page_addr & (PMD_MASK) & (PGDIR_SIZE - 1)) >>
-								PMD_SHIFT);
-#endif
+void
+map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm)
+{
+	pgd_t *pg_dir;
+	pmd_t *pmd;
+	pte_t *pg_table;
+	unsigned long start_pmd;
+	unsigned long start_pte;
+	unsigned long address;
+	unsigned long hpux_gw_page_addr;
+	/* FIXME: This is 'const' in order to trick the compiler
+	   into not treating it as DP-relative data. */
+	extern void * const hpux_gateway_page;
 
-	pg_table_base = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
+	hpux_gw_page_addr = HPUX_GATEWAY_ADDR & PAGE_MASK;
 
-	pmd_val(*pmd) = _PAGE_TABLE | __pa(pg_table_base);
+	/*
+	 * Setup HP-UX Gateway page.
+	 *
+	 * The HP-UX gateway page resides in the user address space,
+	 * so it needs to be aliased into each process.
+	 */
 
-	pte = __mk_pte(__pa(&linux_gateway_page), PAGE_GATEWAY);
+	pg_dir = pgd_offset(mm,hpux_gw_page_addr);
 
-	pg_table = pg_table_base +
-		((linux_gateway_page_addr & (PAGE_MASK) & (PMD_SIZE - 1)) >>
-								PAGE_SHIFT);
+#if PTRS_PER_PMD == 1
+	start_pmd = 0;
+#else
+	start_pmd = ((hpux_gw_page_addr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
+#endif
+	start_pte = ((hpux_gw_page_addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 
-	set_pte(pg_table,pte);
+	address = __pa(&hpux_gateway_page);
+#if PTRS_PER_PMD == 1
+	pmd = (pmd_t *)__pa(pg_dir);
+#else
+	pmd = (pmd_t *) (PAGE_MASK & pgd_val(*pg_dir));
 
 	/*
-	 * Setup HP-UX gateway page.
-	 * This page will be aliased into each user address space.
+	 * pmd is physical at this point
 	 */
 
-	pg_table_base = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
-
-	pte = __mk_pte(__pa(&hpux_gateway_page), PAGE_GATEWAY);
-	pg_table = pg_table_base +
-		((hpux_gateway_page_addr & (PAGE_MASK) & (PMD_SIZE - 1)) >>
-								PAGE_SHIFT);
-
-	set_pte(pg_table,pte);
-
+	if (!pmd) {
+		pmd = (pmd_t *) get_zeroed_page(GFP_KERNEL);
+		pmd = (pmd_t *) __pa(pmd);
+	}
 
-#if PTRS_PER_PMD == 1
-	pmd_base = (pmd_t *)pg_table_base;
-#else
-	pmd_base = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
-	pmd = pmd_base +
-		((hpux_gateway_page_addr & (PMD_MASK) & (PGDIR_SIZE - 1)) >>
-								PMD_SHIFT);
-	pmd_val(*pmd) = _PAGE_TABLE | __pa(pg_table_base);
+	pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pmd;
 #endif
+	/* now change pmd to kernel virtual addresses */
 
-	gateway_pgd_entry = _PAGE_TABLE | __pa(pmd_base);
+	pmd = (pmd_t *)__va(pmd) + start_pmd;
 
 	/*
-	 * We will be aliasing the HP-UX gateway page into all HP-UX
-	 * user spaces at the same address (not counting the space register
-	 * value) that will be equivalently mapped as long as space register
-	 * hashing is disabled. It will be a problem if anyone touches
-	 * the gateway pages at its "kernel" address, since that is
-	 * NOT equivalently mapped. We'll flush the caches at this
-	 * point, just in case some code has touched those addresses
-	 * previous to this, but all bets are off if they get touched
-	 * after this point.
+	 * pg_table is physical at this point
 	 */
 
-	flush_all_caches();
+	pg_table = (pte_t *) (PAGE_MASK & pmd_val(*pmd));
+	if (!pg_table)
+		pg_table = (pte_t *) __pa(get_zeroed_page(GFP_KERNEL));
 
-	return;
+	pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) pg_table;
+
+	/* now change pg_table to kernel virtual addresses */
+
+	pg_table = (pte_t *) __va(pg_table) + start_pte;
+	set_pte(pg_table, __mk_pte(address, PAGE_GATEWAY));
 }
 
+extern void flush_tlb_all_local(void);
+
 void __init paging_init(void)
 {
+	int i;
+
+	setup_bootmem();
 	pagetable_init();
 	gateway_init();
+	flush_cache_all_local(); /* start with known state */
+	flush_tlb_all_local();
 
-	{
-		unsigned long zones_size[MAX_NR_ZONES] = { max_pfn/2, max_pfn/2, };
+	for (i = 0; i < npmem_ranges; i++) {
+		unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0, };
 
-		free_area_init(zones_size);
+		zones_size[ZONE_DMA] = pmem_ranges[i].pages;
+		free_area_init_node(i,NODE_DATA(i),NULL,zones_size,
+				(pmem_ranges[i].start_pfn << PAGE_SHIFT),0);
 	}
+
+#ifdef CONFIG_DISCONTIGMEM
+	/*
+	 * Initialize support for virt_to_page() macro.
+	 *
+	 * Note that MAX_ADDRESS is the largest virtual address that
+	 * we can map. However, since we map all physical memory into
+	 * the kernel address space, it also has an effect on the maximum
+	 * physical address we can map (MAX_ADDRESS - PAGE_OFFSET).
+	 */
+
+	maxchunkmap = MAX_ADDRESS >> CHUNKSHIFT;
+	chunkmap = (unsigned char *)alloc_bootmem(maxchunkmap);
+
+	for (i = 0; i < maxchunkmap; i++)
+	    chunkmap[i] = BADCHUNK;
+
+	for (i = 0; i < npmem_ranges; i++) {
+
+		ADJ_NODE_MEM_MAP(i) = NODE_MEM_MAP(i) - pmem_ranges[i].start_pfn;
+		{
+			unsigned long chunk_paddr;
+			unsigned long end_paddr;
+			int chunknum;
+
+			chunk_paddr = (pmem_ranges[i].start_pfn << PAGE_SHIFT);
+			end_paddr = chunk_paddr + (pmem_ranges[i].pages << PAGE_SHIFT);
+			chunk_paddr &= CHUNKMASK;
+
+			chunknum = (int)CHUNKNUM(chunk_paddr);
+			while (chunk_paddr < end_paddr) {
+				if (chunknum >= maxchunkmap)
+					goto badchunkmap1;
+				if (chunkmap[chunknum] != BADCHUNK)
+					goto badchunkmap2;
+				chunkmap[chunknum] = (unsigned char)i;
+				chunk_paddr += CHUNKSZ;
+				chunknum++;
+			}
+		}
+	}
+
+	return;
+
+badchunkmap1:
+	panic("paging_init: Physical address exceeds maximum address space!\n");
+badchunkmap2:
+	panic("paging_init: Collision in chunk map array. CHUNKSZ needs to be smaller\n");
+#endif
 }
 
-#define NR_SPACE_IDS	8192
+#ifdef CONFIG_PA20
 
-static unsigned long space_id[NR_SPACE_IDS / (8 * sizeof(long))];
-static unsigned long space_id_index;
-static unsigned long free_space_ids = NR_SPACE_IDS;
+/*
+ * Currently, all PA20 chips have 18 bit protection id's, which is the
+ * limiting factor (space ids are 32 bits).
+ */
+
+#define NR_SPACE_IDS 262144
+
+#else
 
 /*
- * XXX: We should probably unfold the set_bit / test_bit / clear_bit
- * locking out of these two functions and have a single spinlock on the
- * space_id data structures.
- *
- * Don't bother. This is all going to be significantly changed in the
- * very near future.
+ * Currently we have a one-to-one relationship between space id's and
+ * protection id's. Older parisc chips (PCXS, PCXT, PCXL, PCXL2) only
+ * support 15 bit protection id's, so that is the limiting factor.
+ * PCXT' has 18 bit protection id's, but only 16 bit spaceids, so it's
+ * probably not worth the effort for a special case here.
  */
 
-#define SPACEID_SHIFT (PAGE_SHIFT + (PT_NLEVELS)*(PAGE_SHIFT - PT_NLEVELS) - 32)
+#define NR_SPACE_IDS 32768
+
+#endif  /* !CONFIG_PA20 */
+
+#define RECYCLE_THRESHOLD (NR_SPACE_IDS / 2)
+#define SID_ARRAY_SIZE  (NR_SPACE_IDS / (8 * sizeof(long)))
+
+static unsigned long space_id[SID_ARRAY_SIZE] = { 1 }; /* disallow space 0 */
+static unsigned long dirty_space_id[SID_ARRAY_SIZE];
+static unsigned long space_id_index;
+static unsigned long free_space_ids = NR_SPACE_IDS - 1;
+static unsigned long dirty_space_ids = 0;
+
+static spinlock_t sid_lock = SPIN_LOCK_UNLOCKED;
 
 unsigned long alloc_sid(void)
 {
 	unsigned long index;
 
-	if (free_space_ids == 0)
-		BUG();
+	spin_lock(&sid_lock);
 
-	free_space_ids--;
+	if (free_space_ids == 0) {
+		if (dirty_space_ids != 0) {
+			spin_unlock(&sid_lock);
+			flush_tlb_all(); /* flush_tlb_all() calls recycle_sids() */
+			spin_lock(&sid_lock);
+		}
+		if (free_space_ids == 0)
+			BUG();
+	}
 
-	do {
-		index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index);
-	} while(test_and_set_bit(index, space_id));
+	free_space_ids--;
 
+	index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index);
+	space_id[index >> SHIFT_PER_LONG] |= (1L << (index & (BITS_PER_LONG - 1)));
 	space_id_index = index;
 
+	spin_unlock(&sid_lock);
+
 	return index << SPACEID_SHIFT;
 }
 
 void free_sid(unsigned long spaceid)
 {
 	unsigned long index = spaceid >> SPACEID_SHIFT;
-	if (index < 0)
-		BUG();
+	unsigned long *dirty_space_offset;
+
+	dirty_space_offset = dirty_space_id + (index >> SHIFT_PER_LONG);
+	index &= (BITS_PER_LONG - 1);
+
+	spin_lock(&sid_lock);
+
+	if (*dirty_space_offset & (1L << index))
+	    BUG(); /* attempt to free space id twice */
+
+	*dirty_space_offset |= (1L << index);
+	dirty_space_ids++;
+
+	spin_unlock(&sid_lock);
+}
+
+
+#ifdef CONFIG_SMP
+static void get_dirty_sids(unsigned long *ndirtyptr,unsigned long *dirty_array)
+{
+	int i;
+
+	/* NOTE: sid_lock must be held upon entry */
+
+	*ndirtyptr = dirty_space_ids;
+	if (dirty_space_ids != 0) {
+	    for (i = 0; i < SID_ARRAY_SIZE; i++) {
+		dirty_array[i] = dirty_space_id[i];
+		dirty_space_id[i] = 0;
+	    }
+	    dirty_space_ids = 0;
+	}
 
-	clear_bit(index, space_id);
+	return;
+}
+
+static void recycle_sids(unsigned long ndirty,unsigned long *dirty_array)
+{
+	int i;
+
+	/* NOTE: sid_lock must be held upon entry */
+
+	if (ndirty != 0) {
+		for (i = 0; i < SID_ARRAY_SIZE; i++) {
+			space_id[i] ^= dirty_array[i];
+		}
+
+		free_space_ids += ndirty;
+		space_id_index = 0;
+	}
+}
+
+#else /* CONFIG_SMP */
+
+static void recycle_sids(void)
+{
+	int i;
+
+	/* NOTE: sid_lock must be held upon entry */
+
+	if (dirty_space_ids != 0) {
+		for (i = 0; i < SID_ARRAY_SIZE; i++) {
+			space_id[i] ^= dirty_space_id[i];
+			dirty_space_id[i] = 0;
+		}
+
+		free_space_ids += dirty_space_ids;
+		dirty_space_ids = 0;
+		space_id_index = 0;
+	}
+}
+#endif
+
+/*
+ * flush_tlb_all() calls recycle_sids(), since whenever the entire tlb is
+ * purged, we can safely reuse the space ids that were released but
+ * not flushed from the tlb.
+ */
+
+#ifdef CONFIG_SMP
 
-	if (space_id_index > index) {
-		space_id_index = index;
+static unsigned long recycle_ndirty;
+static unsigned long recycle_dirty_array[SID_ARRAY_SIZE];
+static unsigned int recycle_inuse = 0;
+
+void flush_tlb_all(void)
+{
+	int do_recycle;
+
+	do_recycle = 0;
+	spin_lock(&sid_lock);
+	if (dirty_space_ids > RECYCLE_THRESHOLD) {
+	    if (recycle_inuse) {
+		BUG();  /* FIXME: Use a semaphore/wait queue here */
+	    }
+	    get_dirty_sids(&recycle_ndirty,recycle_dirty_array);
+	    recycle_inuse++;
+	    do_recycle++;
+	}
+	spin_unlock(&sid_lock);
+	smp_call_function((void (*)(void *))flush_tlb_all_local, NULL, 1, 1);
+	flush_tlb_all_local();
+	if (do_recycle) {
+	    spin_lock(&sid_lock);
+	    recycle_sids(recycle_ndirty,recycle_dirty_array);
+	    recycle_inuse = 0;
+	    spin_unlock(&sid_lock);
 	}
-	free_space_ids++;
 }
+#else
+void flush_tlb_all(void)
+{
+	spin_lock(&sid_lock);
+	flush_tlb_all_local();
+	recycle_sids();
+	spin_unlock(&sid_lock);
+}
+#endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
 #if 0
+	if (start < end)
+		printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 	for (; start < end; start += PAGE_SIZE) {
-		ClearPageReserved(mem_map + MAP_NR(start));
-		set_page_count(mem_map+MAP_NR(start), 1);
+		ClearPageReserved(virt_to_page(start));
+		set_page_count(virt_to_page(start), 1);
 		free_page(start);
-		totalram_pages++;
+		num_physpages++;
 	}
-	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 #endif
 }
 #endif
 
 void si_meminfo(struct sysinfo *val)
 {
-	int i;
-
-	i = max_mapnr;
-	val->totalram = totalram_pages;
+	val->totalram = num_physpages;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages();
 	val->bufferram = atomic_read(&buffermem_pages);
-#if 0
-	while (i-- > 0)  {
-		if (PageReserved(mem_map+i))
-			continue;
-		val->totalram++;
-		if (!atomic_read(&mem_map[i].count))
-			continue;
-		val->sharedram += atomic_read(&mem_map[i].count) - 1;
-	}
-	val->totalram <<= PAGE_SHIFT;
-	val->sharedram <<= PAGE_SHIFT;
-#endif
 	val->totalhigh = 0;
 	val->freehigh = 0;
+	val->mem_unit = PAGE_SIZE;
 	return;
 }
diff -urN linux-2.4.20-pre1/arch/parisc/mm/ioremap.c linux-2.4.20-pre2/arch/parisc/mm/ioremap.c
--- linux-2.4.20-pre1/arch/parisc/mm/ioremap.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/mm/ioremap.c	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,177 @@
+/*
+ * arch/parisc/mm/ioremap.c
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ * This is needed for high PCI addresses that aren't mapped in the
+ * 640k-1MB IO memory area on PC's
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ * (C) Copyright 2001 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
+	do {
+		if (!pte_none(*pte)) {
+			printk(KERN_ERR "remap_area_pte: page already exists\n");
+			BUG();
+		}
+		set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | _PAGE_RW | 
+					_PAGE_DIRTY | _PAGE_ACCESSED | flags)));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	if (address >= end)
+		BUG();
+	do {
+		pte_t * pte = pte_alloc(NULL, pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address && (address < end));
+	return 0;
+}
+
+#if (USE_HPPA_IOREMAP)
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+				 unsigned long size, unsigned long flags)
+{
+	int error;
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	if (address >= end)
+		BUG();
+	spin_lock(&init_mm.page_table_lock);
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc(dir, address);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		if (remap_area_pmd(pmd, address, end - address,
+					 phys_addr + address, flags))
+			break;
+		error = 0;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
+	flush_tlb_all();
+	return error;
+}
+#endif /* USE_HPPA_IOREMAP */
+
+/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+#if !(USE_HPPA_IOREMAP)
+
+	unsigned long end = phys_addr + size - 1;
+	/* Support EISA addresses */
+	if ((phys_addr >= 0x00080000 && end < 0x000fffff)
+			|| (phys_addr >= 0x00500000 && end < 0x03bfffff)) {
+		phys_addr |= 0xfc000000;
+	}
+
+	return (void *)phys_addr;
+
+#else
+	void * addr;
+	struct vm_struct * area;
+	unsigned long offset, last_addr;
+
+	/* Don't allow wraparound or zero size */
+	last_addr = phys_addr + size - 1;
+	if (!size || last_addr < phys_addr)
+		return NULL;
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using..
+	 */
+	if (phys_addr < virt_to_phys(high_memory)) {
+		char *t_addr, *t_end;
+		struct page *page;
+
+		t_addr = __va(phys_addr);
+		t_end = t_addr + (size - 1);
+	   
+		for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
+			if(!PageReserved(page))
+				return NULL;
+	}
+
+	/*
+	 * Mappings have to be page-aligned
+	 */
+	offset = phys_addr & ~PAGE_MASK;
+	phys_addr &= PAGE_MASK;
+	size = PAGE_ALIGN(last_addr) - phys_addr;
+
+	/*
+	 * Ok, go for it..
+	 */
+	area = get_vm_area(size, VM_IOREMAP);
+	if (!area)
+		return NULL;
+	addr = area->addr;
+	if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+		vfree(addr);
+		return NULL;
+	}
+	return (void *) (offset + (char *)addr);
+#endif
+}
+
+void iounmap(void *addr)
+{
+#if !(USE_HPPA_IOREMAP)
+	return;
+#else
+	if (addr > high_memory)
+		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+#endif
+}
diff -urN linux-2.4.20-pre1/arch/parisc/mm/kmap.c linux-2.4.20-pre2/arch/parisc/mm/kmap.c
--- linux-2.4.20-pre1/arch/parisc/mm/kmap.c	Fri Feb  9 11:29:44 2001
+++ linux-2.4.20-pre2/arch/parisc/mm/kmap.c	Wed Dec 31 16:00:00 1969
@@ -1,143 +0,0 @@
-/*
-** Stolen mostly from arch/parisc/kernel/pci-dma.c
-*/
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-
-#include <asm/io.h>
-#include <asm/page.h>		/* get_order */
-
-#undef flush_cache_all
-#define flush_cache_all flush_all_caches
-
-typedef void (*pte_iterator_t) (pte_t * pte, unsigned long arg);
-
-#if 0
-/* XXX This routine could be used with iterate_page() to replace
- * unmap_uncached_page() and save a little code space but I didn't
- * do that since I'm not certain whether this is the right path. -PB
- */
-static void unmap_cached_pte(pte_t * pte, unsigned long arg)
-{
-	pte_t page = *pte;
-	pte_clear(pte);
-	if (!pte_none(page)) {
-		if (pte_present(page)) {
-			unsigned long map_nr = pte_pagenr(page);
-			if (map_nr < max_mapnr)
-				__free_page(mem_map + map_nr);
-		} else {
-			printk(KERN_CRIT
-			       "Whee.. Swapped out page in kernel page table\n");
-		}
-	}
-}
-#endif
-
-/* These two routines should probably check a few things... */
-static void set_uncached(pte_t * pte, unsigned long arg)
-{
-	pte_val(*pte) |= _PAGE_NO_CACHE;
-}
-
-static void set_cached(pte_t * pte, unsigned long arg)
-{
-	pte_val(*pte) &= ~_PAGE_NO_CACHE;
-}
-
-static inline void iterate_pte(pmd_t * pmd, unsigned long address,
-			       unsigned long size, pte_iterator_t op,
-			       unsigned long arg)
-{
-	pte_t *pte;
-	unsigned long end;
-
-	if (pmd_none(*pmd))
-		return;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return;
-	}
-	pte = pte_offset(pmd, address);
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	do {
-		op(pte, arg);
-		address += PAGE_SIZE;
-		pte++;
-	} while (address < end);
-}
-
-static inline void iterate_pmd(pgd_t * dir, unsigned long address,
-			       unsigned long size, pte_iterator_t op,
-			       unsigned long arg)
-{
-	pmd_t *pmd;
-	unsigned long end;
-
-	if (pgd_none(*dir))
-		return;
-	if (pgd_bad(*dir)) {
-		pgd_ERROR(*dir);
-		pgd_clear(dir);
-		return;
-	}
-	pmd = pmd_offset(dir, address);
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	do {
-		iterate_pte(pmd, address, end - address, op, arg);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-}
-
-static void iterate_pages(unsigned long address, unsigned long size,
-			  pte_iterator_t op, unsigned long arg)
-{
-	pgd_t *dir;
-	unsigned long end = address + size;
-
-	dir = pgd_offset_k(address);
-	flush_cache_all();
-	do {
-		iterate_pmd(dir, address, end - address, op, arg);
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	} while (address && (address < end));
-	flush_tlb_all();
-}
-
-void
-kernel_set_cachemode(unsigned long vaddr, unsigned long size, int what)
-{
-	switch (what) {
-	case IOMAP_FULL_CACHING:
-		iterate_pages(vaddr, size, set_cached, 0);
-		flush_tlb_range(&init_mm, vaddr, size);
-		break;
-	case IOMAP_NOCACHE_SER:
-		iterate_pages(vaddr, size, set_uncached, 0);
-		flush_tlb_range(&init_mm, vaddr, size);
-		break;
-	default:
-		printk(KERN_CRIT
-		       "kernel_set_cachemode mode %d not understood\n",
-		       what);
-		break;
-	}
-}
diff -urN linux-2.4.20-pre1/arch/parisc/mm/pa11.c linux-2.4.20-pre2/arch/parisc/mm/pa11.c
--- linux-2.4.20-pre1/arch/parisc/mm/pa11.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.20-pre2/arch/parisc/mm/pa11.c	Wed Dec 31 16:00:00 1969
@@ -1,171 +0,0 @@
-/* $Id: pa11.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $
- *
- * pa11.c: PA 1.1 specific mmu/cache code.
- *
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/sgialib.h>
-#include <asm/mmu_context.h>
-
-extern unsigned long mips_tlb_entries;
-
-/* page functions */
-void pa11_clear_page(unsigned long page)
-{
-}
-
-static void pa11_copy_page(unsigned long to, unsigned long from)
-{
-}
-
-/* Cache operations. */
-static inline void pa11_flush_cache_all(void) { }
-static void pa11_flush_cache_mm(struct mm_struct *mm) { }
-static void pa11_flush_cache_range(struct mm_struct *mm,
-				    unsigned long start,
-				    unsigned long end)
-{
-}
-
-static void pa11_flush_cache_page(struct vm_area_struct *vma,
-				   unsigned long page)
-{
-}
-
-static void pa11_flush_page_to_ram(unsigned long page)
-{
-}
-
-static void pa11_flush_cache_sigtramp(unsigned long page)
-{
-}
-
-/* TLB operations. */
-static inline void pa11_flush_tlb_all(void)
-{
-	unsigned long flags;
-	int entry;
-
-	save_and_cli(flags);
-/* Here we will need to flush all the TLBs */
-	restore_flags(flags);
-}
-
-static void pa11_flush_tlb_mm(struct mm_struct *mm)
-{
-/* This is what the MIPS does..  Is it the right thing for PA-RISC? */
-	if(mm == current->mm)
-		pa11_flush_tlb_all();
-}
-
-static void pa11_flush_tlb_range(struct mm_struct *mm, unsigned long start,
-				  unsigned long end)
-{
-	if(mm == current->mm)
-		pa11_flush_tlb_all();
-}
-
-static void pa11_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-	if(vma->vm_mm == current->mm)
-		pa11_flush_tlb_all();
-}
-
-static void pa11_load_pgd(unsigned long pg_dir)
-{
-	unsigned long flags;
-    /* We need to do the right thing here */
-}
-
-/*
- * Initialize new page directory with pointers to invalid ptes
- */
-static void pa11_pgd_init(unsigned long page)
-{
-	unsigned long dummy1, dummy2;
-
-}
-
-static void pa11_update_mmu_cache(struct vm_area_struct * vma,
-				   unsigned long address, pte_t pte)
-{
-	pa11_flush_tlb_page(vma, address);
-}
-
-static void pa11_show_regs(struct pt_regs * regs)
-{
-	/*
-	 * Saved main processor registers
-	 */
-	printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2],
-	       (unsigned long) regs->regs[3], (unsigned long) regs->regs[4],
-	       (unsigned long) regs->regs[5], (unsigned long) regs->regs[6],
-	       (unsigned long) regs->regs[7]);
-	printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[8], (unsigned long) regs->regs[9],
-	       (unsigned long) regs->regs[10], (unsigned long) regs->regs[11],
-               (unsigned long) regs->regs[12], (unsigned long) regs->regs[13],
-	       (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]);
-	printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[16], (unsigned long) regs->regs[17],
-	       (unsigned long) regs->regs[18], (unsigned long) regs->regs[19],
-               (unsigned long) regs->regs[20], (unsigned long) regs->regs[21],
-	       (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]);
-	printk("$24: %08lx %08lx                   %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[24], (unsigned long) regs->regs[25],
-	       (unsigned long) regs->regs[28], (unsigned long) regs->regs[29],
-               (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]);
-
-	/*
-	 * Saved cp0 registers
-	 */
-	printk("epc  : %08lx    %s\nStatus: %08x\nCause : %08x\n",
-	       (unsigned long) regs->cp0_epc, print_tainted(),
-	       (unsigned int) regs->cp0_status,
-	       (unsigned int) regs->cp0_cause);
-}
-
-static int pa11_user_mode(struct pt_regs *regs)
-{
-       /* Return user mode stuff?? */
-}
-
-__initfunc(void ld_mmu_pa11(void))
-{
-
-    /* Taken directly from the MIPS arch..  Lots of bad things here */
-	clear_page = pa11_clear_page;
-	copy_page = pa11_copy_page;
-
-	flush_cache_all = pa11_flush_cache_all;
-	flush_cache_mm = pa11_flush_cache_mm;
-	flush_cache_range = pa11_flush_cache_range;
-	flush_cache_page = pa11_flush_cache_page;
-	flush_cache_sigtramp = pa11_flush_cache_sigtramp;
-	flush_page_to_ram = pa11_flush_page_to_ram;
-
-	flush_tlb_all = pa11_flush_tlb_all;
-	flush_tlb_mm = pa11_flush_tlb_mm;
-	flush_tlb_range = pa11_flush_tlb_range;
-	flush_tlb_page = pa11_flush_tlb_page;
-	pa11_asid_setup();
-
-	load_pgd = pa11_load_pgd;
-	pgd_init = pa11_pgd_init;
-	update_mmu_cache = pa11_update_mmu_cache;
-
-	show_regs = pa11_show_regs;
-    
-        add_wired_entry = pa11_add_wired_entry;
-
-	user_mode = pa11_user_mode;
-	flush_tlb_all();
-}
diff -urN linux-2.4.20-pre1/arch/parisc/mm/pa20.c linux-2.4.20-pre2/arch/parisc/mm/pa20.c
--- linux-2.4.20-pre1/arch/parisc/mm/pa20.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.20-pre2/arch/parisc/mm/pa20.c	Wed Dec 31 16:00:00 1969
@@ -1,171 +0,0 @@
-/* $Id: pa20.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $
- *
- * pa20.c: PA 2.0 specific mmu/cache code.
- *
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/sgialib.h>
-#include <asm/mmu_context.h>
-
-extern unsigned long mips_tlb_entries;
-
-/* page functions */
-void pa20_clear_page(unsigned long page)
-{
-}
-
-static void pa20_copy_page(unsigned long to, unsigned long from)
-{
-}
-
-/* Cache operations. */
-static inline void pa20_flush_cache_all(void) { }
-static void pa20_flush_cache_mm(struct mm_struct *mm) { }
-static void pa20_flush_cache_range(struct mm_struct *mm,
-				    unsigned long start,
-				    unsigned long end)
-{
-}
-
-static void pa20_flush_cache_page(struct vm_area_struct *vma,
-				   unsigned long page)
-{
-}
-
-static void pa20_flush_page_to_ram(unsigned long page)
-{
-}
-
-static void pa20_flush_cache_sigtramp(unsigned long page)
-{
-}
-
-/* TLB operations. */
-static inline void pa20_flush_tlb_all(void)
-{
-	unsigned long flags;
-	int entry;
-
-	save_and_cli(flags);
-/* Here we will need to flush all the TLBs */
-	restore_flags(flags);
-}
-
-static void pa20_flush_tlb_mm(struct mm_struct *mm)
-{
-/* This is what the MIPS does..  Is it the right thing for PA-RISC? */
-	if(mm == current->mm)
-		pa20_flush_tlb_all();
-}
-
-static void pa20_flush_tlb_range(struct mm_struct *mm, unsigned long start,
-				  unsigned long end)
-{
-	if(mm == current->mm)
-		pa20_flush_tlb_all();
-}
-
-static void pa20_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-	if(vma->vm_mm == current->mm)
-		pa20_flush_tlb_all();
-}
-
-static void pa20_load_pgd(unsigned long pg_dir)
-{
-	unsigned long flags;
-    /* We need to do the right thing here */
-}
-
-/*
- * Initialize new page directory with pointers to invalid ptes
- */
-static void pa20_pgd_init(unsigned long page)
-{
-	unsigned long dummy1, dummy2;
-
-}
-
-static void pa20_update_mmu_cache(struct vm_area_struct * vma,
-				   unsigned long address, pte_t pte)
-{
-	pa20_flush_tlb_page(vma, address);
-}
-
-static void pa20_show_regs(struct pt_regs * regs)
-{
-	/*
-	 * Saved main processor registers
-	 */
-	printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2],
-	       (unsigned long) regs->regs[3], (unsigned long) regs->regs[4],
-	       (unsigned long) regs->regs[5], (unsigned long) regs->regs[6],
-	       (unsigned long) regs->regs[7]);
-	printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[8], (unsigned long) regs->regs[9],
-	       (unsigned long) regs->regs[10], (unsigned long) regs->regs[11],
-               (unsigned long) regs->regs[12], (unsigned long) regs->regs[13],
-	       (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]);
-	printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[16], (unsigned long) regs->regs[17],
-	       (unsigned long) regs->regs[18], (unsigned long) regs->regs[19],
-               (unsigned long) regs->regs[20], (unsigned long) regs->regs[21],
-	       (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]);
-	printk("$24: %08lx %08lx                   %08lx %08lx %08lx %08lx\n",
-	       (unsigned long) regs->regs[24], (unsigned long) regs->regs[25],
-	       (unsigned long) regs->regs[28], (unsigned long) regs->regs[29],
-               (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]);
-
-	/*
-	 * Saved cp0 registers
-	 */
-	printk("epc  : %08lx    %s\nStatus: %08x\nCause : %08x\n",
-	       (unsigned long) regs->cp0_epc, print_tainted(),
-	       (unsigned int) regs->cp0_status,
-	       (unsigned int) regs->cp0_cause);
-}
-
-static int pa20_user_mode(struct pt_regs *regs)
-{
-       /* Return user mode stuff?? */
-}
-
-__initfunc(void ld_mmu_pa20(void))
-{
-
-    /* Taken directly from the MIPS arch..  Lots of bad things here */
-	clear_page = pa20_clear_page;
-	copy_page = pa20_copy_page;
-
-	flush_cache_all = pa20_flush_cache_all;
-	flush_cache_mm = pa20_flush_cache_mm;
-	flush_cache_range = pa20_flush_cache_range;
-	flush_cache_page = pa20_flush_cache_page;
-	flush_cache_sigtramp = pa20_flush_cache_sigtramp;
-	flush_page_to_ram = pa20_flush_page_to_ram;
-
-	flush_tlb_all = pa20_flush_tlb_all;
-	flush_tlb_mm = pa20_flush_tlb_mm;
-	flush_tlb_range = pa20_flush_tlb_range;
-	flush_tlb_page = pa20_flush_tlb_page;
-	pa20_asid_setup();
-
-	load_pgd = pa20_load_pgd;
-	pgd_init = pa20_pgd_init;
-	update_mmu_cache = pa20_update_mmu_cache;
-
-	show_regs = pa20_show_regs;
-    
-        add_wired_entry = pa20_add_wired_entry;
-
-	user_mode = pa20_user_mode;
-	flush_tlb_all();
-}
diff -urN linux-2.4.20-pre1/arch/parisc/tools/Makefile linux-2.4.20-pre2/arch/parisc/tools/Makefile
--- linux-2.4.20-pre1/arch/parisc/tools/Makefile	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/tools/Makefile	Mon Aug 12 16:34:14 2002
@@ -22,7 +22,4 @@
 
 offset.s: offset.c
 
-clean:
-	rm -f offset.[hs] $(TARGET).new
-
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/arch/parisc/tools/offset.c linux-2.4.20-pre2/arch/parisc/tools/offset.c
--- linux-2.4.20-pre1/arch/parisc/tools/offset.c	Tue Dec  5 12:29:39 2000
+++ linux-2.4.20-pre2/arch/parisc/tools/offset.c	Mon Aug 12 16:34:14 2002
@@ -13,6 +13,13 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/hardirq.h>
+#include <asm/pdc.h>
+
+#ifdef __LP64__
+#define FRAME_SIZE	128
+#else
+#define FRAME_SIZE	64
+#endif
 
 #define text(t) __asm__("\n@@@" t)
 #define _offset(type, member) (&(((type *)NULL)->member))
@@ -21,7 +28,7 @@
 	__asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member)))
 #define size(string, size) \
 	__asm__("\n@@@" string "%0" : : "i" (sizeof(size)))
-#define align(x,y) (((x)+(2*(y))-1)-(((x)+(y)-1)%(y)))
+#define align(x,y) (((x)+FRAME_SIZE+(y)-1)-(((x)+(y)-1)%(y)))
 #define size_align(string, size, algn) \
 	__asm__("\n@@@" string "%0" : : "i" \
 		align(sizeof(size),algn))
@@ -32,6 +39,15 @@
 text("#ifndef _PARISC_OFFSET_H");
 text("#define _PARISC_OFFSET_H");
 linefeed;
+#ifdef __LP64__
+text("#ifndef __LP64__");
+text("#error offset.h was generated for 64-bit build; did you do 'make dep'?");
+#else
+text("#ifdef __LP64__");
+text("#error offset.h was generated for 32-bit build; did you do 'make dep'?");
+#endif
+text("#endif");
+linefeed;
 
 void output_task_ptreg_defines(void)
 {
@@ -113,23 +129,14 @@
 	offset("#define TASK_PT_IASQ1   ", struct task_struct, thread.regs.iasq[1]);
 	offset("#define TASK_PT_IAOQ0   ", struct task_struct, thread.regs.iaoq[0]);
 	offset("#define TASK_PT_IAOQ1   ", struct task_struct, thread.regs.iaoq[1]);
-	offset("#define TASK_PT_CR24    ", struct task_struct, thread.regs.cr24);
-	offset("#define TASK_PT_CR25    ", struct task_struct, thread.regs.cr25);
-	offset("#define TASK_PT_CR26    ", struct task_struct, thread.regs.cr26);
 	offset("#define TASK_PT_CR27    ", struct task_struct, thread.regs.cr27);
-	offset("#define TASK_PT_CR30    ", struct task_struct, thread.regs.cr30);
 	offset("#define TASK_PT_ORIG_R28 ", struct task_struct, thread.regs.orig_r28);
 	offset("#define TASK_PT_KSP     ", struct task_struct, thread.regs.ksp);
 	offset("#define TASK_PT_KPC     ", struct task_struct, thread.regs.kpc);
 	offset("#define TASK_PT_SAR     ", struct task_struct, thread.regs.sar);
-	offset("#define TASK_PT_CR11    ", struct task_struct, thread.regs.sar);
 	offset("#define TASK_PT_IIR     ", struct task_struct, thread.regs.iir);
 	offset("#define TASK_PT_ISR     ", struct task_struct, thread.regs.isr);
 	offset("#define TASK_PT_IOR     ", struct task_struct, thread.regs.ior);
-	offset("#define TASK_PT_CR_PID0 ", struct task_struct, thread.regs.cr_pid[0]);
-	offset("#define TASK_PT_CR_PID1 ", struct task_struct, thread.regs.cr_pid[1]);
-	offset("#define TASK_PT_CR_PID2 ", struct task_struct, thread.regs.cr_pid[2]);
-	offset("#define TASK_PT_CR_PID3 ", struct task_struct, thread.regs.cr_pid[3]);
 	size("#define TASK_SZ      ", struct task_struct);
 	size_align("#define TASK_SZ_ALGN  ", struct task_struct, 64);
 	linefeed;
@@ -214,23 +221,14 @@
 	offset("#define PT_IASQ1   ", struct pt_regs, iasq[1]);
 	offset("#define PT_IAOQ0   ", struct pt_regs, iaoq[0]);
 	offset("#define PT_IAOQ1   ", struct pt_regs, iaoq[1]);
-	offset("#define PT_CR24    ", struct pt_regs, cr24);
-	offset("#define PT_CR25    ", struct pt_regs, cr25);
-	offset("#define PT_CR26    ", struct pt_regs, cr26);
 	offset("#define PT_CR27    ", struct pt_regs, cr27);
-	offset("#define PT_CR30    ", struct pt_regs, cr30);
 	offset("#define PT_ORIG_R28 ", struct pt_regs, orig_r28);
 	offset("#define PT_KSP     ", struct pt_regs, ksp);
 	offset("#define PT_KPC     ", struct pt_regs, kpc);
 	offset("#define PT_SAR     ", struct pt_regs, sar);
-	offset("#define PT_CR11    ", struct pt_regs, sar);
 	offset("#define PT_IIR     ", struct pt_regs, iir);
 	offset("#define PT_ISR     ", struct pt_regs, isr);
 	offset("#define PT_IOR     ", struct pt_regs, ior);
-	offset("#define PT_CR_PID0 ", struct pt_regs, cr_pid[0]);
-	offset("#define PT_CR_PID1 ", struct pt_regs, cr_pid[1]);
-	offset("#define PT_CR_PID2 ", struct pt_regs, cr_pid[2]);
-	offset("#define PT_CR_PID3 ", struct pt_regs, cr_pid[3]);
 	size("#define PT_SIZE    ", struct pt_regs);
 	size_align("#define PT_SZ_ALGN  ", struct pt_regs, 64);
 	linefeed;
@@ -249,6 +247,7 @@
 	offset("#define TASK_NICE          ", struct task_struct, nice);
 	offset("#define TASK_MM            ", struct task_struct, mm);
 	offset("#define TASK_PROCESSOR     ", struct task_struct, processor);
+	offset("#define TASK_PERSONALITY   ", struct task_struct, personality);
 	size  ("#define TASK_SZ          ", struct task_struct);
 	size_align("#define TASK_SZ_ALGN       ", struct task_struct, 64);
 	linefeed;
@@ -257,12 +256,39 @@
 void output_irq_stat_defines(void)
 {
 	text("/* PARISC irq_cpustat_t offsets. */");
-	offset("#define IRQSTAT_SI_ACTIVE  ", irq_cpustat_t, __softirq_active);
-	offset("#define IRQSTAT_SI_MASK    ", irq_cpustat_t, __softirq_mask);
+	offset("#define IRQSTAT_SIRQ_PEND  ", irq_cpustat_t, __softirq_pending);
 	size  ("#define IRQSTAT_SZ         ", irq_cpustat_t);
 	linefeed;
 }
 
+void output_cache_info_defines(void)
+{
+	text("/* PARISC pdc_cache_info offsets. */");
+	offset("#define ICACHE_BASE      ", struct pdc_cache_info, ic_base);
+	offset("#define ICACHE_STRIDE    ", struct pdc_cache_info, ic_stride);
+	offset("#define ICACHE_COUNT     ", struct pdc_cache_info, ic_count);
+	offset("#define ICACHE_LOOP      ", struct pdc_cache_info, ic_loop);
+	offset("#define DCACHE_BASE      ", struct pdc_cache_info, dc_base);
+	offset("#define DCACHE_STRIDE    ", struct pdc_cache_info, dc_stride);
+	offset("#define DCACHE_COUNT     ", struct pdc_cache_info, dc_count);
+	offset("#define DCACHE_LOOP      ", struct pdc_cache_info, dc_loop);
+	offset("#define ITLB_SID_BASE    ", struct pdc_cache_info, it_sp_base);
+	offset("#define ITLB_SID_STRIDE  ", struct pdc_cache_info, it_sp_stride);
+	offset("#define ITLB_SID_COUNT   ", struct pdc_cache_info, it_sp_count);
+	offset("#define ITLB_OFF_BASE    ", struct pdc_cache_info, it_off_base);
+	offset("#define ITLB_OFF_STRIDE  ", struct pdc_cache_info, it_off_stride);
+	offset("#define ITLB_OFF_COUNT   ", struct pdc_cache_info, it_off_count);
+	offset("#define ITLB_LOOP        ", struct pdc_cache_info, it_loop);
+	offset("#define DTLB_SID_BASE    ", struct pdc_cache_info, dt_sp_base);
+	offset("#define DTLB_SID_STRIDE  ", struct pdc_cache_info, dt_sp_stride);
+	offset("#define DTLB_SID_COUNT   ", struct pdc_cache_info, dt_sp_count);
+	offset("#define DTLB_OFF_BASE    ", struct pdc_cache_info, dt_off_base);
+	offset("#define DTLB_OFF_STRIDE  ", struct pdc_cache_info, dt_off_stride);
+	offset("#define DTLB_OFF_COUNT   ", struct pdc_cache_info, dt_off_count);
+	offset("#define DTLB_LOOP        ", struct pdc_cache_info, dt_loop);
+	linefeed;
+}
+
 #ifdef PRUMPF_HAD_MORE_TIME
 void output_thread_defines(void)
 {
diff -urN linux-2.4.20-pre1/arch/parisc/vmlinux.lds linux-2.4.20-pre2/arch/parisc/vmlinux.lds
--- linux-2.4.20-pre1/arch/parisc/vmlinux.lds	Mon Jul  2 14:40:58 2001
+++ linux-2.4.20-pre2/arch/parisc/vmlinux.lds	Mon Aug 12 16:34:14 2002
@@ -1,21 +1,14 @@
 /* ld script to make hppa Linux kernel */
-OUTPUT_FORMAT("elf32-hppa")
 OUTPUT_ARCH(hppa)
 ENTRY(_stext)
 SECTIONS
 {
 
-/* right now use 0x10000/0x11000, later when we don't use Console and
- * Boot-Device IODC, we will change this to 0x8000 !!!
- */
-
-  . = 0xc0100000;   
-/*	. = 0x10000;  */
+  . = 0x10100000;
 
   _text = .;			/* Text and read-only data */
   .text BLOCK(16) : {
 	*(.text*)
-	*(.PARISC.unwind)
 	*(.fixup)
 	*(.lock.text)		/* out-of-line lock text */
 	*(.gnu.warning)
@@ -57,12 +50,14 @@
 
 
   init_task BLOCK(16384) : { *(init_task) }  /* The initial task and kernel stack */
+  init_istack BLOCK(32768) : { *(init_istack) }  /* The initial interrupt stack */
 
   _edata = .;			/* End of data section */
 
 
   .bss : { *(.bss) *(COMMON) }		/* BSS */
 
+  .PARISC.unwind : { *(.PARISC.unwind) }
 
   _end = . ;
 
diff -urN linux-2.4.20-pre1/arch/parisc/vmlinux64.lds linux-2.4.20-pre2/arch/parisc/vmlinux64.lds
--- linux-2.4.20-pre1/arch/parisc/vmlinux64.lds	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/parisc/vmlinux64.lds	Mon Aug 12 16:34:14 2002
@@ -0,0 +1,76 @@
+/* ld script to make hppa Linux kernel */
+OUTPUT_ARCH(hppa:hppa2.0w)
+ENTRY(_stext)
+SECTIONS
+{
+
+  . = 0x10100000;
+
+  _text = .;			/* Text and read-only data */
+  .text BLOCK(16) : {
+	*(.text*)
+	*(.PARISC.unwind)
+	*(.fixup)
+	*(.lock.text)		/* out-of-line lock text */
+	*(.gnu.warning)
+	} = 0
+
+  . = ALIGN(16);
+  .rodata : { *(.rodata) }
+  .kstrtab : { *(.kstrtab) }
+
+  _etext = .;			/* End of text section */
+  
+  .data BLOCK(8192) : {			/* Data without special */
+	data_start = .;
+	*(.data)
+	}
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+  . = ALIGN(16);		/* Linkage tables */
+  .opd : { *(.opd) } PROVIDE (__gp = .); .plt : { *(.plt) } .dlt : { *(.dlt) }
+
+  . = ALIGN(16384);
+  __init_begin = .;
+  .init.text : { *(.init.text) }
+  .init.data : { *(.init.data) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) } 
+  __initcall_end = .;
+  __init_end = .;
+
+
+  init_task BLOCK(16384) : { *(init_task) }  /* The initial task and kernel stack */
+  init_istack BLOCK(32768) : { *(init_task) }  /* The initial interrupt stack */
+
+  _edata = .;			/* End of data section */
+
+
+  .bss : { *(.bss) *(COMMON) }		/* BSS */
+
+
+  _end = . ;
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note 0 : { *(.note) }	
+	
+}
diff -urN linux-2.4.20-pre1/arch/ppc/Makefile linux-2.4.20-pre2/arch/ppc/Makefile
--- linux-2.4.20-pre1/arch/ppc/Makefile	Thu Oct 11 09:04:57 2001
+++ linux-2.4.20-pre2/arch/ppc/Makefile	Mon Aug 12 16:34:14 2002
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.23 09/18/01 11:19:05 paulus
+# BK Id: %F% %I% %G% %U% %#%
 #
 # 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
@@ -21,16 +21,17 @@
 CHECKS		= checks
 endif
 
-ASFLAGS		=
 LINKFLAGS	= -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
-CPPFLAGS	:= $(CPPFLAGS) -D__powerpc__
-CFLAGS		:= $(CFLAGS) -D__powerpc__ -fsigned-char \
+CPPFLAGS	:= $(CPPFLAGS) -I$(TOPDIR)/arch/$(ARCH)
+AFLAGS		:= $(AFLAGS) -I$(TOPDIR)/arch/$(ARCH)
+CFLAGS		:= $(CFLAGS) -I$(TOPDIR)/arch/$(ARCH) -fsigned-char \
 		-msoft-float -pipe -ffixed-r2 -Wno-uninitialized \
 		-mmultiple -mstring
+HOSTCFLAGS	+= -I$(TOPDIR)/arch/$(ARCH)
 CPP		= $(CC) -E $(CFLAGS)
 
 ifdef CONFIG_4xx
-CFLAGS := $(CFLAGS) -mcpu=403
+CFLAGS := $(CFLAGS) -Wa,-m405
 endif
 
 ifdef CONFIG_8xx
@@ -51,9 +52,10 @@
   endif
 endif
 
-ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib
+ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/platforms arch/ppc/mm arch/ppc/lib
 SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
-CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
+CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/platforms/platform.o \
+	arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
 
 ifdef CONFIG_MATH_EMULATION
 SUBDIRS += arch/ppc/math-emu
diff -urN linux-2.4.20-pre1/arch/ppc/boot/common/crt0.S linux-2.4.20-pre2/arch/ppc/boot/common/crt0.S
--- linux-2.4.20-pre1/arch/ppc/boot/common/crt0.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/boot/common/crt0.S	Mon Aug 12 16:34:14 2002
@@ -22,7 +22,7 @@
  */
 
 #include <linux/config.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 	.text
 
diff -urN linux-2.4.20-pre1/arch/ppc/boot/common/relocate.S linux-2.4.20-pre2/arch/ppc/boot/common/relocate.S
--- linux-2.4.20-pre1/arch/ppc/boot/common/relocate.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/boot/common/relocate.S	Mon Aug 12 16:34:14 2002
@@ -20,7 +20,7 @@
 #include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 #define GETSYM(reg, sym)	\
 	lis	reg, sym@h; ori	reg, reg, sym@l	
diff -urN linux-2.4.20-pre1/arch/ppc/boot/common/util.S linux-2.4.20-pre2/arch/ppc/boot/common/util.S
--- linux-2.4.20-pre1/arch/ppc/boot/common/util.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/boot/common/util.S	Mon Aug 12 16:34:14 2002
@@ -24,7 +24,7 @@
 
 #include <asm/processor.h>
 #include <asm/cache.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 
 	.text
diff -urN linux-2.4.20-pre1/arch/ppc/boot/prep/head.S linux-2.4.20-pre2/arch/ppc/boot/prep/head.S
--- linux-2.4.20-pre1/arch/ppc/boot/prep/head.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/boot/prep/head.S	Mon Aug 12 16:34:14 2002
@@ -2,7 +2,7 @@
  * BK Id: SCCS/s.head.S 1.13 01/11/02 10:46:07 trini
  */
 
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
 
diff -urN linux-2.4.20-pre1/arch/ppc/boot/simple/head.S linux-2.4.20-pre2/arch/ppc/boot/simple/head.S
--- linux-2.4.20-pre1/arch/ppc/boot/simple/head.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/boot/simple/head.S	Mon Aug 12 16:34:14 2002
@@ -18,7 +18,7 @@
 #include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 	.text
 
diff -urN linux-2.4.20-pre1/arch/ppc/boot/simple/legacy.S linux-2.4.20-pre2/arch/ppc/boot/simple/legacy.S
--- linux-2.4.20-pre1/arch/ppc/boot/simple/legacy.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/boot/simple/legacy.S	Mon Aug 12 16:34:14 2002
@@ -6,7 +6,7 @@
  * This will go and setup ISA_io to 0x8000000 and return.
  */
 
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 	.text
 
diff -urN linux-2.4.20-pre1/arch/ppc/config.in linux-2.4.20-pre2/arch/ppc/config.in
--- linux-2.4.20-pre1/arch/ppc/config.in	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/config.in	Mon Aug 12 16:34:14 2002
@@ -395,6 +395,8 @@
 
 source net/bluetooth/Config.in
 
+source lib/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/Makefile linux-2.4.20-pre2/arch/ppc/kernel/Makefile
--- linux-2.4.20-pre1/arch/ppc/kernel/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/Makefile	Mon Aug 12 16:34:14 2002
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.41 04/16/02 20:08:22 paulus
+# BK Id: %F% %I% %G% %U% %#%
 #
 #
 # Makefile for the linux kernel.
@@ -14,9 +14,9 @@
 ifdef CONFIG_PPC64BRIDGE
 EXTRA_AFLAGS		:= -Wa,-mppc64bridge
 endif
-
-# Extra CFLAGS so we don't have to do relative includes
-CFLAGS_pmac_setup.o	+= -I$(TOPDIR)/arch/$(ARCH)/mm -I$(TOPDIR)/drivers/scsi
+ifdef CONFIG_4xx
+EXTRA_AFLAGS		:= -Wa,-m405
+endif
 
 # Code in these files is used before the kernel is moved to its final position
 CFLAGS_prom_init.o	+= -mrelocatable-lib
@@ -31,7 +31,7 @@
 
 O_TARGET := kernel.o
 
-export-objs			:= ppc_ksyms.o prep_setup.o time.o
+export-objs			:= ppc_ksyms.o time.o
 
 obj-y				:= entry.o traps.o irq.o idle.o time.o misc.o \
 					process.o signal.o ptrace.o align.o \
@@ -39,17 +39,12 @@
 					cputable.o ppc_htab.o
 obj-$(CONFIG_6xx)		+= l2cr.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
-obj-$(CONFIG_POWER4)		+= xics.o
-obj-$(CONFIG_PCI)		+= pci.o pci-dma.o
+obj-$(CONFIG_PCI)		+= pci.o 
+obj-$(CONFIG_PCI)		+= pci-dma.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
 obj-$(CONFIG_SMP)		+= smp.o
-obj-$(CONFIG_4xx)		+= ppc4xx_pic.o
-obj-$(CONFIG_OAK)		+= oak_setup.o
-obj-$(CONFIG_WALNUT)		+= walnut_setup.o
 obj-$(CONFIG_TAU)		+= temp.o
-ifeq ($(CONFIG_WALNUT),y)
-obj-$(CONFIG_PCI)		+= galaxy_pci.o
-endif
+obj-$(CONFIG_4xx)		+= ppc4xx_pic.o
 obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o
 ifeq ($(CONFIG_8xx),y)
 obj-$(CONFIG_PCI)		+= qspan_pci.o
@@ -58,30 +53,12 @@
 endif
 endif
 obj-$(CONFIG_MBX)		+= i8259.o
-obj-$(CONFIG_APUS)		+= apus_setup.o
-ifeq ($(CONFIG_APUS),y)
-obj-$(CONFIG_PCI)		+= apus_pci.o
-endif
-obj-$(CONFIG_ALL_PPC)		+= pmac_pic.o pmac_setup.o pmac_time.o prom.o \
-					prom_init.o pmac_feature.o pmac_pci.o \
-					chrp_setup.o chrp_time.o chrp_pci.o \
-					open_pic.o indirect_pci.o i8259.o \
-					prep_pci.o prep_time.o prep_nvram.o \
-					prep_setup.o
-obj-$(CONFIG_NVRAM)		+= pmac_nvram.o
-obj-$(CONFIG_PMAC_BACKLIGHT)	+= pmac_backlight.o
-obj-$(CONFIG_PMAC_PBOOK)	+= sleep.o
-obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
-obj-$(CONFIG_PPC_RTAS)		+= error_log.o proc_rtas.o
-obj-$(CONFIG_GEMINI)		+= gemini_prom.o gemini_pci.o gemini_setup.o \
-					open_pic.o
+obj-$(CONFIG_ALL_PPC)		+= prom_init.o prom.o open_pic.o \
+					indirect_pci.o i8259.o prep_nvram.o
+obj-$(CONFIG_GEMINI)		+= open_pic.o
 obj-$(CONFIG_8260)		+= m8260_setup.o ppc8260_pic.o
 obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 
-ifeq ($(CONFIG_SMP),y)
-obj-$(CONFIG_ALL_PPC)		+= pmac_smp.o chrp_smp.o
-endif
-
 include $(TOPDIR)/Rules.make
 
 entry.o: entry.S ppc_defs.h
@@ -90,7 +67,6 @@
 head.o: head.S ppc_defs.h
 head_4xx.o: head_4xx.S ppc_defs.h
 head_8xx.o: head_8xx.S ppc_defs.h
-gemini_prom.o: gemini_prom.S ppc_defs.h
 
 ppc_defs.h: mk_defs.c ppc_defs.head \
 		$(TOPDIR)/include/asm/mmu.h \
@@ -110,4 +86,3 @@
 checks: checks.c
 	$(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -fno-builtin -o checks checks.c
 	./checks
-
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/apus_pci.c linux-2.4.20-pre2/arch/ppc/kernel/apus_pci.c
--- linux-2.4.20-pre1/arch/ppc/kernel/apus_pci.c	Sat Sep  8 12:38:41 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/apus_pci.c	Wed Dec 31 16:00:00 1969
@@ -1,187 +0,0 @@
-/*
- * BK Id: SCCS/s.apus_pci.c 1.5 09/08/01 15:47:42 paulus
- */
-/*
- * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch>
- *
- * APUS PCI routines.
- *
- * Currently, only B/CVisionPPC cards (Permedia2) are supported.
- *
- * Thanks to Geert Uytterhoeven for the idea:
- * Read values from given config space(s) for the first devices, -1 otherwise
- *
- */
-
-#include <linux/config.h>
-#ifdef CONFIG_AMIGA
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-
-#include <asm/io.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-
-#include "apus_pci.h"
-
-
-/* These definitions are mostly adapted from pm2fb.c */
-
-#undef APUS_PCI_MASTER_DEBUG
-#ifdef APUS_PCI_MASTER_DEBUG
-#define DPRINTK(a,b...)	printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b)
-#else
-#define DPRINTK(a,b...)
-#endif 
-
-/*
- * The _DEFINITIVE_ memory mapping/unmapping functions.
- * This is due to the fact that they're changing soooo often...
- */
-#define DEFW()		wmb()
-#define DEFR()		rmb()
-#define DEFRW()		mb()
-
-#define DEVNO(d)	((d)>>3)
-#define FNNO(d)		((d)&7)
-
-
-extern unsigned long powerup_PCI_present;
-
-static struct pci_controller *apus_hose;
-
-
-void *pci_io_base(unsigned int bus)
-{
-	return 0;
-}
-
-
-#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
-#define cfg_write(val, addr, type, op)	op((val), (type *)(addr)); DEFW()
-#define cfg_read_bad	*val = ~0;
-#define cfg_write_bad	;
-#define cfg_read_val(val)	*val
-#define cfg_write_val(val)	val
-
-#define APUS_PCI_OP(rw, size, type, op, mask)					\
-int									\
-apus_pcibios_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
-{										\
-	int fnno = FNNO(dev->devfn);						\
-	int devno = DEVNO(dev->devfn);						\
-										\
-	if (dev->bus->number > 0 || devno != 1) {				\
-		cfg_##rw##_bad;							\
-		return PCIBIOS_DEVICE_NOT_FOUND;				\
-	}									\
-	/* base address + function offset + offset ^ endianness conversion */	\
-	cfg_##rw(val, apus_hose->cfg_data + (fnno<<5) + (offset ^ mask),	\
-		 type, op);							\
-										\
-	DPRINTK(#op " b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, v: 0x%x\n",		\
-		dev->bus->number, dev->devfn>>3, dev->devfn&7,			\
-		offset, cfg_##rw##_val(val));					\
-	return PCIBIOS_SUCCESSFUL;						\
-}
-
-APUS_PCI_OP(read, byte, u8 *, readb, 3)
-APUS_PCI_OP(read, word, u16 *, readw, 2)
-APUS_PCI_OP(read, dword, u32 *, readl, 0)
-APUS_PCI_OP(write, byte, u8, writeb, 3)
-APUS_PCI_OP(write, word, u16, writew, 2)
-APUS_PCI_OP(write, dword, u32, writel, 0)
-
-
-static struct pci_ops apus_pci_ops = {
-	apus_pcibios_read_config_byte,
-	apus_pcibios_read_config_word,
-	apus_pcibios_read_config_dword,
-	apus_pcibios_write_config_byte,
-	apus_pcibios_write_config_word,
-	apus_pcibios_write_config_dword
-};
-
-static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM };
-
-void __init
-apus_pcibios_fixup(void)
-{
-/*	struct pci_dev *dev = pci_find_slot(0, 1<<3);
-	unsigned int reg, val, offset;*/
-
-	/* FIXME: interrupt? */
-	/*dev->interrupt = xxx;*/
-
-        request_resource(&iomem_resource, &pci_mem);
-    	printk("%s: PCI mem resource requested\n", __FUNCTION__);
-}
-
-static void __init apus_pcibios_fixup_bus(struct pci_bus *bus)
-{
-        bus->resource[1] = &pci_mem;
-}
-
-
-/* 
- * This is from pm2fb.c again
- * 
- * Check if PCI (B/CVisionPPC) is available, initialize it and set up
- * the pcibios_* pointers
- */
-
-
-void __init
-apus_setup_pci_ptrs(void)
-{
-	if (!powerup_PCI_present) {
-		DPRINTK("no PCI bridge detected\n");
-		return;
-	}
-	DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n");
-
-	apus_hose = pcibios_alloc_controller();
-	if (!apus_hose) {
-		printk("apus_pci: Can't allocate PCI controller structure\n");
-		return;
-	}
-
-	if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) {
-		printk("apus_pci: unable to map PCI config region\n");
-		return;
-	}
-
-	if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) {
-		printk("apus_pci: unable to map PCI bridge\n");
-		return;
-	}
-
-	writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN);
-	DEFW();
-
-	writel(CVPPC_REGS_REGION,  apus_hose->cfg_data+ PCI_BASE_ADDRESS_0);
-	DEFW();
-	writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1);
-	DEFW();
-	writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2);
-	DEFW();
-	writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS);
-	DEFW();
-
-	writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-		PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND);
-	DEFW();
-
-	apus_hose->first_busno = 0;
-	apus_hose->last_busno = 0;
-	apus_hose->ops = &apus_pci_ops;
-	ppc_md.pcibios_fixup = apus_pcibios_fixup;
-	ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus;
-
-	return;
-}
-
-#endif /* CONFIG_AMIGA */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/apus_pci.h linux-2.4.20-pre2/arch/ppc/kernel/apus_pci.h
--- linux-2.4.20-pre1/arch/ppc/kernel/apus_pci.h	Mon May 21 17:04:46 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/apus_pci.h	Wed Dec 31 16:00:00 1969
@@ -1,40 +0,0 @@
-/*
- * BK Id: SCCS/s.apus_pci.h 1.4 05/17/01 18:14:21 cort
- */
-/*
- * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer
- * driver.
- *
- * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
- * --------------------------------------------------------------------------
- * 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.
- */
-
-#ifndef APUS_PCI_H
-#define APUS_PCI_H
-
-
-#include "pci.h"
-
-
-#define CSPPC_PCI_BRIDGE		0xfffe0000
-#define CSPPC_BRIDGE_ENDIAN		0x0000
-#define CSPPC_BRIDGE_INT		0x0010
-
-#define	CVPPC_PCI_CONFIG		0xfffc0000
-#define CVPPC_ROM_ADDRESS		0xe2000001
-#define CVPPC_REGS_REGION		0xef000000
-#define CVPPC_FB_APERTURE_ONE		0xe0000000
-#define CVPPC_FB_APERTURE_TWO		0xe1000000
-#define CVPPC_FB_SIZE			0x00800000
-
-/* CVPPC_BRIDGE_ENDIAN */
-#define CSPPCF_BRIDGE_BIG_ENDIAN	0x02
-
-/* CVPPC_BRIDGE_INT */
-#define CSPPCF_BRIDGE_ACTIVE_INT2	0x01
-
-
-#endif	/* APUS_PCI_H */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/apus_setup.c linux-2.4.20-pre2/arch/ppc/kernel/apus_setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/apus_setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/apus_setup.c	Wed Dec 31 16:00:00 1969
@@ -1,1113 +0,0 @@
-/*
- * BK Id: SCCS/s.apus_setup.c 1.24 11/13/01 21:26:07 paulus
- */
-/*
- *  linux/arch/ppc/kernel/apus_setup.c
- *
- *  Copyright (C) 1998, 1999  Jesper Skov
- *
- *  Basically what is needed to replace functionality found in
- *  arch/m68k allowing Amiga drivers to work under APUS.
- *  Bits of code and/or ideas from arch/m68k and arch/ppc files.
- *
- * TODO:
- *  This file needs a *really* good cleanup. Restructure and optimize.
- *  Make sure it can be compiled for non-APUS configs. Begin to move
- *  Amiga specific stuff into mach/amiga.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kd.h>
-#include <linux/init.h>
-#include <linux/hdreg.h>
-#include <linux/blk.h>
-#include <linux/pci.h>
-#include <linux/seq_file.h>
-
-#ifdef CONFIG_APUS
-#include <asm/logging.h>
-#endif
-
-/* Needs INITSERIAL call in head.S! */
-#undef APUS_DEBUG
-
-
-#include <linux/ide.h>
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-        D_SHORT(10),    /* config - vendor2 */
-        D_TEXT(20),     /* serial_no */
-        D_SHORT(3),     /* buf_type, buf_size - ecc_bytes */
-        D_TEXT(48),     /* fw_rev - model */
-        D_CHAR(2),      /* max_multsect - vendor3 */
-        D_SHORT(1),     /* dword_io */
-        D_CHAR(2),      /* vendor4 - capability */
-        D_SHORT(1),     /* reserved50 */
-        D_CHAR(4),      /* vendor5 - tDMA */
-        D_SHORT(4),     /* field_valid - cur_sectors */
-        D_INT(1),       /* cur_capacity */
-        D_CHAR(2),      /* multsect - multsect_valid */
-        D_INT(1),       /* lba_capacity */
-        D_SHORT(194)    /* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-#include <asm/bootinfo.h>
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amigappc.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-
-#include "local_irq.h"
-
-unsigned long m68k_machtype;
-char debug_device[6] = "";
-
-extern void amiga_init_IRQ(void);
-
-void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
-/* machine dependent keyboard functions */
-int (*mach_keyb_init) (void) __initdata = NULL;
-int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
-void (*mach_kbd_leds) (unsigned int) = NULL;
-/* machine dependent irq functions */
-void (*mach_init_IRQ) (void) __initdata = NULL;
-void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
-void (*mach_get_model) (char *model) = NULL;
-int (*mach_get_hardware_list) (char *buffer) = NULL;
-int (*mach_get_irq_list) (char *) = NULL;
-void (*mach_process_int) (int, struct pt_regs *) = NULL;
-/* machine dependent timer functions */
-unsigned long (*mach_gettimeoffset) (void);
-void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
-int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
-int (*mach_set_clock_mmss) (unsigned long) = NULL;
-void (*mach_reset)( void );
-long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-#if defined(CONFIG_AMIGA_FLOPPY)
-void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
-#endif
-#ifdef CONFIG_HEARTBEAT
-void (*mach_heartbeat) (int) = NULL;
-extern void apus_heartbeat (void);
-#endif
-
-extern unsigned long amiga_model;
-extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */
-extern unsigned count_period_num; /* 1 decrementer count equals */
-extern unsigned count_period_den; /* count_period_num / count_period_den us */
-
-int num_memory = 0;
-struct mem_info memory[NUM_MEMINFO];/* memory description */
-/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */
-int m68k_realnum_memory = 0;
-struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
-
-struct mem_info ramdisk;
-
-extern void amiga_floppy_setup(char *, int *);
-extern void config_amiga(void);
-
-static int __60nsram = 0;
-
-/* for cpuinfo */
-static int __bus_speed = 0;
-static int __speed_test_failed = 0;
-
-/********************************************** COMPILE PROTECTION */
-/* Provide some stubs that links to Amiga specific functions. 
- * This allows CONFIG_APUS to be removed from generic PPC files while
- * preventing link errors for other PPC targets.
- */
-unsigned long apus_get_rtc_time(void)
-{
-#ifdef CONFIG_APUS
-	extern unsigned long m68k_get_rtc_time(void);
-	
-	return m68k_get_rtc_time ();
-#else
-	return 0;
-#endif
-}
-
-int apus_set_rtc_time(unsigned long nowtime)
-{
-#ifdef CONFIG_APUS
-	extern int m68k_set_rtc_time(unsigned long nowtime);
-
-	return m68k_set_rtc_time (nowtime);
-#else
-	return 0;
-#endif
-}
-
-
-
-/* Here some functions we don't support, but which the other ports reference */
-int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return 0; 
-}
-int pckbd_getkeycode(unsigned int scancode) 
-{ 
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return 0; 
-}
-int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-		    char raw_mode) 
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return 0; 
-}
-char pckbd_unexpected_up(unsigned char keycode)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return 0;
-}
-void pckbd_leds(unsigned char leds)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-}
-void pckbd_init_hw(void)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-}
-unsigned char pckbd_sysrq_xlate[128];
-
-struct pci_bus * __init pci_scan_peer_bridge(int bus)
-{
-	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
-	return NULL;
-}
-
-/*********************************************************** SETUP */
-/* From arch/m68k/kernel/setup.c. */
-void __init apus_setup_arch(void)
-{
-#ifdef CONFIG_APUS
-	extern char cmd_line[];
-	int i;
-	char *p, *q;
-
-	/* Let m68k-shared code know it should do the Amiga thing. */
-	m68k_machtype = MACH_AMIGA;
-
-	/* Parse the command line for arch-specific options.
-	 * For the m68k, this is currently only "debug=xxx" to enable printing
-	 * certain kernel messages to some machine-specific device.  */
-	for( p = cmd_line; p && *p; ) {
-	    i = 0;
-	    if (!strncmp( p, "debug=", 6 )) {
-		    strncpy( debug_device, p+6, sizeof(debug_device)-1 );
-		    debug_device[sizeof(debug_device)-1] = 0;
-		    if ((q = strchr( debug_device, ' ' ))) *q = 0;
-		    i = 1;
-	    } else if (!strncmp( p, "60nsram", 7 )) {
-		    APUS_WRITE (APUS_REG_WAITSTATE, 
-				REGWAITSTATE_SETRESET
-				|REGWAITSTATE_PPCR
-				|REGWAITSTATE_PPCW);
-		    __60nsram = 1;
-		    i = 1;
-	    }
-
-	    if (i) {
-		/* option processed, delete it */
-		if ((q = strchr( p, ' ' )))
-		    strcpy( p, q+1 );
-		else
-		    *p = 0;
-	    } else {
-		if ((p = strchr( p, ' ' ))) ++p;
-	    }
-	}
-
-	config_amiga();
-
-#if 0 /* Enable for logging - also include logging.o in Makefile rule */
-	{
-#define LOG_SIZE 4096
-		void* base;
-
-		/* Throw away some memory - the P5 firmare stomps on top
-		 * of CHIP memory during bootup.
-		 */
-		amiga_chip_alloc(0x1000);
-
-		base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t));
-		LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE);
-	}
-#endif
-#endif
-}
-
-int
-apus_show_cpuinfo(struct seq_file *m)
-{
-	extern int __map_without_bats;
-	extern unsigned long powerup_PCI_present;
-
-	seq_printf(m, "machine\t\t: Amiga\n");
-	seq_printf(m, "bus speed\t: %d%s", __bus_speed,
-		   (__speed_test_failed) ? " [failed]\n" : "\n");
-	seq_printf(m, "using BATs\t: %s\n",
-		   (__map_without_bats) ? "No" : "Yes");
-	seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70);
-	seq_printf(m, "PCI bridge\t: %s\n",
-		   (powerup_PCI_present) ? "Yes" : "No");
-	return 0;
-}
-
-static void get_current_tb(unsigned long long *time)
-{
-	__asm __volatile ("1:mftbu 4      \n\t"
-			  "  mftb  5      \n\t"
-			  "  mftbu 6      \n\t"
-			  "  cmpw  4,6    \n\t"
-			  "  bne   1b     \n\t"
-			  "  stw   4,0(%0)\n\t"
-			  "  stw   5,4(%0)\n\t"
-			  : 
-			  : "r" (time)
-			  : "r4", "r5", "r6");
-}
-
-
-void apus_calibrate_decr(void)
-{
-#ifdef CONFIG_APUS
-	unsigned long freq;
-
-	/* This algorithm for determining the bus speed was
-           contributed by Ralph Schmidt. */
-	unsigned long long start, stop;
-	int bus_speed;
-	int speed_test_failed = 0;
-
-	{
-		unsigned long loop = amiga_eclock / 10;
-
-		get_current_tb (&start);
-		while (loop--) {
-			unsigned char tmp;
-
-			tmp = ciaa.pra;
-		}
-		get_current_tb (&stop);
-	}
-
-	bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000;
-	if (AMI_1200 == amiga_model)
-		bus_speed /= 2;
-
-	if ((bus_speed >= 47) && (bus_speed < 53)) {
-		bus_speed = 50;
-		freq = 12500000;
-	} else if ((bus_speed >= 57) && (bus_speed < 63)) {
-		bus_speed = 60;
-		freq = 15000000;
-	} else if ((bus_speed >= 63) && (bus_speed < 69)) {
-		bus_speed = 67;
-		freq = 16666667;
-	} else {
-		printk ("APUS: Unable to determine bus speed (%d). "
-			"Defaulting to 50MHz", bus_speed);
-		bus_speed = 50;
-		freq = 12500000;
-		speed_test_failed = 1;
-	}
-
-	/* Ease diagnostics... */
-	{
-		extern int __map_without_bats;
-		extern unsigned long powerup_PCI_present;
-
-		printk ("APUS: BATs=%d, BUS=%dMHz",
-			(__map_without_bats) ? 0 : 1,
-			bus_speed);
-		if (speed_test_failed)
-			printk ("[FAILED - please report]");
-
-		printk (", RAM=%dns, PCI bridge=%d\n",
-			(__60nsram) ? 60 : 70,
-			(powerup_PCI_present) ? 1 : 0);
-
-		/* print a bit more if asked politely... */
-		if (!(ciaa.pra & 0x40)){
-			extern unsigned int bat_addrs[4][3];
-			int b;
-			for (b = 0; b < 4; ++b) {
-				printk ("APUS: BAT%d ", b);
-				printk ("%08x-%08x -> %08x\n",
-					bat_addrs[b][0],
-					bat_addrs[b][1],
-					bat_addrs[b][2]);
-			}
-		}
-
-	}
-
-        printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-	       freq/1000000, freq%1000000);
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-
-	__bus_speed = bus_speed;
-	__speed_test_failed = speed_test_failed;
-#endif
-}
-
-void arch_gettod(int *year, int *mon, int *day, int *hour,
-		 int *min, int *sec)
-{
-#ifdef CONFIG_APUS
-	if (mach_gettod)
-		mach_gettod(year, mon, day, hour, min, sec);
-	else
-		*year = *mon = *day = *hour = *min = *sec = 0;
-#endif
-}
-
-/* for "kbd-reset" cmdline param */
-__init
-void kbd_reset_setup(char *str, int *ints)
-{
-}
-
-/*********************************************************** FLOPPY */
-#if defined(CONFIG_AMIGA_FLOPPY)
-__init 
-void floppy_setup(char *str, int *ints)
-{
-	if (mach_floppy_setup)
-		mach_floppy_setup (str, ints);
-}
-#endif
-
-/*********************************************************** MEMORY */
-#define KMAP_MAX 32
-unsigned long kmap_chunks[KMAP_MAX*3];
-int kmap_chunk_count = 0;
-
-/* From pgtable.h */
-static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va)
-{
-	pgd_t *dir = 0;
-	pmd_t *pmd = 0;
-	pte_t *pte = 0;
-
-	va &= PAGE_MASK;
-	
-	dir = pgd_offset( mm, va );
-	if (dir)
-	{
-		pmd = pmd_offset(dir, va & PAGE_MASK);
-		if (pmd && pmd_present(*pmd))
-		{
-			pte = pte_offset(pmd, va);
-		}
-	}
-	return pte;
-}
-
-
-/* Again simulating an m68k/mm/kmap.c function. */
-void kernel_set_cachemode( unsigned long address, unsigned long size,
-			   unsigned int cmode )
-{
-	unsigned long mask, flags;
-
-	switch (cmode)
-	{
-	case IOMAP_FULL_CACHING:
-		mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
-		flags = 0;
-		break;
-	case IOMAP_NOCACHE_SER:
-		mask = ~0;
-		flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
-		break;
-	default:
-		panic ("kernel_set_cachemode() doesn't support mode %d\n", 
-		       cmode);
-		break;
-	}
-	
-	size /= PAGE_SIZE;
-	address &= PAGE_MASK;
-	while (size--)
-	{
-		pte_t *pte;
-
-		pte = my_find_pte(&init_mm, address);
-		if ( !pte )
-		{
-			printk("pte NULL in kernel_set_cachemode()\n");
-			return;
-		}
-
-                pte_val (*pte) &= mask;
-                pte_val (*pte) |= flags;
-                flush_tlb_page(find_vma(&init_mm,address),address);
-
-		address += PAGE_SIZE;
-	}
-}
-
-unsigned long mm_ptov (unsigned long paddr)
-{
-	unsigned long ret;
-	if (paddr < 16*1024*1024)
-		ret = ZTWO_VADDR(paddr);
-	else {
-		int i;
-
-		for (i = 0; i < kmap_chunk_count;){
-			unsigned long phys = kmap_chunks[i++];
-			unsigned long size = kmap_chunks[i++];
-			unsigned long virt = kmap_chunks[i++];
-			if (paddr >= phys
-			    && paddr < (phys + size)){
-				ret = virt + paddr - phys;
-				goto exit;
-			}
-		}
-		
-		ret = (unsigned long) __va(paddr);
-	}
-exit:
-#ifdef DEBUGPV
-	printk ("PTOV(%lx)=%lx\n", paddr, ret);
-#endif
-	return ret;
-}
-
-int mm_end_of_chunk (unsigned long addr, int len)
-{
-	if (memory[0].addr + memory[0].size == addr + len)
-		return 1;
-	return 0;
-}
-
-/*********************************************************** CACHE */
-
-#define L1_CACHE_BYTES 32
-#define MAX_CACHE_SIZE 8192
-void cache_push(__u32 addr, int length)
-{
-	addr = mm_ptov(addr);
-
-	if (MAX_CACHE_SIZE < length)
-		length = MAX_CACHE_SIZE;
-
-	while(length > 0){
-		__asm ("dcbf 0,%0\n\t"
-		       : : "r" (addr));
-		addr += L1_CACHE_BYTES;
-		length -= L1_CACHE_BYTES;
-	}
-	/* Also flush trailing block */
-	__asm ("dcbf 0,%0\n\t"
-	       "sync \n\t"
-	       : : "r" (addr));
-}
-
-void cache_clear(__u32 addr, int length)
-{
-	if (MAX_CACHE_SIZE < length)
-		length = MAX_CACHE_SIZE;
-
-	addr = mm_ptov(addr);
-
-	__asm ("dcbf 0,%0\n\t"
-	       "sync \n\t"
-	       "icbi 0,%0 \n\t"
-	       "isync \n\t"
-	       : : "r" (addr));
-	
-	addr += L1_CACHE_BYTES;
-	length -= L1_CACHE_BYTES;
-
-	while(length > 0){
-		__asm ("dcbf 0,%0\n\t"
-		       "sync \n\t"
-		       "icbi 0,%0 \n\t"
-		       "isync \n\t"
-		       : : "r" (addr));
-		addr += L1_CACHE_BYTES;
-		length -= L1_CACHE_BYTES;
-	}
-
-	__asm ("dcbf 0,%0\n\t"
-	       "sync \n\t"
-	       "icbi 0,%0 \n\t"
-	       "isync \n\t"
-	       : : "r" (addr));
-}
-
-/****************************************************** from setup.c */
-void
-apus_restart(char *cmd)
-{
-	cli();
-
-	APUS_WRITE(APUS_REG_LOCK, 
-		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
-	APUS_WRITE(APUS_REG_LOCK, 
-		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
-	APUS_WRITE(APUS_REG_LOCK, 
-		   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
-	APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
-	APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
-	for(;;);
-}
-
-void
-apus_power_off(void)
-{
-	for (;;);
-}
-
-void
-apus_halt(void)
-{
-   apus_restart(NULL);
-}
-
-/****************************************************** from setup.c/IDE */
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-
-#if 0	/* no longer used  -- paulus */
-void
-apus_ide_fix_driveid(struct hd_driveid *id)
-{
-   u_char *p = (u_char *)id;
-   int i, j, cnt;
-   u_char t;
-
-   if (!MACH_IS_AMIGA && !MACH_IS_MAC)
-   	return;
-   for (i = 0; i < num_driveid_types; i++) {
-      cnt = driveid_types[i] & T_MASK_COUNT;
-      switch (driveid_types[i] & T_MASK_TYPE) {
-         case T_CHAR:
-            p += cnt;
-            break;
-         case T_SHORT:
-            for (j = 0; j < cnt; j++) {
-               t = p[0];
-               p[0] = p[1];
-               p[1] = t;
-               p += 2;
-            }
-            break;
-         case T_INT:
-            for (j = 0; j < cnt; j++) {
-               t = p[0];
-               p[0] = p[3];
-               p[3] = t;
-               t = p[1];
-               p[1] = p[2];
-               p[2] = t;
-               p += 4;
-            }
-            break;
-         case T_TEXT:
-            for (j = 0; j < cnt; j += 2) {
-               t = p[0];
-               p[0] = p[1];
-               p[1] = t;
-               p += 2;
-            }
-            break;
-      }
-   }
-}
-#endif /* 0 */
-
-__init
-void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, 
-			       ide_ioreg_t ctrl_port, int *irq)
-{
-        if (data_port || ctrl_port)
-                printk("apus_ide_init_hwif_ports: must not be called\n");
-}
-#endif
-/****************************************************** IRQ stuff */
-
-static unsigned int apus_irq_cannonicalize(unsigned int irq)
-{
-	return irq;
-}
-
-int apus_get_irq_list(char *buf)
-{
-#ifdef CONFIG_APUS
-	extern int amiga_get_irq_list(char *buf);
-	
-	return amiga_get_irq_list (buf);
-#else
-	return 0;
-#endif
-}
-
-/* IPL must be between 0 and 7 */
-static inline void apus_set_IPL(unsigned long ipl)
-{
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | ((~ipl) & IPLEMU_IPLMASK));
-	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-}
-
-static inline unsigned long apus_get_IPL(void)
-{
-	/* This returns the present IPL emulation level. */
-	unsigned long __f;
-	APUS_READ(APUS_IPL_EMU, __f);
-	return ((~__f) & IPLEMU_IPLMASK);
-}
-
-static inline unsigned long apus_get_prev_IPL(struct pt_regs* regs)
-{
-	/* The value saved in mq is the IPL_EMU value at the time of
-	   interrupt. The lower bits are the current interrupt level,
-	   the upper bits the requested level. Thus, to restore the
-	   IPL level to the post-interrupt state, we will need to use
-	   the lower bits. */
-	unsigned long __f = regs->mq;
-	return ((~__f) & IPLEMU_IPLMASK);
-}
-
-
-#ifdef CONFIG_APUS
-void free_irq(unsigned int irq, void *dev_id)
-{
-	extern void amiga_free_irq(unsigned int irq, void *dev_id);
-
-	amiga_free_irq (irq, dev_id);
-}
-
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-	unsigned long irqflags, const char * devname, void *dev_id)
-{
-	extern int  amiga_request_irq(unsigned int irq, 
-				      void (*handler)(int, void *, 
-						      struct pt_regs *),
-				      unsigned long flags, 
-				      const char *devname, 
-				      void *dev_id);
-
-	return amiga_request_irq (irq, handler, irqflags, devname, dev_id);
-}
-
-/* In Linux/m68k the sys_request_irq deals with vectors 0-7. That's what
-   callers expect - but on Linux/APUS we actually use the IRQ_AMIGA_AUTO
-   vectors (24-31), so we put this dummy function in between to adjust
-   the vector argument (rather have cruft here than in the generic irq.c). */
-int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-		    unsigned long irqflags, const char * devname, void *dev_id)
-{
-	extern int request_sysirq(unsigned int irq, 
-				  void (*handler)(int, void *, 
-						  struct pt_regs *),
-				  unsigned long irqflags,
-				  const char * devname, void *dev_id);
-	return request_sysirq(irq+IRQ_AMIGA_AUTO, handler, irqflags, 
-			      devname, dev_id);
-}
-#endif
-
-int apus_get_irq(struct pt_regs* regs)
-{
-#ifdef CONFIG_APUS
-	int level = apus_get_IPL();
-
-#ifdef __INTERRUPT_DEBUG
-	printk("<%d:%d>", level, apus_get_prev_IPL(regs));
-#endif
-
-	if (0 == level)
-		return -8;
-	if (7 == level)
-		return -9;
-
-	return level + IRQ_AMIGA_AUTO;
-#else
-	return 0;
-#endif
-}
-
-void apus_post_irq(struct pt_regs* regs, int level)
-{
-#ifdef __INTERRUPT_DEBUG
-	printk("{%d}", apus_get_prev_IPL(regs));
-#endif
-	/* Restore IPL to the previous value */
-	apus_set_IPL(apus_get_prev_IPL(regs));
-}
-
-/****************************************************** keyboard */
-static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	return -EOPNOTSUPP;
-}
-
-static int apus_kbd_getkeycode(unsigned int scancode)
-{
-	return scancode > 127 ? -EINVAL : scancode;
-}
-
-static int apus_kbd_translate(unsigned char keycode, unsigned char *keycodep,
-			      char raw_mode)
-{
-	*keycodep = keycode;
-	return 1;
-}
-
-static char apus_kbd_unexpected_up(unsigned char keycode)
-{
-	return 0200;
-}
-
-static void apus_kbd_leds(unsigned char leds)
-{
-}
-
-static void apus_kbd_init_hw(void)
-{
-#ifdef CONFIG_APUS
-	extern int amiga_keyb_init(void);
-
-	amiga_keyb_init();
-#endif
-}
-
-
-/****************************************************** debugging */
-
-/* some serial hardware definitions */
-#define SDR_OVRUN   (1<<15)
-#define SDR_RBF     (1<<14)
-#define SDR_TBE     (1<<13)
-#define SDR_TSRE    (1<<12)
-
-#define AC_SETCLR   (1<<15)
-#define AC_UARTBRK  (1<<11)
-
-#define SER_DTR     (1<<7)
-#define SER_RTS     (1<<6)
-#define SER_DCD     (1<<5)
-#define SER_CTS     (1<<4)
-#define SER_DSR     (1<<3)
-
-static __inline__ void ser_RTSon(void)
-{
-    ciab.pra &= ~SER_RTS; /* active low */
-}
-
-int __debug_ser_out( unsigned char c )
-{
-	custom.serdat = c | 0x100;
-	mb();
-	while (!(custom.serdatr & 0x2000))
-		barrier();
-	return 1;
-}
-
-unsigned char __debug_ser_in( void )
-{
-	unsigned char c;
-
-	/* XXX: is that ok?? derived from amiga_ser.c... */
-	while( !(custom.intreqr & IF_RBF) )
-		barrier();
-	c = custom.serdatr;
-	/* clear the interrupt, so that another character can be read */
-	custom.intreq = IF_RBF;
-	return c;
-}
-
-int __debug_serinit( void )
-{	
-	unsigned long flags;
-	
-	save_flags (flags);
-	cli();
-
-	/* turn off Rx and Tx interrupts */
-	custom.intena = IF_RBF | IF_TBE;
-
-	/* clear any pending interrupt */
-	custom.intreq = IF_RBF | IF_TBE;
-
-	restore_flags (flags);
-
-	/*
-	 * set the appropriate directions for the modem control flags,
-	 * and clear RTS and DTR
-	 */
-	ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
-	ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
-	
-#ifdef CONFIG_KGDB
-	/* turn Rx interrupts on for GDB */
-	custom.intena = IF_SETCLR | IF_RBF;
-	ser_RTSon();
-#endif
-
-	return 0;
-}
-
-void __debug_print_hex(unsigned long x)
-{
-	int i;
-	char hexchars[] = "0123456789ABCDEF";
-
-	for (i = 0; i < 8; i++) {
-		__debug_ser_out(hexchars[(x >> 28) & 15]);
-		x <<= 4;
-	}
-	__debug_ser_out('\n');
-	__debug_ser_out('\r');
-}
-
-void __debug_print_string(char* s)
-{
-	unsigned char c;
-	while((c = *s++))
-		__debug_ser_out(c);
-	__debug_ser_out('\n');
-	__debug_ser_out('\r');
-}
-
-static void apus_progress(char *s, unsigned short value)
-{
-	__debug_print_string(s);
-}
-
-/****************************************************** init */
-
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
-
-#define NUM_IRQ_NODES 100
-static irq_node_t nodes[NUM_IRQ_NODES];
-
-extern void (*amiga_default_handler[AUTO_IRQS])(int, void *, struct pt_regs *);
-
-static const char *default_names[SYS_IRQS] = {
-	"spurious int", "int1 handler", "int2 handler", "int3 handler",
-	"int4 handler", "int5 handler", "int6 handler", "int7 handler"
-};
-
-irq_node_t *new_irq_node(void)
-{
-	irq_node_t *node;
-	short i;
-
-	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
-		if (!node->handler)
-			return node;
-
-	printk ("new_irq_node: out of nodes\n");
-	return NULL;
-}
-
-extern void amiga_enable_irq(unsigned int irq);
-extern void amiga_disable_irq(unsigned int irq);
-
-struct hw_interrupt_type amiga_irqctrl = {
-	" Amiga  ",
-	NULL,
-	NULL,
-	amiga_enable_irq,
-	amiga_disable_irq,
-	0,
-	0
-};
-
-#define HARDWARE_MAPPED_SIZE (512*1024)
-unsigned long __init apus_find_end_of_memory(void)
-{
-	int shadow = 0;
-	unsigned long total;
-
-	/* The memory size reported by ADOS excludes the 512KB
-	   reserved for PPC exception registers and possibly 512KB
-	   containing a shadow of the ADOS ROM. */
-	{
-		unsigned long size = memory[0].size;
-
-		/* If 2MB aligned, size was probably user
-                   specified. We can't tell anything about shadowing
-                   in this case so skip shadow assignment. */
-		if (0 != (size & 0x1fffff)){
-			/* Align to 512KB to ensure correct handling
-			   of both memfile and system specified
-			   sizes. */
-			size = ((size+0x0007ffff) & 0xfff80000);
-			/* If memory is 1MB aligned, assume
-                           shadowing. */
-			shadow = !(size & 0x80000);
-		}
-
-		/* Add the chunk that ADOS does not see. by aligning
-                   the size to the nearest 2MB limit upwards.  */
-		memory[0].size = ((size+0x001fffff) & 0xffe00000);
-	}
-
-	total = memory[0].size;
-
-	/* Remove the memory chunks that are controlled by special
-           Phase5 hardware. */
-
-	/* Remove the upper 512KB if it contains a shadow of
-	   the ADOS ROM. FIXME: It might be possible to
-	   disable this shadow HW. Check the booter
-	   (ppc_boot.c) */
-	if (shadow)
-		total -= HARDWARE_MAPPED_SIZE;
-
-	/* Remove the upper 512KB where the PPC exception
-	   vectors are mapped. */
-	total -= HARDWARE_MAPPED_SIZE;
-
-	/* Linux/APUS only handles one block of memory -- the one on
-	   the PowerUP board. Other system memory is horrible slow in
-	   comparison. The user can use other memory for swapping
-	   using the z2ram device. */
-	ram_phys_base = memory[0].addr;
-	return total;
-}
-
-static void __init
-apus_map_io(void)
-{
-	/* Map PPC exception vectors. */
-	io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL);
-	/* Map chip and ZorroII memory */
-	io_block_mapping(zTwoBase,   0x00000000, 0x01000000, _PAGE_IO);
-}
-
-__init
-void apus_init_IRQ(void)
-{
-	int i;
-
-	for ( i = 0 ; i < NR_IRQS ; i++ )
-		irq_desc[i].handler = &amiga_irqctrl;
-
-	for (i = 0; i < NUM_IRQ_NODES; i++)
-		nodes[i].handler = NULL;
-
-	for (i = 0; i < AUTO_IRQS; i++) {
-		if (amiga_default_handler[i] != NULL)
-			sys_request_irq(i, amiga_default_handler[i],
-					0, default_names[i], NULL);
-	}
-
-	amiga_init_IRQ();
-
-}
-
-__init
-void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-		   unsigned long r6, unsigned long r7)
-{
-	extern int parse_bootinfo(const struct bi_record *);
-	extern char _end[];
-	
-	/* Parse bootinfo. The bootinfo is located right after
-           the kernel bss */
-	parse_bootinfo((const struct bi_record *)&_end);
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* Take care of initrd if we have one. Use data from
-	   bootinfo to avoid the need to initialize PPC
-	   registers when kernel is booted via a PPC reset. */
-	if ( ramdisk.addr ) {
-		initrd_start = (unsigned long) __va(ramdisk.addr);
-		initrd_end = (unsigned long) 
-			__va(ramdisk.size + ramdisk.addr);
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	ISA_DMA_THRESHOLD = 0x00ffffff;
-
-	ppc_md.setup_arch     = apus_setup_arch;
-	ppc_md.show_cpuinfo   = apus_show_cpuinfo;
-	ppc_md.irq_cannonicalize = apus_irq_cannonicalize;
-	ppc_md.init_IRQ       = apus_init_IRQ;
-	ppc_md.get_irq        = apus_get_irq;
-	
-#error Should use the ->end() member of irq_desc[x]. -- Cort
-	/*ppc_md.post_irq       = apus_post_irq;*/
-	
-#ifdef CONFIG_HEARTBEAT
-	ppc_md.heartbeat      = apus_heartbeat;
-	ppc_md.heartbeat_count = 1;
-#endif
-#ifdef APUS_DEBUG
-	__debug_serinit();
-	ppc_md.progress       = apus_progress;
-#endif
-	ppc_md.init           = NULL;
-
-	ppc_md.restart        = apus_restart;
-	ppc_md.power_off      = apus_power_off;
-	ppc_md.halt           = apus_halt;
-
-	ppc_md.time_init      = NULL;
-	ppc_md.set_rtc_time   = apus_set_rtc_time;
-	ppc_md.get_rtc_time   = apus_get_rtc_time;
-	ppc_md.calibrate_decr = apus_calibrate_decr;
-
-	ppc_md.find_end_of_memory = apus_find_end_of_memory;
-	ppc_md.setup_io_mappings = apus_map_io;
-
-	ppc_md.nvram_read_val = NULL;
-	ppc_md.nvram_write_val = NULL;
-
-	/* These should not be used for the APUS yet, since it uses
-	   the M68K keyboard now. */
-	ppc_md.kbd_setkeycode    = apus_kbd_setkeycode;
-	ppc_md.kbd_getkeycode    = apus_kbd_getkeycode;
-	ppc_md.kbd_translate     = apus_kbd_translate;
-	ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up;
-	ppc_md.kbd_leds          = apus_kbd_leds;
-	ppc_md.kbd_init_hw       = apus_kbd_init_hw;
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports;
-#endif		
-}
-
-
-/*************************************************** coexistence */
-void __init adbdev_init(void)
-{
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/chrp_pci.c linux-2.4.20-pre2/arch/ppc/kernel/chrp_pci.c
--- linux-2.4.20-pre1/arch/ppc/kernel/chrp_pci.c	Sat Sep  8 12:38:41 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/chrp_pci.c	Wed Dec 31 16:00:00 1969
@@ -1,330 +0,0 @@
-/*
- * BK Id: SCCS/s.chrp_pci.c 1.22 09/08/01 15:47:42 paulus
- */
-/*
- * CHRP pci routines.
- */
-
-#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/hydra.h>
-#include <asm/prom.h>
-#include <asm/gg2.h>
-#include <asm/machdep.h>
-#include <asm/sections.h>
-#include <asm/pci-bridge.h>
-
-#include "open_pic.h"
-#include "pci.h"
-
-/* LongTrail */
-unsigned long gg2_pci_config_base;
-
-#define pci_config_addr(dev, offset) \
-(gg2_pci_config_base | ((dev->bus->number)<<16) | ((dev->devfn)<<8) | (offset))
-
-volatile struct Hydra *Hydra = NULL;
-
-/*
- * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
- * limit the bus number to 3 bits
- */
-
-#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
-#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
-
-#define cfg_read_bad(val, size)		*val = bad_##size;
-#define cfg_write_bad(val, size)
-
-#define bad_byte	0xff
-#define bad_word	0xffff
-#define bad_dword	0xffffffffU
-
-#define GG2_PCI_OP(rw, size, type, op)					    \
-int __chrp gg2_##rw##_config_##size(struct pci_dev *dev, int off, type val) \
-{									    \
-	if (dev->bus->number > 7) {					    \
-		cfg_##rw##_bad(val, size)				    \
-		return PCIBIOS_DEVICE_NOT_FOUND;			    \
-	}								    \
-	cfg_##rw(val, pci_config_addr(dev, off), type, op);		    \
-	return PCIBIOS_SUCCESSFUL;					    \
-}
-
-GG2_PCI_OP(read, byte, u8 *, in_8)
-GG2_PCI_OP(read, word, u16 *, in_le16)
-GG2_PCI_OP(read, dword, u32 *, in_le32)
-GG2_PCI_OP(write, byte, u8, out_8)
-GG2_PCI_OP(write, word, u16, out_le16)
-GG2_PCI_OP(write, dword, u32, out_le32)
-
-static struct pci_ops gg2_pci_ops =
-{
-	gg2_read_config_byte,
-	gg2_read_config_word,
-	gg2_read_config_dword,
-	gg2_write_config_byte,
-	gg2_write_config_word,
-	gg2_write_config_dword
-};
-
-/*
- * Access functions for PCI config space on IBM "python" host bridges.
- */
-#define PYTHON_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
-				 | (((o) & ~3) << 24))
-
-#define PYTHON_PCI_OP(rw, size, type, op, mask)			    	     \
-int __chrp								     \
-python_##rw##_config_##size(struct pci_dev *dev, int offset, type val) 	     \
-{									     \
-	struct pci_controller *hose = dev->sysdata;			     \
-									     \
-	out_be32(hose->cfg_addr,					     \
-		 PYTHON_CFA(dev->bus->number, dev->devfn, offset));	     \
-	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);   	     \
-	return PCIBIOS_SUCCESSFUL;					     \
-}
-
-PYTHON_PCI_OP(read, byte, u8 *, in_8, 3)
-PYTHON_PCI_OP(read, word, u16 *, in_le16, 2)
-PYTHON_PCI_OP(read, dword, u32 *, in_le32, 0)
-PYTHON_PCI_OP(write, byte, u8, out_8, 3)
-PYTHON_PCI_OP(write, word, u16, out_le16, 2)
-PYTHON_PCI_OP(write, dword, u32, out_le32, 0)
-
-static struct pci_ops python_pci_ops =
-{
-	python_read_config_byte,
-	python_read_config_word,
-	python_read_config_dword,
-	python_write_config_byte,
-	python_write_config_word,
-	python_write_config_dword
-};
-
-/*
- * Access functions for PCI config space using RTAS calls.
- */
-#define RTAS_PCI_READ_OP(size, type, nbytes)			    	  \
-int __chrp								  \
-rtas_read_config_##size(struct pci_dev *dev, int offset, type val) 	  \
-{									  \
-	unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
-		| ((dev->bus->number & 0xff) << 16);			  \
-	unsigned long ret = ~0UL;					  \
-	int rval;							  \
-									  \
-	rval = call_rtas("read-pci-config", 2, 2, &ret, addr, nbytes);	  \
-	*val = ret;							  \
-	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;    	  \
-}
-
-#define RTAS_PCI_WRITE_OP(size, type, nbytes)				  \
-int __chrp								  \
-rtas_write_config_##size(struct pci_dev *dev, int offset, type val)	  \
-{									  \
-	unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
-		| ((dev->bus->number & 0xff) << 16);			  \
-	int rval;							  \
-									  \
-	rval = call_rtas("write-pci-config", 3, 1, NULL,		  \
-			 addr, nbytes, (ulong)val);			  \
-	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;	  \
-}
-
-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)
-
-static struct pci_ops rtas_pci_ops =
-{
-	rtas_read_config_byte,
-	rtas_read_config_word,
-	rtas_read_config_dword,
-	rtas_write_config_byte,
-	rtas_write_config_word,
-	rtas_write_config_dword
-};
-
-    /*
-     *  Temporary fixes for PCI devices. These should be replaced by OF query
-     *  code -- Geert
-     */
-
-static u_char hydra_openpic_initsenses[] __initdata = {
-    1,	/* HYDRA_INT_SIO */
-    0,	/* HYDRA_INT_SCSI_DMA */
-    0,	/* HYDRA_INT_SCCA_TX_DMA */
-    0,	/* HYDRA_INT_SCCA_RX_DMA */
-    0,	/* HYDRA_INT_SCCB_TX_DMA */
-    0,	/* HYDRA_INT_SCCB_RX_DMA */
-    1,	/* HYDRA_INT_SCSI */
-    1,	/* HYDRA_INT_SCCA */
-    1,	/* HYDRA_INT_SCCB */
-    1,	/* HYDRA_INT_VIA */
-    1,	/* HYDRA_INT_ADB */
-    0,	/* HYDRA_INT_ADB_NMI */
-    	/* all others are 1 (= default) */
-};
-
-int __init
-hydra_init(void)
-{
-	struct device_node *np;
-
-	np = find_devices("mac-io");
-	if (np == NULL || np->n_addrs == 0) {
-		printk(KERN_WARNING "Warning: no mac-io found\n");
-		return 0;
-	}
-	Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
-	printk("Hydra Mac I/O at %x\n", np->addrs[0].address);
-	out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
-					   HYDRA_FC_SCSI_CELL_EN |
-					   HYDRA_FC_SCCA_ENABLE |
-					   HYDRA_FC_SCCB_ENABLE |
-					   HYDRA_FC_ARB_BYPASS |
-					   HYDRA_FC_MPIC_ENABLE |
-					   HYDRA_FC_SLOW_SCC_PCLK |
-					   HYDRA_FC_MPIC_IS_MASTER));
-	OpenPIC_Addr = &Hydra->OpenPIC;
-	OpenPIC_InitSenses = hydra_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof(hydra_openpic_initsenses);
-	return 1;
-}
-
-void __init
-chrp_pcibios_fixup(void)
-{
-	struct pci_dev *dev;
-	struct device_node *np;
-
-	/* PCI interrupts are controlled by the OpenPIC */
-	pci_for_each_dev(dev) {
-		np = pci_device_to_OF_node(dev);
-		if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0))
-			dev->irq = np->intrs[0].line;
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-	}
-}
-
-void __init
-chrp_find_bridges(void)
-{
-	struct device_node *dev;
-	int *bus_range;
-	int len, index = -1;
-	struct pci_controller *hose;
-	volatile unsigned char *cfg;
-	unsigned int *dma;
-	char *model, *machine;
-	int is_longtrail = 0, is_mot = 0;
-	struct device_node *root = find_path_device("/");
-#ifdef CONFIG_POWER3
-	unsigned int *opprop = (unsigned int *)
-		get_property(root, "platform-open-pic", NULL);
-	int i;
-#endif
-
-	/*
-	 * The PCI host bridge nodes on some machines don't have
-	 * properties to adequately identify them, so we have to
-	 * look at what sort of machine this is as well.
-	 */
-	machine = get_property(root, "model", NULL);
-	if (machine != NULL) {
-		is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
-		is_mot = strncmp(machine, "MOT", 3) == 0;
-	}
-	for (dev = root->child; dev != NULL; dev = dev->sibling) {
-		if (dev->type == NULL || strcmp(dev->type, "pci") != 0)
-			continue;
-		++index;
-		/* The GG2 bridge on the LongTrail doesn't have an address */
-		if (dev->n_addrs < 1 && !is_longtrail) {
-			printk(KERN_WARNING "Can't use %s: no address\n",
-			       dev->full_name);
-			continue;
-		}
-		bus_range = (int *) get_property(dev, "bus-range", &len);
-		if (bus_range == NULL || len < 2 * sizeof(int)) {
-			printk(KERN_WARNING "Can't get bus-range for %s\n",
-				dev->full_name);
-			continue;
-		}
-		if (bus_range[1] == bus_range[0])
-			printk(KERN_INFO "PCI bus %d", bus_range[0]);
-		else
-			printk(KERN_INFO "PCI buses %d..%d",
-			       bus_range[0], bus_range[1]);
-		printk(" controlled by %s", dev->type);
-		if (dev->n_addrs > 0)
-			printk(" at %x", dev->addrs[0].address);
-		printk("\n");
-
-		hose = pcibios_alloc_controller();
-		if (!hose) {
-			printk("Can't allocate PCI controller structure for %s\n",
-				dev->full_name);
-			continue;
-		}
-		hose->arch_data = dev;
-		hose->first_busno = bus_range[0];
-		hose->last_busno = bus_range[1];
-
-		model = get_property(dev, "model", NULL);
-		if (model == NULL)
-			model = "<none>";
-		if (device_is_compatible(dev, "IBM,python")) {
-			hose->ops = &python_pci_ops;
-			cfg = ioremap(dev->addrs[0].address + 0xf8000, 0x20);
-			hose->cfg_addr = (volatile unsigned int *) cfg;
-			hose->cfg_data = cfg + 0x10;
-		} else if (is_mot
-			   || strncmp(model, "Motorola, Grackle", 17) == 0) {
-			setup_grackle(hose);
-		} else if (is_longtrail) {
-			hose->ops = &gg2_pci_ops;
-			gg2_pci_config_base = (unsigned long)
-				ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
-		} else {
-			printk("No methods for %s (model %s), using RTAS\n",
-			       dev->full_name, model);
-			hose->ops = &rtas_pci_ops;
-		}
-
-		pci_process_bridge_OF_ranges(hose, dev, index == 0);
-
-#ifdef CONFIG_POWER3
-		if (opprop != NULL) {
-			i = prom_n_addr_cells(root) * (index + 2) - 1;
-			openpic_setup_ISU(index, opprop[i]);
-		}
-#endif /* CONFIG_POWER3 */
-
-		/* check the first bridge for a property that we can
-		   use to set pci_dram_offset */
-		dma = (unsigned int *)
-			get_property(dev, "ibm,dma-ranges", &len);
-		if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
-			pci_dram_offset = dma[2] - dma[3];
-			printk("pci_dram_offset = %lx\n", pci_dram_offset);
-		}
-	}
-
-	ppc_md.pcibios_fixup = chrp_pcibios_fixup;
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/chrp_setup.c linux-2.4.20-pre2/arch/ppc/kernel/chrp_setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/chrp_setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/chrp_setup.c	Wed Dec 31 16:00:00 1969
@@ -1,634 +0,0 @@
-/*
- * BK Id: SCCS/s.chrp_setup.c 1.42 04/09/02 21:43:09 paulus
- */
-/*
- *  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)
- */
-
-/*
- * 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/ide.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/gg2.h>
-#include <asm/pci-bridge.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-#include <asm/hydra.h>
-#include <asm/keyboard.h>
-#include <asm/sections.h>
-#include <asm/time.h>
-#include <asm/btext.h>
-
-#include "local_irq.h"
-#include "i8259.h"
-#include "open_pic.h"
-#include "xics.h"
-
-unsigned long chrp_get_rtc_time(void);
-int chrp_set_rtc_time(unsigned long nowtime);
-void chrp_calibrate_decr(void);
-long chrp_time_init(void);
-
-void chrp_find_bridges(void);
-void chrp_event_scan(void);
-void rtas_display_progress(char *, unsigned short);
-void rtas_indicator_progress(char *, unsigned short);
-void btext_progress(char *, unsigned short);
-
-extern unsigned long pmac_find_end_of_memory(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 select_adb_keyboard(void);
-extern int of_show_percpuinfo(struct seq_file *, int);
-
-extern kdev_t boot_dev;
-
-extern PTE *Hash, *Hash_end;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
-extern unsigned long loops_per_jiffy;
-static int max_width;
-
-#ifdef CONFIG_SMP
-extern struct smp_ops_t chrp_smp_ops;
-extern struct smp_ops_t xics_smp_ops;
-#endif
-
-static const char *gg2_memtypes[4] = {
-	"FPM", "SDRAM", "EDO", "BEDO"
-};
-static const char *gg2_cachesizes[4] = {
-	"256 KB", "512 KB", "1 MB", "Reserved"
-};
-static const char *gg2_cachetypes[4] = {
-	"Asynchronous", "Reserved", "Flow-Through Synchronous",
-	"Pipelined Synchronous"
-};
-static const char *gg2_cachemodes[4] = {
-	"Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
-};
-
-int __chrp
-chrp_show_cpuinfo(struct seq_file *m)
-{
-	int i, sdramen;
-	unsigned int t;
-	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);
-
-	/* longtrail (goldengate) stuff */
-	if (!strncmp(model, "IBM,LongTrail", 13)) {
-		/* VLSI VAS96011/12 `Golden Gate 2' */
-		/* Memory banks */
-		sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
-						GG2_PCI_DRAM_CTRL))
-			   >>31) & 1;
-		for (i = 0; i < (sdramen ? 4 : 6); i++) {
-			t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
-						 GG2_PCI_DRAM_BANK0+
-						 i*4));
-			if (!(t & 1))
-				continue;
-			switch ((t>>8) & 0x1f) {
-			case 0x1f:
-				model = "4 MB";
-				break;
-			case 0x1e:
-				model = "8 MB";
-				break;
-			case 0x1c:
-				model = "16 MB";
-				break;
-			case 0x18:
-				model = "32 MB";
-				break;
-			case 0x10:
-				model = "64 MB";
-				break;
-			case 0x00:
-				model = "128 MB";
-				break;
-			default:
-				model = "Reserved";
-				break;
-			}
-			seq_printf(m, "memory bank %d\t: %s %s\n", i, model,
-				   gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
-		}
-		/* L2 cache */
-		t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
-		seq_printf(m, "board l2\t: %s %s (%s)\n",
-			   gg2_cachesizes[(t>>7) & 3],
-			   gg2_cachetypes[(t>>2) & 3],
-			   gg2_cachemodes[t & 3]);
-	}
-	return 0;
-}
-
-/*
- *  Fixes for the National Semiconductor PC78308VUL SuperI/O
- *
- *  Some versions of Open Firmware incorrectly initialize the IRQ settings
- *  for keyboard and mouse
- */
-static inline void __init sio_write(u8 val, u8 index)
-{
-	outb(index, 0x15c);
-	outb(val, 0x15d);
-}
-
-static inline u8 __init sio_read(u8 index)
-{
-	outb(index, 0x15c);
-	return inb(0x15d);
-}
-
-static void __init sio_fixup_irq(const char *name, u8 device, u8 level,
-				     u8 type)
-{
-	u8 level0, type0, active;
-
-	/* select logical device */
-	sio_write(device, 0x07);
-	active = sio_read(0x30);
-	level0 = sio_read(0x70);
-	type0 = sio_read(0x71);
-	if (level0 != level || type0 != type || !active) {
-		printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: "
-		       "remapping to level %d, type %d, active\n",
-		       name, level0, type0, !active ? "in" : "", level, type);
-		sio_write(0x01, 0x30);
-		sio_write(level, 0x70);
-		sio_write(type, 0x71);
-	}
-}
-
-static void __init sio_init(void)
-{
-	struct device_node *root;
-
-	if ((root = find_path_device("/")) &&
-	    !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
-		/* logical device 0 (KBC/Keyboard) */
-		sio_fixup_irq("keyboard", 0, 1, 2);
-		/* select logical device 1 (KBC/Mouse) */
-		sio_fixup_irq("mouse", 1, 12, 2);
-	}
-}
-
-
-void __init
-chrp_setup_arch(void)
-{
-	struct device_node *device;
-
-	/* init to some ~sane value until calibrate_delay() runs */
-	loops_per_jiffy = 50000000/HZ;
-
-#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) */
-
-	/* Lookup PCI host bridges */
-	chrp_find_bridges();
-
-#ifndef CONFIG_PPC64BRIDGE
-	/*
-	 *  Temporary fixes for PCI devices.
-	 *  -- Geert
-	 */
-	hydra_init();		/* Mac I/O */
-
-#endif /* CONFIG_PPC64BRIDGE */
-
-	/* Some IBM machines don't have the hydra -- Cort */
-	if (!OpenPIC_Addr) {
-		struct device_node *root;
-		unsigned long *opprop;
-		int n;
-
-		root = find_path_device("/");
-		opprop = (unsigned long *) get_property
-			(root, "platform-open-pic", NULL);
-		n = prom_n_addr_cells(root);
-		if (opprop != 0) {
-			printk("OpenPIC addrs: %lx %lx %lx\n",
-			       opprop[n-1], opprop[2*n-1], opprop[3*n-1]);
-			OpenPIC_Addr = ioremap(opprop[n-1], 0x40000);
-		}
-	}
-
-	/*
-	 *  Fix the Super I/O configuration
-	 */
-	sio_init();
-
-	/*
-	 *  Setup the console operations
-	 */
-#ifdef CONFIG_DUMMY_CONSOLE
-	conswitchp = &dummy_con;
-#endif
-
-	/* Get the event scan rate for the rtas so we know how
-	 * often it expects a heartbeat. -- Cort
-	 */
-	if ( rtas_data ) {
-		struct property *p;
-		device = find_devices("rtas");
-		for ( p = device->properties;
-		      p && strncmp(p->name, "rtas-event-scan-rate", 20);
-		      p = p->next )
-			/* nothing */ ;
-		if ( p && *(unsigned long *)p->value ) {
-			ppc_md.heartbeat = chrp_event_scan;
-			ppc_md.heartbeat_reset = (HZ/(*(unsigned long *)p->value)*30)-1;
-			ppc_md.heartbeat_count = 1;
-			printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n",
-			       *(unsigned long *)p->value, ppc_md.heartbeat_reset );
-		}
-	}
-}
-
-void __chrp
-chrp_event_scan(void)
-{
-	unsigned char log[1024];
-	unsigned long ret = 0;
-	/* XXX: we should loop until the hardware says no more error logs -- Cort */
-	call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0,
-		   __pa(log), 1024 );
-	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
-}
-	
-void __chrp
-chrp_restart(char *cmd)
-{
-	printk("RTAS system-reboot returned %d\n",
-	       call_rtas("system-reboot", 0, 1, NULL));
-	for (;;);
-}
-
-void __chrp
-chrp_power_off(void)
-{
-	/* allow power on only with power button press */
-	printk("RTAS power-off returned %d\n",
-	       call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff));
-	for (;;);
-}
-
-void __chrp
-chrp_halt(void)
-{
-	chrp_power_off();
-}
-
-u_int __chrp
-chrp_irq_cannonicalize(u_int irq)
-{
-	if (irq == 2)
-		return 9;
-	return irq;
-}
-
-void __init chrp_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("Cannot find pci to get ack address\n");
-	else
-		chrp_int_ack_special = (unsigned char *)
-			ioremap(addrp[prom_n_addr_cells(np)-1], 1);
-	/* 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(0);
-#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
-	/* see if there is a keyboard in the device tree
-	   with a parent of type "adb" */
-	for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
-		if (kbd->parent && kbd->parent->type
-		    && strcmp(kbd->parent->type, "adb") == 0)
-			break;
-	if (kbd)
-		request_irq( HYDRA_INT_ADB_NMI, xmon_irq, 0, "XMON break", 0);
-#endif
-}
-
-void __init
-chrp_init2(void)
-{
-#ifdef CONFIG_NVRAM  
-	pmac_nvram_init();
-#endif
-
-	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");
-
-	if (ppc_md.progress)
-		ppc_md.progress("  Have fun!    ", 0x7777);
-
-#if defined(CONFIG_VT) && (defined(CONFIG_ADB_KEYBOARD) || defined(CONFIG_INPUT))
-	/* see if there is a keyboard in the device tree
-	   with a parent of type "adb" */
-	{
-		struct device_node *kbd;
-
-		for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) {
-			if (kbd->parent && kbd->parent->type
-			    && strcmp(kbd->parent->type, "adb") == 0) {
-				select_adb_keyboard();
-				break;
-			}
-		}
-	}
-#endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
-}
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-
-static int __chrp
-chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-        return check_region(from, extent);
-}
-
-static void __chrp
-chrp_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-        request_region(from, extent, name);
-}
-
-static void __chrp
-chrp_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-        release_region(from, extent);
-}
-
-static void __chrp
-chrp_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;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-}
-#endif
-
-/*
- * One of the main thing these mappings are needed for is so that
- * xmon can get to the serial port early on.  We probably should
- * handle the machines with the mpc106 as well as the python (F50)
- * and the GG2 (longtrail).  Actually we should look in the device
- * tree and do the right thing.
- */
-static void __init
-chrp_map_io(void)
-{
-	char *name;
-
-	/*
-	 * The code below tends to get removed, please don't take it out.
-	 * The F50 needs this mapping and it you take it out I'll track you
-	 * down and slap your hands.  If it causes problems please email me.
-	 *  -- Cort <cort@fsmlabs.com>
-	 */
-	name = get_property(find_path_device("/"), "name", NULL);
-	if (name && strncmp(name, "IBM-70", 6) == 0
-	    && strstr(name, "-F50")) {
-		io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
-		io_block_mapping(0x90000000, 0x90000000, 0x10000000, _PAGE_IO);
-		return;
-	} else {
-		io_block_mapping(0xf8000000, 0xf8000000, 0x04000000, _PAGE_IO);
-	}
-}
-
-void __init
-chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	  unsigned long r6, unsigned long r7)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* take care of initrd if we have one */
-	if ( r6 )
-	{
-		initrd_start = r6 + KERNELBASE;
-		initrd_end = r6 + r7 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	ISA_DMA_THRESHOLD = ~0L;
-	DMA_MODE_READ = 0x44;
-	DMA_MODE_WRITE = 0x48;
-	isa_io_base = CHRP_ISA_IO_BASE;		/* default value */
-
-	ppc_md.setup_arch     = chrp_setup_arch;
-	ppc_md.show_percpuinfo = of_show_percpuinfo;
-	ppc_md.show_cpuinfo   = chrp_show_cpuinfo;
-	ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
-#ifndef CONFIG_POWER4
-	ppc_md.init_IRQ       = chrp_init_IRQ;
-	ppc_md.get_irq        = openpic_get_irq;
-#else
-	ppc_md.init_IRQ	      = xics_init_IRQ;
-	ppc_md.get_irq	      = xics_get_irq;
-#endif /* CONFIG_POWER4 */
-
-	ppc_md.init           = chrp_init2;
-
-	ppc_md.restart        = chrp_restart;
-	ppc_md.power_off      = chrp_power_off;
-	ppc_md.halt           = chrp_halt;
-
-	ppc_md.time_init      = chrp_time_init;
-	ppc_md.set_rtc_time   = chrp_set_rtc_time;
-	ppc_md.get_rtc_time   = chrp_get_rtc_time;
-	ppc_md.calibrate_decr = chrp_calibrate_decr;
-
-	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
-	ppc_md.setup_io_mappings = chrp_map_io;
-
-#ifdef CONFIG_VT
-	/* these are adjusted in chrp_init2 if we have an ADB keyboard */
-	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 = 0x54;
-#endif /* CONFIG_MAGIC_SYSRQ */
-#endif /* CONFIG_VT */
-
-	if (rtas_data) {
-		struct device_node *rtas;
-		unsigned int *p;
-
-		rtas = find_devices("rtas");
-		if (rtas != NULL) {
-			if (get_property(rtas, "display-character", NULL)) {
-				ppc_md.progress = rtas_display_progress;
-				p = (unsigned int *) get_property
-				       (rtas, "ibm,display-line-length", NULL);
-				if (p)
-					max_width = *p;
-			} else if (get_property(rtas, "set-indicator", NULL))
-				ppc_md.progress = rtas_indicator_progress;
-		}
-	}
-#ifdef CONFIG_BOOTX_TEXT
-	if (ppc_md.progress == NULL && boot_text_mapped)
-		ppc_md.progress = btext_progress;
-#endif
-
-#ifdef CONFIG_SMP
-#ifndef CONFIG_POWER4
-	ppc_md.smp_ops = &chrp_smp_ops;
-#else
-	ppc_md.smp_ops = &xics_smp_ops;
-#endif /* CONFIG_POWER4 */
-#endif /* CONFIG_SMP */
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region = chrp_ide_check_region;
-        ppc_ide_md.ide_request_region = chrp_ide_request_region;
-        ppc_ide_md.ide_release_region = chrp_ide_release_region;
-        ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
-#endif
-
-	/*
-	 * Print the banner, then scroll down so boot progress
-	 * can be printed.  -- Cort 
-	 */
-	if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
-}
-
-void __chrp
-rtas_display_progress(char *s, unsigned short hex)
-{
-	int width;
-	char *os = s;
-
-	if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) )
-		return;
-
-	width = max_width;
-	while ( *os )
-	{
-		if ( (*os == '\n') || (*os == '\r') )
-			width = max_width;
-		else
-			width--;
-		call_rtas( "display-character", 1, 1, NULL, *os++ );
-		/* if we overwrite the screen length */
-		if ( width == 0 )
-			while ( (*os != 0) && (*os != '\n') && (*os != '\r') )
-				os++;
-	}
-
-	/*while ( width-- > 0 )*/
-	call_rtas( "display-character", 1, 1, NULL, ' ' );
-}
-
-void __chrp
-rtas_indicator_progress(char *s, unsigned short hex)
-{
-	call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex);
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-void
-btext_progress(char *s, unsigned short hex)
-{
-	prom_print(s);
-	prom_print("\n");
-}
-#endif /* CONFIG_BOOTX_TEXT */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/chrp_smp.c linux-2.4.20-pre2/arch/ppc/kernel/chrp_smp.c
--- linux-2.4.20-pre1/arch/ppc/kernel/chrp_smp.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/chrp_smp.c	Wed Dec 31 16:00:00 1969
@@ -1,148 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * Smp support for CHRP machines.
- *
- * 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>
- *
- */
-
-#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/spinlock.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/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/residual.h>
-#include <asm/time.h>
-
-#include "open_pic.h"
-
-extern unsigned long smp_chrp_cpu_nr;
-
-static int __init
-smp_chrp_probe(void)
-{
-	if (smp_chrp_cpu_nr > 1)
-		openpic_request_IPIs();
-
-	return smp_chrp_cpu_nr;
-}
-
-static void __init
-smp_chrp_kick_cpu(int nr)
-{
-	*(unsigned long *)KERNELBASE = nr;
-	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-}
-
-static void __init
-smp_chrp_setup_cpu(int cpu_nr)
-{
-	static atomic_t ready = ATOMIC_INIT(1);
-	static volatile int frozen = 0;
-
-	if (cpu_nr == 0) {
-		/* wait for all the others */
-		while (atomic_read(&ready) < smp_num_cpus)
-			barrier();
-		atomic_set(&ready, 1);
-		/* freeze the timebase */
-		call_rtas("freeze-time-base", 0, 1, NULL);
-		mb();
-		frozen = 1;
-		/* XXX assumes this is not a 601 */
-		set_tb(0, 0);
-		last_jiffy_stamp(0) = 0;
-		while (atomic_read(&ready) < smp_num_cpus)
-			barrier();
-		/* thaw the timebase again */
-		call_rtas("thaw-time-base", 0, 1, NULL);
-		mb();
-		frozen = 0;
-		smp_tb_synchronized = 1;
-	} else {
-		atomic_inc(&ready);
-		while (!frozen)
-			barrier();
-		set_tb(0, 0);
-		last_jiffy_stamp(0) = 0;
-		mb();
-		atomic_inc(&ready);
-		while (frozen)
-			barrier();
-	}
-
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-}
-
-#ifdef CONFIG_POWER4
-static void __chrp
-smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	/* for now, only do reschedule messages
-	   since we only have one IPI */
-	if (msg != PPC_MSG_RESCHEDULE)
-		return;
-	for (i = 0; i < smp_num_cpus; ++i) {
-		if (target == MSG_ALL || target == i
-		    || (target == MSG_ALL_BUT_SELF
-			&& i != smp_processor_id()))
-			xics_cause_IPI(i);
-	}
-}
-
-static int __chrp
-smp_xics_probe(void)
-{
-	return smp_chrp_cpu_nr;
-}
-
-static void __chrp
-smp_xics_setup_cpu(int cpu_nr)
-{
-	if (cpu_nr > 0)
-		xics_setup_cpu();
-}
-#endif /* CONFIG_POWER4 */
-
-/* CHRP with openpic */
-struct smp_ops_t chrp_smp_ops __chrpdata = {
-	smp_openpic_message_pass,
-	smp_chrp_probe,
-	smp_chrp_kick_cpu,
-	smp_chrp_setup_cpu,
-};
-
-#ifdef CONFIG_POWER4
-/* CHRP with new XICS interrupt controller */
-struct smp_ops_t xics_smp_ops __chrpdata = {
-	smp_xics_message_pass,
-	smp_xics_probe,
-	smp_chrp_kick_cpu,
-	smp_xics_setup_cpu,
-};
-#endif /* CONFIG_POWER4 */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/chrp_time.c linux-2.4.20-pre2/arch/ppc/kernel/chrp_time.c
--- linux-2.4.20-pre1/arch/ppc/kernel/chrp_time.c	Sat Sep  8 12:38:41 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/chrp_time.c	Wed Dec 31 16:00:00 1969
@@ -1,195 +0,0 @@
-/*
- * BK Id: SCCS/s.chrp_time.c 1.10 09/08/01 15:47:42 paulus
- */
-/*
- *  linux/arch/i386/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * Adapted for PowerPC (PreP) by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- *  copied and modified from intel version
- *
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/kernel_stat.h>
-#include <linux/mc146818rtc.h>
-#include <linux/init.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/nvram.h>
-#include <asm/prom.h>
-#include <asm/sections.h>
-#include <asm/time.h>
-
-extern spinlock_t rtc_lock;
-
-static int nvram_as1 = NVRAM_AS1;
-static int nvram_as0 = NVRAM_AS0;
-static int nvram_data = NVRAM_DATA;
-
-long __init chrp_time_init(void)
-{
-	struct device_node *rtcs;
-	int base;
-
-	rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
-	if (rtcs == NULL || rtcs->addrs == NULL)
-		return 0;
-	base = rtcs->addrs[0].address;
-	nvram_as1 = 0;
-	nvram_as0 = base;
-	nvram_data = base + 1;
-	
-	return 0;
-}
-
-int __chrp chrp_cmos_clock_read(int addr)
-{
-	if (nvram_as1 != 0)
-		outb(addr>>8, nvram_as1);
-	outb(addr, nvram_as0);
-	return (inb(nvram_data));
-}
-
-void __chrp chrp_cmos_clock_write(unsigned long val, int addr)
-{
-	if (nvram_as1 != 0)
-		outb(addr>>8, nvram_as1);
-	outb(addr, nvram_as0);
-	outb(val, nvram_data);
-	return;
-}
-
-/*
- * Set the hardware clock. -- Cort
- */
-int __chrp chrp_set_rtc_time(unsigned long nowtime)
-{
-	unsigned char save_control, save_freq_select;
-	struct rtc_time tm;
-
-	spin_lock(&rtc_lock);
-	to_tm(nowtime, &tm);
-
-	save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
-
-	chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
-
-	save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
-	
-	chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-        tm.tm_year -= 1900;
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BIN_TO_BCD(tm.tm_sec);
-		BIN_TO_BCD(tm.tm_min);
-		BIN_TO_BCD(tm.tm_hour);
-		BIN_TO_BCD(tm.tm_mon);
-		BIN_TO_BCD(tm.tm_mday);
-		BIN_TO_BCD(tm.tm_year);
-	}
-	chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
-	chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
-	chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS);
-	chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH);
-	chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
-	chrp_cmos_clock_write(tm.tm_year,RTC_YEAR);
-	
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	chrp_cmos_clock_write(save_control, RTC_CONTROL);
-	chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
-
-	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
-		time_state = TIME_OK;
-	spin_unlock(&rtc_lock);
-	return 0;
-}
-
-unsigned long __chrp chrp_get_rtc_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	int uip, i;
-
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-
-	/* Since the UIP flag is set for about 2.2 ms and the clock
-	 * is typically written with a precision of 1 jiffy, trying
-	 * to obtain a precision better than a few milliseconds is 
-	 * an illusion. Only consistency is interesting, this also
-	 * allows to use the routine for /dev/rtc without a potential
-	 * 1 second kernel busy loop triggered by any reader of /dev/rtc. 
-	 */
-
-	for ( i = 0; i<1000000; i++) {
-		uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
-		sec = chrp_cmos_clock_read(RTC_SECONDS);
-		min = chrp_cmos_clock_read(RTC_MINUTES);
-		hour = chrp_cmos_clock_read(RTC_HOURS);
-		day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
-		mon = chrp_cmos_clock_read(RTC_MONTH);
-		year = chrp_cmos_clock_read(RTC_YEAR);
-		uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
-		if ((uip & RTC_UIP)==0) break;
-	}
-
-	if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	  {
-	    BCD_TO_BIN(sec);
-	    BCD_TO_BIN(min);
-	    BCD_TO_BIN(hour);
-	    BCD_TO_BIN(day);
-	    BCD_TO_BIN(mon);
-	    BCD_TO_BIN(year);
-	  }
-	if ((year += 1900) < 1970)
-		year += 100;
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-
-void __init chrp_calibrate_decr(void)
-{
-	struct device_node *cpu;
-	unsigned int freq, *fp;
-
-	if (via_calibrate_decr())
-		return;
-
-	/*
-	 * 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 = (unsigned int *)
-			get_property(cpu, "timebase-frequency", NULL);
-		if (fp != 0)
-			freq = *fp;
-	}
-	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
- 	       freq/1000000, freq%1000000);
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/cputable.c linux-2.4.20-pre2/arch/ppc/kernel/cputable.c
--- linux-2.4.20-pre1/arch/ppc/kernel/cputable.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/cputable.c	Mon Aug 12 16:34:14 2002
@@ -189,7 +189,7 @@
     {	/* 7450 2.0 - no doze/nap */
     	0xffffffff, 0x80000200, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
@@ -198,7 +198,7 @@
     {	/* 7450 2.1 */
     	0xffffffff, 0x80000201, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
@@ -207,7 +207,7 @@
     {	/* 7450 2.3 and newer */
     	0xffff0000, 0x80000000, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
@@ -216,7 +216,7 @@
     {	/* 7455 */
     	0xffff0000, 0x80010000, "7455",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/entry.S linux-2.4.20-pre2/arch/ppc/kernel/entry.S
--- linux-2.4.20-pre1/arch/ppc/kernel/entry.S	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/entry.S	Mon Aug 12 16:34:14 2002
@@ -22,7 +22,6 @@
  *	
  */
 
-#include "ppc_asm.h"
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sys.h>
@@ -31,6 +30,8 @@
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 #undef SHOW_SYSCALLS
 #undef SHOW_SYSCALLS_TASK
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/error_log.c linux-2.4.20-pre2/arch/ppc/kernel/error_log.c
--- linux-2.4.20-pre1/arch/ppc/kernel/error_log.c	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/error_log.c	Wed Dec 31 16:00:00 1969
@@ -1,186 +0,0 @@
-/*
- * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort
- */
-/*
- *  arch/ppc/kernel/error_log.c
- *  
- *  Copyright (c) 2000 Tilmann Bitterberg
- *  (tilmann@bitterberg.de)
- *
- *  Error processing of errors found by rtas even-scan routine
- *  which is done with every heartbeat. (chrp_setup.c)
- */
-
-#include <linux/sched.h>
-
-#include <asm/prom.h>
-
-#include "error_log.h"
-
-/* ****************************************************************** */
-/* 
- * EVENT-SCAN
- * The whole stuff below here doesn't take any action when it found
- * an error, it just prints as much information as possible and 
- * then its up to the user to decide what to do.
- *
- * Returns 0 if no errors were found
- * Returns 1 if there may be more errors
- */
-int ppc_rtas_errorlog_scan(void)
-{
-const char *_errlog_severity[] = {
-#ifdef VERBOSE_ERRORS
-	"No Error\n\t\
-Should require no further information",
-	"Event\n\t\
-This is not really an error, it is an event. I use events\n\t\
-to communicate with RTAS back and forth.",
-	"Warning\n\t\
-Indicates a non-state-losing error, either fully recovered\n\t\
-by RTAS or not needing recovery. Ignore it.",
-	"Error sync\n\t\
-May only be fatal to a certain program or thread. Recovery\n\t\
-and continuation is possible, if I only had a handler for\n\t\
-this. Less serious",
-	"Error\n\t\
-Less serious, but still causing a loss of data and state.\n\t\
-I can't tell you exactly what to do, You have to decide\n\t\
-with help from the target and initiator field, what kind\n\t\
-of further actions may take place.",
-	"Fatal\n\t\
-Represent a permanent hardware failure and I believe this\n\t\
-affects my overall performance and behaviour. I would not\n\t\
-attempt to continue normal operation."
-#else
-	"No Error",
-	"Event",
-	"Warning",
-	"Error sync",
-	"Error",
-	"Fatal"
-#endif /* VERBOSE_ERRORS */
-};
-
-#if 0 /* unused?? */
-const char *_errlog_disposition[] = {
-#ifdef VERBOSE_ERRORS
-	"Fully recovered\n\t\
-There was an error, but it is fully recovered by RTAS.",
-	"Limited recovery\n\t\
-RTAS was able to recover the state of the machine, but some\n\t\
-feature of the machine has been disabled or lost (for example\n\t\
-error checking) or performance may suffer.",
-	"Not recovered\n\t\
-Whether RTAS did not try to recover anything or recovery failed:\n\t\
-HOUSTON, WE HAVE A PROBLEM!"
-#else
-	"Fully recovered",
-	"Limited recovery",
-	"Not recovered"
-#endif /* VERBOSE_ERRORS */
-};
-#endif
-
-const char *_errlog_extended[] = {
-#ifdef VERBOSE_ERRORS
-	"Not present\n\t\
-Sad, the RTAS call didn't return an extended error log.",
-	"Present\n\t\
-The extended log is present and hopefully it contains a lot of\n\t\
-useful information, which leads to the solution of the problem."
-#else
-	"Not present",
-	"Present"
-#endif /* VERBOSE_ERRORS */
-};
-
-const char *_errlog_initiator[] = { 
-	"Unknown or not applicable",
-	"CPU",
-	"PCI",
-	"ISA",
-	"Memory",
-	"Power management"
-};
-
-const char *_errlog_target[] = { 
-	"Unknown or not applicable",
-	"CPU",
-	"PCI",
-	"ISA",
-	"Memory",
-	"Power management"
-};
-	rtas_error_log error_log;
-	char logdata[1024];
-	int error;
-#if 0 /* unused?? */
-	int retries = 0; /* if HW error, try 10 times */
-#endif
-
-	error = call_rtas ("event-scan", 4, 1, (unsigned long *)&error_log,
-			INTERNAL_ERROR | EPOW_WARNING,
-			0, __pa(logdata), 1024);
-
-	if (error == 1) /* no errors found */
-		return 0;
-
-	if (error == -1) {
-		printk(KERN_ERR "Unable to get errors. Do you a favor and throw this box away\n");
-		return 0;
-	}
-	if (error_log.version != 1)
-		printk(KERN_WARNING "Unknown version (%d), please implement me\n", 
-				error_log.version);
-
-	switch (error_log.disposition) {
-		case DISP_FULLY_RECOVERED:
-			/* there was an error, but everything is fine now */
-			return 0;
-		case DISP_NOT_RECOVERED:
-			printk("We have a really serious Problem!\n");
-		case DISP_LIMITED_RECOVERY:
-			printk("Error classification\n");
-			printk("Severity  : %s\n", 
-					ppc_rtas_errorlog_check_severity (error_log));
-			printk("Initiator : %s\n", 
-					ppc_rtas_errorlog_check_initiator (error_log));
-			printk("Target    : %s\n", 
-					ppc_rtas_errorlog_check_target (error_log));
-			printk("Type      : %s\n", 
-					ppc_rtas_errorlog_check_type (error_log));
-			printk("Ext. log  : %s\n", 
-					ppc_rtas_errorlog_check_extended (error_log));
-			if (error_log.extended)
-				ppc_rtas_errorlog_disect_extended (logdata);
-			return 1;	
-		default:
-			/* nothing */
-			break;
-	}
-	return 0;
-}
-/* ****************************************************************** */
-const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log)
-{
-	const char *_errlog_type[] = {
-		"unknown type",
-		"too many tries failed",
-		"TCE error",
-		"RTAS device failed",
-		"target timed out",
-		"parity error on data",			/* 5 */
-		"parity error on address",
-		"parity error on external cache",
-		"access to invalid address",
-		"uncorrectable ECC error",
-		"corrected ECC error"			/* 10 */
-	};
-	if (error_log.type == TYPE_EPOW) 
-		return "EPOW"; 
-	if (error_log.type >= TYPE_PMGM_POWER_SW_ON)
-		return "PowerMGM Event (not handled right now)";
-	return _errlog_type[error_log.type];
-}
-
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/error_log.h linux-2.4.20-pre2/arch/ppc/kernel/error_log.h
--- linux-2.4.20-pre1/arch/ppc/kernel/error_log.h	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/error_log.h	Wed Dec 31 16:00:00 1969
@@ -1,98 +0,0 @@
-/*
- * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort
- */
-#ifndef __ERROR_LOG_H__
-#define __ERROR_LOG_H__
-
-#define VERBOSE_ERRORS		1 /* Maybe I enlarge the kernel too much */
-#undef VERBOSE_ERRORS
-
-/* Event classes */
-/* XXX: Endianess correct? NOW*/
-#define INTERNAL_ERROR		0x80000000 /* set bit 0 */
-#define EPOW_WARNING		0x40000000 /* set bit 1 */
-#define POWERMGM_EVENTS		0x20000000 /* set bit 2 */
-
-/* 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
-
-typedef 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 */
-} rtas_error_log;
-
-/* ****************************************************************** */
-#define ppc_rtas_errorlog_check_severity(x) \
-	(_errlog_severity[x.severity])
-#define ppc_rtas_errorlog_check_target(x) \
-	(_errlog_target[x.target])
-#define ppc_rtas_errorlog_check_initiator(x) \
-	(_errlog_initiator[x.initiator])
-#define ppc_rtas_errorlog_check_extended(x) \
-	(_errlog_extended[x.extended])
-#define ppc_rtas_errorlog_disect_extended(x) \
-	do { /* implement me */ } while(0)
-extern const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log);
-extern int ppc_rtas_errorlog_scan(void);
-
-
-#endif /* __ERROR_LOG_H__ */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/galaxy_pci.c linux-2.4.20-pre2/arch/ppc/kernel/galaxy_pci.c
--- linux-2.4.20-pre1/arch/ppc/kernel/galaxy_pci.c	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/galaxy_pci.c	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.galaxy_pci.c 1.7 05/17/01 18:14:21 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *
@@ -27,8 +27,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
-
-#include "pci.h"
+#include <asm/pci-bridge.h>
 
 
 /* Preprocessor Defines */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/gemini_pci.c linux-2.4.20-pre2/arch/ppc/kernel/gemini_pci.c
--- linux-2.4.20-pre1/arch/ppc/kernel/gemini_pci.c	Fri Nov  2 17:43:54 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/gemini_pci.c	Wed Dec 31 16:00:00 1969
@@ -1,124 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini_pci.c 1.6 10/11/01 08:51:46 trini
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/machdep.h>
-#include <asm/gemini.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pci-bridge.h>
-
-#include "pci.h"
-
-#define pci_config_addr(bus,dev,offset) \
-        (0x80000000 | (bus<<16) | (dev<<8) | offset)
-
-
-int
-gemini_pcibios_read_config_byte(struct pci_dev *dev, int offset, u8 *val)
-{
-	unsigned long reg;
-	reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
-					   (offset & ~(0x3))));
-	*val = ((reg >> ((offset & 0x3) << 3)) & 0xff);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_read_config_word(struct pci_dev *dev, int offset, u16 *val)
-{
-	unsigned long reg;
-	reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
-					   (offset & ~(0x3))));
-	*val = ((reg >> ((offset & 0x3) << 3)) & 0xffff);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_read_config_dword(struct pci_dev *dev, int offset, u32 *val)
-{
-	*val = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
-					    (offset & ~(0x3))));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_write_config_byte(struct pci_dev *dev, int offset, u8 val)
-{
-	unsigned long reg;
-	int shifts = offset & 0x3;
-	unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn,
-					    (offset & ~(0x3)));
-
-	reg = grackle_read(addr);
-	reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3));
-	grackle_write(addr, reg );
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_write_config_word(struct pci_dev *dev, int offset, u16 val)
-{
-	unsigned long reg;
-	int shifts = offset & 0x3;
-	unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn,
-					    (offset & ~(0x3)));
-
-	reg = grackle_read(addr);
-	reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3));
-	grackle_write(addr, reg );
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-gemini_pcibios_write_config_dword(struct pci_dev *dev, int offset, u32 val)
-{
-	grackle_write(pci_config_addr(dev->bus->number, dev->devfn,
-				      (offset & ~(0x3))), val);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops gemini_pci_ops =
-{
-	gemini_pcibios_read_config_byte,
-	gemini_pcibios_read_config_word,
-	gemini_pcibios_read_config_dword,
-	gemini_pcibios_write_config_byte,
-	gemini_pcibios_write_config_word,
-	gemini_pcibios_write_config_dword
-};
-
-void __init gemini_pcibios_fixup(void)
-{
-	int i;
-	struct pci_dev *dev;
-	
-	pci_for_each_dev(dev) {
-		for(i = 0; i < 6; i++) {
-			if (dev->resource[i].flags & IORESOURCE_IO) {
-				dev->resource[i].start |= (0xfe << 24);
-				dev->resource[i].end |= (0xfe << 24);
-			}
-		}
-	}
-}
-
-
-/* The "bootloader" for Synergy boards does none of this for us, so we need to
-   lay it all out ourselves... --Dan */
-void __init gemini_find_bridges(void)
-{
-	struct pci_controller* hose;
-	
-	ppc_md.pcibios_fixup = gemini_pcibios_fixup;
-
-	hose = pcibios_alloc_controller();
-	if (!hose)
-		return;
-	hose->ops = &gemini_pci_ops;
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/gemini_prom.S linux-2.4.20-pre2/arch/ppc/kernel/gemini_prom.S
--- linux-2.4.20-pre1/arch/ppc/kernel/gemini_prom.S	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/gemini_prom.S	Wed Dec 31 16:00:00 1969
@@ -1,99 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini_prom.S 1.5 05/17/01 18:14:21 cort
- */
-/*
- *  arch/ppc/kernel/gemini_prom.S
- *
- *  Not really prom support code (yet), but sort of anti-prom code.  The current
- *  bootloader does a number of things it shouldn't and doesn't do things that it
- *  should.  The stuff in here is mainly a hodge-podge collection of setup code
- *  to get the board up and running.
- *    ---Dan
- */
-
-#include "ppc_asm.tmpl"
-#include "ppc_defs.h"
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/gemini.h>
-
-#define HID0_ABE (1<<3)
-
-/*
- *  On 750's the MMU is on when Linux is booted, so we need to clear out the
- *  bootloader's BAT settings, make sure we're in supervisor state (gotcha!),
- *  and turn off the MMU.
- *
- */
-
-_GLOBAL(gemini_prom_init)
-#ifdef CONFIG_SMP
-	/* Since the MMU's on, get stuff in rom space that we'll need */
-	lis	r4,GEMINI_CPUSTAT@h
-	ori	r4,r4,GEMINI_CPUSTAT@l
-	lbz	r5,0(r4)
-	andi.	r5,r5,3
-	mr	r24,r5		/* cpu # used later on */
-#endif
-	mfmsr	r4
-	li	r3,MSR_PR	/* ensure supervisor! */
-	ori	r3,r3,MSR_IR|MSR_DR
-	andc	r4,r4,r3
-	mtmsr	r4
-	isync
-#if 0
-	/* zero out the bats now that the MMU is off */
-prom_no_mmu:	
-	li	r3,0
-        mtspr   IBAT0U,r3
-        mtspr   IBAT0L,r3
-        mtspr   IBAT1U,r3
-        mtspr   IBAT1L,r3
-        mtspr   IBAT2U,r3
-        mtspr   IBAT2L,r3
-        mtspr   IBAT3U,r3
-        mtspr   IBAT3L,r3
-
-        mtspr   DBAT0U,r3
-        mtspr   DBAT0L,r3
-        mtspr   DBAT1U,r3
-        mtspr   DBAT1L,r3
-        mtspr   DBAT2U,r3
-	mtspr   DBAT2L,r3
-        mtspr   DBAT3U,r3
-        mtspr   DBAT3L,r3
-#endif
-
-	/* the bootloader (as far as I'm currently aware) doesn't mess with page
-	   tables, but since we're already here, might as well zap these, too */
-	li	r4,0
-	mtspr	SDR1,r4
-
-	li	r4,16
-	mtctr	r4
-	li	r3,0
-	li	r4,0
-3:	mtsrin	r3,r4
-	addi	r3,r3,1
-	bdnz	3b
-
-#ifdef CONFIG_SMP
-	/* The 750 book (and Mot/IBM support) says that this will "assist" snooping
-	   when in SMP.  Not sure yet whether this should stay or leave... */
-	mfspr	r4,HID0
-	ori	r4,r4,HID0_ABE
-	mtspr	HID0,r4
-	sync
-#endif /* CONFIG_SMP */
-	blr
-
-/*  apparently, SMon doesn't pay attention to HID0[SRST].  Disable the MMU and
-    branch to 0xfff00100 */
-_GLOBAL(_gemini_reboot)
-	lis	r5,GEMINI_BOOT_INIT@h
-	ori	r5,r5,GEMINI_BOOT_INIT@l
-	li	r6,MSR_IP
-	mtspr	SRR0,r5
-	mtspr	SRR1,r6
-	rfi
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/gemini_setup.c linux-2.4.20-pre2/arch/ppc/kernel/gemini_setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/gemini_setup.c	Fri Nov 16 10:10:08 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/gemini_setup.c	Wed Dec 31 16:00:00 1969
@@ -1,584 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini_setup.c 1.14 10/18/01 11:16:28 trini
- */
-/*
- *  linux/arch/ppc/kernel/setup.c
- *
- *  Copyright (C) 1995 Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- *  Synergy Microsystems board support by Dan Cox (dan@synergymicro.com)
- *
- */
-
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h> 
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/time.h>
-#include <linux/kdev_t.h>
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/blk.h>
-#include <linux/console.h>
-#include <linux/seq_file.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/m48t35.h>
-#include <asm/gemini.h>
-#include <asm/time.h>
-
-#include "local_irq.h"
-#include "open_pic.h"
-
-void gemini_find_bridges(void);
-static int gemini_get_clock_speed(void);
-extern void gemini_pcibios_fixup(void);
-
-static char *gemini_board_families[] = {
-  "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR"
-};
-static int gemini_board_count = sizeof(gemini_board_families) /
-                                 sizeof(gemini_board_families[0]);
-
-static unsigned int cpu_7xx[16] = {
-	0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
-};
-static unsigned int cpu_6xx[16] = {
-	0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
-};
-
-/*
- * prom_init is the Gemini version of prom.c:prom_init.  We only need
- * the BSS clearing code, so I copied that out of prom.c.  This is a
- * lot simpler than hacking prom.c so it will build with Gemini. -VAL
- */
-
-#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
-
-unsigned long
-prom_init(void)
-{
-	unsigned long offset = reloc_offset();
-	unsigned long phys;
-	extern char __bss_start, _end;
-
-	/* First zero the BSS -- use memset, some arches don't have
-	 * caches on yet */
-	memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start);
-
- 	/* Default */
- 	phys = offset + KERNELBASE;
-
-	gemini_prom_init();
-
-	return phys;
-}
-
-int
-gemini_show_cpuinfo(struct seq_file *m)
-{
-	unsigned char reg, rev;
-	char *family;
-	unsigned int type;
-
-	reg = readb(GEMINI_FEAT);
-	family = gemini_board_families[((reg>>4) & 0xf)];
-	if (((reg>>4) & 0xf) > gemini_board_count)
-		printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
-
-	reg = readb(GEMINI_BREV);
-	type = (reg>>4) & 0xf;
-	rev = reg & 0xf;
-
-	reg = readb(GEMINI_BECO);
-
-	seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", 
-		   family, type, (rev + 'A'), (reg & 0xf));
-
-	seq_printf(m, "board\t\t: Gemini %s", family);
-	if (type > 9)
-		seq_printf(m, "%c", (type - 10) + 'A');
-	else
-		seq_printf(m, "%d", type);
-
-	seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf));
-
-	seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed());
-
-	return 0;
-}
-
-static u_char gemini_openpic_initsenses[] = {
-	1,
-	1,
-	1,
-	1,
-	0,
-	0,
-	1, /* remainder are level-triggered */
-};
-
-#define GEMINI_MPIC_ADDR (0xfcfc0000)
-#define GEMINI_MPIC_PCI_CFG (0x80005800)
-
-void __init gemini_openpic_init(void)
-{
-
-	OpenPIC_Addr = (volatile struct OpenPIC *)
-		grackle_read(GEMINI_MPIC_PCI_CFG + 0x10);
-	OpenPIC_InitSenses = gemini_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
-
-	ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE);
-}
-
-
-extern unsigned long loops_per_jiffy;
-extern int root_mountflags;
-extern char cmd_line[];
-
-void
-gemini_heartbeat(void)
-{
-	static unsigned long led = GEMINI_LEDBASE+(4*8);
-	static char direction = 8;
-
-	/* We only want to do this on 1 CPU */
-	if (smp_processor_id())
-		return;
-	*(char *)led = 0;
-	if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) ||
-	     (led + direction) < (GEMINI_LEDBASE+(4*8)) )
-		direction *= -1;
-	led += direction;
-	*(char *)led = 0xff;
-	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
-}
-
-void __init gemini_setup_arch(void)
-{
-	extern char cmd_line[];
-
-
-	loops_per_jiffy = 50000000/HZ;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* bootable off CDROM */
-	if (initrd_start)
-		ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0);
-	else
-#endif
-		ROOT_DEV = to_kdev_t(0x0801);
-
-	/* nothing but serial consoles... */
-	sprintf(cmd_line, "%s console=ttyS0", cmd_line);
-
-	printk("Boot arguments: %s\n", cmd_line);
-
-	ppc_md.heartbeat = gemini_heartbeat;
-	ppc_md.heartbeat_reset = HZ/8;
-	ppc_md.heartbeat_count = 1;
-	
-	/* Lookup PCI hosts */
-	gemini_find_bridges();
-	/* take special pains to map the MPIC, since it isn't mapped yet */
-	gemini_openpic_init();
-	/* start the L2 */
-	gemini_init_l2();
-}
-
-
-int
-gemini_get_clock_speed(void)
-{
-	unsigned long hid1, pvr;
-	int clock;
-
-	pvr = mfspr(PVR);
-	hid1 = (mfspr(HID1) >> 28) & 0xf;
-	if (PVR_VER(pvr) == 8 ||
-	    PVR_VER(pvr) == 12)
-		hid1 = cpu_7xx[hid1];
-	else
-		hid1 = cpu_6xx[hid1];
-
-	switch((readb(GEMINI_BSTAT) & 0xc) >> 2) {
-
-	case 0:
-	default:
-		clock = (hid1*100)/3;
-		break;
-  
-	case 1:
-		clock = (hid1*125)/3;
-		break;
-  
-	case 2:
-		clock = (hid1*50);
-		break;
-	}
-
-	return clock;
-}
-
-void __init gemini_init_l2(void)
-{
-        unsigned char reg, brev, fam, creg;
-        unsigned long cache;
-        unsigned long pvr;
-
-        reg = readb(GEMINI_L2CFG);
-        brev = readb(GEMINI_BREV);
-        fam = readb(GEMINI_FEAT);
-        pvr = mfspr(PVR);
-
-        switch(PVR_VER(pvr)) {
-
-        case 8:
-                if (reg & 0xc0)
-                        cache = (((reg >> 6) & 0x3) << 28);
-                else
-                        cache = 0x3 << 28;
-
-#ifdef CONFIG_SMP
-                /* Pre-3.0 processor revs had snooping errata.  Leave
-                   their L2's disabled with SMP. -- Dan */
-                if (PVR_CFG(pvr) < 3) {
-                        printk("Pre-3.0 750; L2 left disabled!\n");
-                        return;
-                }
-#endif /* CONFIG_SMP */
-
-                /* Special case: VGM5-B's came before L2 ratios were set on
-                   the board.  Processor speed shouldn't be too high, so
-                   set L2 ratio to 1:1.5.  */
-                if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0)
-                        reg |= 1;
-
-                /* determine best cache ratio based upon what the board
-                   tells us (which sometimes _may_ not be true) and
-                   the processor speed. */
-                else {
-                        if (gemini_get_clock_speed() > 250)
-                                reg = 2;
-                }
-                break;
-        case 12:
-	{
-		static unsigned long l2_size_val = 0;
-		
-		if (!l2_size_val)
-			l2_size_val = _get_L2CR();
-		cache = l2_size_val;
-                break;
-	}
-        case 4:
-        case 9:
-                creg = readb(GEMINI_CPUSTAT);
-                if (((creg & 0xc) >> 2) != 1)
-                        printk("Dual-604 boards don't support the use of L2\n");
-                else
-                        writeb(1, GEMINI_L2CFG);
-                return;
-        default:
-                printk("Unknown processor; L2 left disabled\n");
-                return;
-        }
-
-        cache |= ((1<<reg) << 25);
-        cache |= (L2CR_L2RAM_MASK|L2CR_L2CTL|L2CR_L2DO);
-        _set_L2CR(0);
-        _set_L2CR(cache | L2CR_L2E);
-
-}
-
-void
-gemini_restart(char *cmd)
-{
-	__cli();
-	/* make a clean restart, not via the MPIC */
-	_gemini_reboot();
-	for(;;);
-}
-
-void
-gemini_power_off(void)
-{
-	for(;;);
-}
-
-void
-gemini_halt(void)
-{
-	gemini_restart(NULL);
-}
-
-void __init gemini_init_IRQ(void)
-{
-	/* gemini has no 8259 */
-	openpic_init(1, 0, 0, -1);
-}
-
-#define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
-#define gemini_rtc_write(val,x)  (writeb((val),(GEMINI_RTC+(x))))
-
-/* ensure that the RTC is up and running */
-long __init gemini_time_init(void)
-{
-	unsigned char reg;
-
-	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-
-	if ( reg & M48T35_RTC_STOPPED ) {
-		printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n");
-		gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
-		gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
-	}
-	return 0;
-}
-
-#undef DEBUG_RTC
-
-unsigned long
-gemini_get_rtc_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	unsigned char reg;
-
-	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-	gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL);
-#ifdef DEBUG_RTC
-	printk("get rtc: reg = %x\n", reg);
-#endif
-  
-	do {
-		sec = gemini_rtc_read(M48T35_RTC_SECONDS);
-		min = gemini_rtc_read(M48T35_RTC_MINUTES);
-		hour = gemini_rtc_read(M48T35_RTC_HOURS);
-		day = gemini_rtc_read(M48T35_RTC_DOM);
-		mon = gemini_rtc_read(M48T35_RTC_MONTH);
-		year = gemini_rtc_read(M48T35_RTC_YEAR);
-	} while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
-#ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
-	       sec, min, hour, day, mon, year);
-#endif
-
-	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
-
-	BCD_TO_BIN(sec);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(year);
-
-	if ((year += 1900) < 1970)
-		year += 100;
-#ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
-	       sec, min, hour, day, mon, year);
-#endif
-
-	return mktime( year, mon, day, hour, min, sec );
-}
-
-
-int
-gemini_set_rtc_time( unsigned long now )
-{
-	unsigned char reg;
-	struct rtc_time tm;
-
-	to_tm( now, &tm );
-
-	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
-#if DEBUG_RTC
-	printk("set rtc: reg = %x\n", reg);
-#endif
-  
-	gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL);
-#if DEBUG_RTC
-	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
-	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
-#endif
-  
-	tm.tm_year -= 1900;
-	BIN_TO_BCD(tm.tm_sec);
-	BIN_TO_BCD(tm.tm_min);
-	BIN_TO_BCD(tm.tm_hour);
-	BIN_TO_BCD(tm.tm_mon);
-	BIN_TO_BCD(tm.tm_mday);
-	BIN_TO_BCD(tm.tm_year);
-#ifdef DEBUG_RTC
-	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
-	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
-#endif
-
-	gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS);
-	gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES);
-	gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS);
-	gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM);
-	gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH);
-	gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR);
-
-	/* done writing */
-	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
-
-	if ((time_state == TIME_ERROR) || (time_state == TIME_BAD))
-		time_state = TIME_OK;
-  
-	return 0;
-}
-
-/*  use the RTC to determine the decrementer count */
-void __init gemini_calibrate_decr(void)
-{
-	int freq, divisor;
-	unsigned char reg;
-
-	/* determine processor bus speed */
-	reg = readb(GEMINI_BSTAT);
-
-	switch(((reg & 0x0c)>>2)&0x3) {
-	case 0:
-	default:
-		freq = 66667;
-		break;
-	case 1:
-		freq = 83000;
-		break;
-	case 2:
-		freq = 100000;
-		break;
-	}
-
-	freq *= 1000;
-	divisor = 4;
-	tb_ticks_per_jiffy = freq / HZ / divisor;
-	tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
-}
-
-unsigned long __init gemini_find_end_of_memory(void)
-{
-	unsigned long total;
-	unsigned char reg;
-
-	reg = readb(GEMINI_MEMCFG);
-	total = ((1<<((reg & 0x7) - 1)) *
-		 (8<<((reg >> 3) & 0x7)));
-	total *= (1024*1024);
-	return total;
-}
-
-static void __init
-gemini_map_io(void)
-{
-	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
-	io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
-}
-
-#ifdef CONFIG_SMP
-static int
-smp_gemini_probe(void)
-{
-	int i, nr;
-
-        nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
-	if (nr == 0)
-		nr = 4;
-
-	if (nr > 1) {
-		openpic_request_IPIs();
-		for (i = 1; i < nr; ++i)
-			smp_hw_index[i] = i;
-	}
-
-	return nr;
-}
-
-static void
-smp_gemini_kick_cpu(int nr)
-{
-	openpic_reset_processor_phys(1 << nr);
-	openpic_reset_processor_phys(0);
-}
-
-static void
-smp_gemini_setup_cpu(int cpu_nr)
-{
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-	if (cpu_nr > 0)
-		gemini_init_l2();
-}
-
-static struct smp_ops_t gemini_smp_ops = {
-	smp_openpic_message_pass,
-	smp_gemini_probe,
-	smp_gemini_kick_cpu,
-	smp_gemini_setup_cpu,
-};
-#endif /* CONFIG_SMP */
-
-void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-			  unsigned long r6, unsigned long r7)
-{
-	int i;
-
-	for(i = 0; i < GEMINI_LEDS; i++)
-		gemini_led_off(i);
- 
-	ISA_DMA_THRESHOLD = 0;
-	DMA_MODE_READ = 0;
-	DMA_MODE_WRITE = 0;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	if ( r4 )
-	{
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif
-
-	ppc_md.setup_arch = gemini_setup_arch;
-	ppc_md.show_cpuinfo = gemini_show_cpuinfo;
-	ppc_md.irq_cannonicalize = NULL;
-	ppc_md.init_IRQ = gemini_init_IRQ;
-	ppc_md.get_irq = openpic_get_irq;
-	ppc_md.init = NULL;
-
-	ppc_md.restart = gemini_restart;
-	ppc_md.power_off = gemini_power_off;
-	ppc_md.halt = gemini_halt;
-
-	ppc_md.time_init = gemini_time_init;
-	ppc_md.set_rtc_time = gemini_set_rtc_time;
-	ppc_md.get_rtc_time = gemini_get_rtc_time;
-	ppc_md.calibrate_decr = gemini_calibrate_decr;
-
-	ppc_md.find_end_of_memory = gemini_find_end_of_memory;
-	ppc_md.setup_io_mappings = gemini_map_io;
-
-	/* no keyboard/mouse/video stuff yet.. */
-	ppc_md.kbd_setkeycode = NULL;
-	ppc_md.kbd_getkeycode = NULL;
-	ppc_md.kbd_translate = NULL;
-	ppc_md.kbd_unexpected_up = NULL;
-	ppc_md.kbd_leds = NULL;
-	ppc_md.kbd_init_hw = NULL;
-	ppc_md.ppc_kbd_sysrq_xlate = NULL;
-	ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
-
-#ifdef CONFIG_SMP
-	ppc_md.smp_ops = &gemini_smp_ops;
-#endif /* CONFIG_SMP */
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/head.S linux-2.4.20-pre2/arch/ppc/kernel/head.S
--- linux-2.4.20-pre1/arch/ppc/kernel/head.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/head.S	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.head.S 1.43 06/25/02 17:24:29 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  PowerPC version 
@@ -26,13 +26,14 @@
  */
 
 #include <linux/config.h>
-#include "ppc_asm.h"
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
 #include <asm/cputable.h>
 #include <asm/cache.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 #ifdef CONFIG_APUS
 #include <asm/amigappc.h>
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/head_4xx.S linux-2.4.20-pre2/arch/ppc/kernel/head_4xx.S
--- linux-2.4.20-pre1/arch/ppc/kernel/head_4xx.S	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/head_4xx.S	Mon Aug 12 16:34:14 2002
@@ -34,7 +34,8 @@
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
 
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 
 /* Preprocessor Defines */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/head_8xx.S linux-2.4.20-pre2/arch/ppc/kernel/head_8xx.S
--- linux-2.4.20-pre1/arch/ppc/kernel/head_8xx.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/head_8xx.S	Mon Aug 12 16:34:14 2002
@@ -24,7 +24,6 @@
  *	
  */
 
-#include "ppc_asm.h"
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <linux/config.h>
@@ -32,6 +31,8 @@
 #include <asm/cache.h>
 #include <asm/pgtable.h>
 #include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 	.text
 	.globl	_stext
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/i8259.c linux-2.4.20-pre2/arch/ppc/kernel/i8259.c
--- linux-2.4.20-pre1/arch/ppc/kernel/i8259.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/i8259.c	Mon Aug 12 16:34:14 2002
@@ -9,7 +9,7 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <asm/io.h>
-#include "i8259.h"
+#include <asm/i8259.h>
 
 static volatile char *pci_intack; /* RO, gives us the irq vector */
 
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/i8259.h linux-2.4.20-pre2/arch/ppc/kernel/i8259.h
--- linux-2.4.20-pre1/arch/ppc/kernel/i8259.h	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/i8259.h	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-/*
- * BK Id: SCCS/s.i8259.h 1.8 12/19/01 09:45:54 trini
- */
-
-#ifndef _PPC_KERNEL_i8259_H
-#define _PPC_KERNEL_i8259_H
-
-#include "local_irq.h"
-
-extern struct hw_interrupt_type i8259_pic;
-
-void i8259_init(long);
-int i8259_irq(void);
-int i8259_poll(void);
-
-#endif /* _PPC_KERNEL_i8259_H */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/indirect_pci.c linux-2.4.20-pre2/arch/ppc/kernel/indirect_pci.c
--- linux-2.4.20-pre1/arch/ppc/kernel/indirect_pci.c	Sat Sep  8 12:38:41 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/indirect_pci.c	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.indirect_pci.c 1.10 09/08/01 15:47:42 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Support for indirect PCI bridges.
@@ -24,8 +24,6 @@
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 
-#include "pci.h"
-
 #define cfg_read(val, addr, type, op)	*val = op((type)(addr))
 #define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
 
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/irq.c linux-2.4.20-pre2/arch/ppc/kernel/irq.c
--- linux-2.4.20-pre1/arch/ppc/kernel/irq.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/irq.c	Mon Aug 12 16:34:14 2002
@@ -63,8 +63,6 @@
 #include <asm/amigappc.h>
 #include <asm/ptrace.h>
 
-#include "local_irq.h"
-
 extern atomic_t ipi_recv;
 extern atomic_t ipi_sent;
 void enable_irq(unsigned int irq_nr);
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/l2cr.S linux-2.4.20-pre2/arch/ppc/kernel/l2cr.S
--- linux-2.4.20-pre1/arch/ppc/kernel/l2cr.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/l2cr.S	Mon Aug 12 16:34:14 2002
@@ -42,7 +42,7 @@
 */
 #include <asm/processor.h>
 #include <asm/cputable.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 /* Usage:
 	
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/local_irq.h linux-2.4.20-pre2/arch/ppc/kernel/local_irq.h
--- linux-2.4.20-pre1/arch/ppc/kernel/local_irq.h	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/local_irq.h	Wed Dec 31 16:00:00 1969
@@ -1,22 +0,0 @@
-/*
- * BK Id: SCCS/s.local_irq.h 1.7 05/17/01 18:14:21 cort
- */
-
-#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 + 31) / 32)
-
-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.20-pre1/arch/ppc/kernel/m8260_setup.c linux-2.4.20-pre2/arch/ppc/kernel/m8260_setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/m8260_setup.c	Fri Nov 16 10:10:08 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/m8260_setup.c	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.m8260_setup.c 1.30 11/13/01 21:26:07 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -45,8 +45,9 @@
 #include <asm/mpc8260.h>
 #include <asm/immap_8260.h>
 #include <asm/machdep.h>
-
+#include <asm/bootinfo.h>
 #include <asm/time.h>
+
 #include "ppc8260_pic.h"
 
 static int m8260_set_rtc_time(unsigned long time);
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/m8xx_setup.c linux-2.4.20-pre2/arch/ppc/kernel/m8xx_setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/m8xx_setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/m8xx_setup.c	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.m8xx_setup.c 1.40 11/13/01 21:26:07 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  *
  *  linux/arch/ppc/kernel/setup.c
  *
@@ -43,8 +43,9 @@
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #include <asm/machdep.h>
-
+#include <asm/bootinfo.h>
 #include <asm/time.h>
+
 #include "ppc8xx_pic.h"
 
 static int m8xx_set_rtc_time(unsigned long time);
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/misc.S linux-2.4.20-pre2/arch/ppc/kernel/misc.S
--- linux-2.4.20-pre1/arch/ppc/kernel/misc.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/misc.S	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.misc.S 1.44 06/25/02 17:24:30 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * This file contains miscellaneous low-level functions.
@@ -23,7 +23,9 @@
 #include <asm/page.h>
 #include <asm/cache.h>
 #include <asm/cputable.h>
-#include "ppc_asm.h"
+#include <asm/mmu.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
 
 	.text
 
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/oak_setup.c linux-2.4.20-pre2/arch/ppc/kernel/oak_setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/oak_setup.c	Fri Nov 16 10:10:08 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/oak_setup.c	Wed Dec 31 16:00:00 1969
@@ -1,297 +0,0 @@
-/*
- * BK Id: SCCS/s.oak_setup.c 1.12 11/13/01 21:26:07 paulus
- */
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oak_setup.c
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- *      <dan@net4x.com>.
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/interrupt.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/blk.h>
-#include <linux/seq_file.h>
-
-#include <asm/processor.h>
-#include <asm/board.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-
-#include "local_irq.h"
-#include "ppc4xx_pic.h"
-#include <asm/time.h>
-#include "oak_setup.h"
-
-
-
-
-
-
-
-/* Function Prototypes */
-
-extern void abort(void);
-
-/* Global Variables */
-
-unsigned char __res[sizeof(bd_t)];
-
-
-/*
- * void __init oak_init()
- *
- * Description:
- *   This routine...
- *
- * Input(s):
- *   r3 - Optional pointer to a board information structure.
- *   r4 - Optional pointer to the physical starting address of the init RAM
- *        disk.
- *   r5 - Optional pointer to the physical ending address of the init RAM
- *        disk.
- *   r6 - Optional pointer to the physical starting address of any kernel
- *        command-line parameters.
- *   r7 - Optional pointer to the physical ending address of any kernel
- *        command-line parameters.
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5, 
-	      unsigned long r6, unsigned long r7)
-{
-	/*
-	 * If we were passed in a board information, copy it into the
-	 * residual data area.
-	 */
-	if (r3) {
-		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
-	}
-
-#if defined(CONFIG_BLK_DEV_INITRD)
-	/*
-	 * If the init RAM disk has been configured in, and there's a valid
-	 * starting address for it, set it up.
-	 */
-	if (r4) {
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	/* Copy the kernel command line arguments to a safe place. */
-
-	if (r6) {
- 		*(char *)(r7 + KERNELBASE) = 0;
-		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
-	}
-
-	/* Initialize machine-dependency vectors */
-
-	ppc_md.setup_arch	 	= oak_setup_arch;
-	ppc_md.show_percpuinfo	 	= oak_show_percpuinfo;
-	ppc_md.irq_cannonicalize 	= NULL;
-	ppc_md.init_IRQ		 	= oak_init_IRQ;
-	ppc_md.get_irq		 	= oak_get_irq;
-	ppc_md.init		 	= NULL;
-
-	ppc_md.restart		 	= oak_restart;
-	ppc_md.power_off	 	= oak_power_off;
-	ppc_md.halt		 	= oak_halt;
-
-	ppc_md.time_init	 	= oak_time_init;
-	ppc_md.set_rtc_time	 	= oak_set_rtc_time;
-	ppc_md.get_rtc_time	 	= oak_get_rtc_time;
-	ppc_md.calibrate_decr	 	= oak_calibrate_decr;
-
-	ppc_md.kbd_setkeycode    	= NULL;
-	ppc_md.kbd_getkeycode    	= NULL;
-	ppc_md.kbd_translate     	= NULL;
-	ppc_md.kbd_unexpected_up 	= NULL;
-	ppc_md.kbd_leds          	= NULL;
-	ppc_md.kbd_init_hw       	= NULL;
-	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
-}
-
-/*
- * Document me.
- */
-void __init
-oak_setup_arch(void)
-{
-	/* XXX - Implement me */
-}
-
-/*
- * int oak_show_percpuinfo()
- *
- * Description:
- *   This routine pretty-prints the platform's internal CPU and bus clock
- *   frequencies into the buffer for usage in /proc/cpuinfo.
- *
- * Input(s):
- *  *buffer - Buffer into which CPU and bus clock frequencies are to be
- *            printed.
- *
- * Output(s):
- *  *buffer - Buffer with the CPU and bus clock frequencies.
- *
- * Returns:
- *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
- *   on error.
- */
-int
-oak_show_percpuinfo(struct seq_file *m, int i)
-{
-	bd_t *bp = (bd_t *)__res;
-
-	seq_printf(m, "clock\t\t: %dMHz\n"
-		   "bus clock\t\t: %dMHz\n",
-		   bp->bi_intfreq / 1000000,
-		   bp->bi_busfreq / 1000000);
-
-	return 0;
-}
-
-/*
- * Document me.
- */
-void __init
-oak_init_IRQ(void)
-{
-	int i;
-
-	ppc4xx_pic_init();
-
-	for (i = 0; i < NR_IRQS; i++) {
-		irq_desc[i].handler = ppc4xx_pic;
-	}
-
-	return;
-}
-
-/*
- * Document me.
- */
-int
-oak_get_irq(struct pt_regs *regs)
-{
-	return (ppc4xx_pic_get_irq(regs));
-}
-
-/*
- * Document me.
- */
-void
-oak_restart(char *cmd)
-{
-	abort();
-}
-
-/*
- * Document me.
- */
-void
-oak_power_off(void)
-{
-	oak_restart(NULL);
-}
-
-/*
- * Document me.
- */
-void
-oak_halt(void)
-{
-	oak_restart(NULL);
-}
-
-/*
- * Document me.
- */
-long __init
-oak_time_init(void)
-{
-	/* XXX - Implement me */
-	return 0;
-}
-
-/*
- * Document me.
- */
-int __init
-oak_set_rtc_time(unsigned long time)
-{
-	/* XXX - Implement me */
-
-	return (0);
-}
-
-/*
- * Document me.
- */
-unsigned long __init
-oak_get_rtc_time(void)
-{
-	/* XXX - Implement me */
-
-	return (0);
-}
-
-/*
- * void __init oak_calibrate_decr()
- *
- * Description:
- *   This routine retrieves the internal processor frequency from the board
- *   information structure, sets up the kernel timer decrementer based on
- *   that value, enables the 403 programmable interval timer (PIT) and sets
- *   it up for auto-reload.
- *
- * Input(s):
- *   N/A
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-oak_calibrate_decr(void)
-{
-	unsigned int freq;
-	bd_t *bip = (bd_t *)__res;
-
-	freq = bip->bi_intfreq;
-
-	decrementer_count = freq / HZ;
-	count_period_num = 1;
-	count_period_den = freq;
-
-	/* Enable the PIT and set auto-reload of its value */
-
-	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
-
-	/* Clear any pending timer interrupts */
-
-	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/oak_setup.h linux-2.4.20-pre2/arch/ppc/kernel/oak_setup.h
--- linux-2.4.20-pre1/arch/ppc/kernel/oak_setup.h	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/oak_setup.h	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-/*
- * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort
- */
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oak_setup.h
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- *      <dan@netx4.com>.
- *
- */
-
-#ifndef	__OAK_SETUP_H__
-#define	__OAK_SETUP_H__
-
-#include <asm/ptrace.h>
-#include <asm/board.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern unsigned char	 __res[sizeof(bd_t)];
-
-extern void		 oak_init(unsigned long r3,
-				  unsigned long ird_start,
-				  unsigned long ird_end,
-				  unsigned long cline_start,
-				  unsigned long cline_end);
-extern void		 oak_setup_arch(void);
-extern int		 oak_setup_residual(char *buffer);
-extern void		 oak_init_IRQ(void);
-extern int		 oak_get_irq(struct pt_regs *regs);
-extern void		 oak_restart(char *cmd);
-extern void		 oak_power_off(void);
-extern void		 oak_halt(void);
-extern void		 oak_time_init(void);
-extern int		 oak_set_rtc_time(unsigned long now);
-extern unsigned long	 oak_get_rtc_time(void);
-extern void		 oak_calibrate_decr(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __OAK_SETUP_H__ */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/open_pic.c linux-2.4.20-pre2/arch/ppc/kernel/open_pic.c
--- linux-2.4.20-pre1/arch/ppc/kernel/open_pic.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/open_pic.c	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.open_pic.c 1.33 12/19/01 09:45:54 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
@@ -17,18 +17,16 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/irq.h>
-#include <linux/init.h>
 #include <asm/ptrace.h>
 #include <asm/signal.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
 #include <asm/sections.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
 
-#include "local_irq.h"
-#include "open_pic.h"
 #include "open_pic_defs.h"
-#include "i8259.h"
 
 void* OpenPIC_Addr;
 static volatile struct OpenPIC *OpenPIC = NULL;
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/open_pic.h linux-2.4.20-pre2/arch/ppc/kernel/open_pic.h
--- linux-2.4.20-pre1/arch/ppc/kernel/open_pic.h	Fri Nov  2 17:43:54 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/open_pic.h	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-/*
- * BK Id: SCCS/s.open_pic.h 1.14 10/11/01 12:09:12 trini
- */
-/*
- *  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 _PPC_KERNEL_OPEN_PIC_H
-#define _PPC_KERNEL_OPEN_PIC_H
-
-#include <linux/config.h>
-
-#define OPENPIC_SIZE	0x40000
-
-/*
- *  Non-offset'ed vector numbers
- */
-
-#define OPENPIC_VEC_TIMER	64	/* and up */
-#define OPENPIC_VEC_IPI		72	/* and up */
-#define OPENPIC_VEC_SPURIOUS	127
-
-/* 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 u_int openpic_irq(void);
-extern void openpic_eoi(void);
-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_reset_processor_phys(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 void smp_openpic_message_pass(int target, int msg, unsigned long data,
-				     int wait);
-
-extern inline int openpic_to_irq(int irq)
-{
-	/* IRQ 0 usually means 'disabled'.. don't mess with it 
-	 * exceptions to this (sandpoint maybe?) 
-	 * shouldn't use openpic_to_irq 
-	 */
-	if (irq != 0){
-		return irq += NUM_8259_INTERRUPTS;
-	} else {
-		return 0;
-	}
-}
-/*extern int open_pic_irq_offset;*/
-#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pci.c linux-2.4.20-pre2/arch/ppc/kernel/pci.c
--- linux-2.4.20-pre1/arch/ppc/kernel/pci.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/pci.c	Mon Aug 12 16:34:14 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pci.c 1.43 05/08/02 15:01:15 benh
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Common pmac/prep/chrp pci routines. -- Cort
@@ -21,15 +21,11 @@
 #include <asm/prom.h>
 #include <asm/sections.h>
 #include <asm/pci-bridge.h>
-#include <asm/residual.h>
 #include <asm/byteorder.h>
 #include <asm/irq.h>
-#include <asm/gg2.h>
 #include <asm/uaccess.h>
 
-#include "pci.h"
-
-#define DEBUG
+#undef DEBUG
 
 #ifdef DEBUG
 #define DBG(x...) printk(x)
@@ -840,12 +836,6 @@
 		ppc_md.pcibios_after_init();
 }
 
-int __init
-pcibios_assign_all_busses(void)
-{
-	return pci_assign_all_busses;
-}
-
 void __init
 pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
 {
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pmac_backlight.c linux-2.4.20-pre2/arch/ppc/kernel/pmac_backlight.c
--- linux-2.4.20-pre1/arch/ppc/kernel/pmac_backlight.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/pmac_backlight.c	Wed Dec 31 16:00:00 1969
@@ -1,150 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_backlight.c 1.10 12/01/01 20:09:06 benh
- */
-/*
- * Miscellaneous procedures for dealing with the PowerMac hardware.
- * Contains support for the backlight.
- * 
- *   Copyright (C) 2000 Benjamin Herrenschmidt
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/reboot.h>
-#include <linux/nvram.h>
-#include <asm/sections.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
-#include <asm/backlight.h>
-
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-static struct backlight_controller *backlighter = NULL;
-static void* backlighter_data = NULL;
-static int backlight_autosave = 0;
-static int backlight_level = BACKLIGHT_MAX;
-static int backlight_enabled = 1;
-
-void __pmac
-register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type)
-{
-	struct device_node* bk_node;
-	char *prop;
-	int valid = 0;
-
-	bk_node = find_devices("backlight");
-	
-#ifdef CONFIG_ADB_PMU
-	/* Special case for the old PowerBook since I can't test on it */
-	backlight_autosave = machine_is_compatible("AAPL,3400/2400")
-		|| machine_is_compatible("AAPL,3500");
-	if ((backlight_autosave
-	     || machine_is_compatible("AAPL,PowerBook1998")
-	     || machine_is_compatible("PowerBook1,1"))
-	    && !strcmp(type, "pmu"))
-		valid = 1;
-#endif
-	if (bk_node) {
-		prop = get_property(bk_node, "backlight-control", NULL);
-		if (prop && !strncmp(prop, type, strlen(type)))
-			valid = 1;
-	}
-	if (!valid)
-		return;
-	backlighter = ctrler;
-	backlighter_data = data;
-	
-	if (bk_node && !backlight_autosave)
-		prop = get_property(bk_node, "bklt", NULL);
-	else
-		prop = NULL;
-	if (prop) {
-		backlight_level = ((*prop)+1) >> 1;
-		if (backlight_level > BACKLIGHT_MAX)
-			backlight_level = BACKLIGHT_MAX;
-	}
-	
-#ifdef CONFIG_ADB_PMU
-	if (backlight_autosave) {
-		struct adb_request req;
-		pmu_request(&req, NULL, 2, 0xd9, 0);
-		while (!req.complete)
-			pmu_poll();
-		backlight_level = req.reply[0] >> 4;
-	}
-#endif
-	if (!backlighter->set_enable(1, backlight_level, data))
-		backlight_enabled = 1;
-
-	printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
-		type, backlight_level);
-}
-
-void __pmac
-unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
-{
-	/* We keep the current backlight level (for now) */
-	if (ctrler == backlighter && data == backlighter_data)
-		backlighter = NULL;
-}
-
-int __pmac
-set_backlight_enable(int enable)
-{
-	int rc;
-	
-	if (!backlighter)
-		return -ENODEV;
-	rc = backlighter->set_enable(enable, backlight_level, backlighter_data);
-	if (!rc)
-		backlight_enabled = enable;
-	return rc;
-}
-
-int __pmac
-get_backlight_enable(void)
-{
-	if (!backlighter)
-		return -ENODEV;
-	return backlight_enabled;
-}
-
-int __pmac
-set_backlight_level(int level)
-{
-	int rc = 0;
-	
-	if (!backlighter)
-		return -ENODEV;
-	if (level < BACKLIGHT_MIN)
-		level = BACKLIGHT_OFF;
-	if (level > BACKLIGHT_MAX)
-		level = BACKLIGHT_MAX;
-	if (backlight_enabled)
-		rc = backlighter->set_level(level, backlighter_data);
-	if (!rc)
-		backlight_level = level;
-	if (!rc && !backlight_autosave) {
-		level <<=1;
-		if (level & 0x10)
-			level |= 0x01;
-		// -- todo: save to property "bklt"
-	}
-	return rc;
-}
-
-int __pmac
-get_backlight_level(void)
-{
-	if (!backlighter)
-		return -ENODEV;
-	return backlight_level;
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pmac_feature.c linux-2.4.20-pre2/arch/ppc/kernel/pmac_feature.c
--- linux-2.4.20-pre1/arch/ppc/kernel/pmac_feature.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/pmac_feature.c	Wed Dec 31 16:00:00 1969
@@ -1,2139 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  arch/ppc/kernel/pmac_feature.c
- *
- *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
- *                          Ben. Herrenschmidt (benh@kernel.crashing.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.
- *  
- *  TODO: 
- *  
- *   - Replace mdelay with some schedule loop if possible
- *   - Shorten some obfuscated delays on some routines (like modem
- *     power)
- *
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <asm/sections.h>
-#include <asm/errno.h>
-#include <asm/ohare.h>
-#include <asm/heathrow.h>
-#include <asm/keylargo.h>
-#include <asm/uninorth.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/dbdma.h>
-
-#undef DEBUG_FEATURE
-
-#ifdef DEBUG_FEATURE
-#define DBG(fmt,...) printk(KERN_DEBUG fmt)
-#else
-#define DBG(fmt,...)
-#endif
-
-/* Exported from arch/ppc/kernel/idle.c */
-extern unsigned long powersave_nap;
-
-/*
- * We use a single global lock to protect accesses. Each driver has
- * to take care of it's own locking
- */
-static spinlock_t feature_lock  __pmacdata = SPIN_LOCK_UNLOCKED;
-
-#define LOCK(flags)	spin_lock_irqsave(&feature_lock, flags);
-#define UNLOCK(flags)	spin_unlock_irqrestore(&feature_lock, flags);
-
-/*
- * Helper functions regarding the various flavors of mac-io
- */
- 
-#define MAX_MACIO_CHIPS		2
-
-enum {
-	macio_unknown = 0,
-	macio_grand_central,
-	macio_ohare,
-	macio_ohareII,
-	macio_heathrow,
-	macio_gatwick,
-	macio_paddington,
-	macio_keylargo,
-	macio_pangea
-};
-
-static const char* macio_names[] __pmacdata = 
-{
-	"Unknown",
-	"Grand Central",
-	"OHare",
-	"OHareII",
-	"Heathrow",
-	"Gatwick",
-	"Paddington",
-	"Keylargo",
-	"Pangea"
-};
-
-static struct macio_chip
-{
-	struct device_node*	of_node;
-	int			type;
-	int			rev;
-	volatile u32*		base;
-	unsigned long		flags;
-} macio_chips[MAX_MACIO_CHIPS]  __pmacdata;
-
-#define MACIO_FLAG_SCCA_ON	0x00000001
-#define MACIO_FLAG_SCCB_ON	0x00000002
-#define MACIO_FLAG_SCC_LOCKED	0x00000004
-#define MACIO_FLAG_AIRPORT_ON	0x00000010
-#define MACIO_FLAG_FW_SUPPORTED	0x00000020
-
-static struct macio_chip* __pmac
-macio_find(struct device_node* child, int type)
-{
-	while(child) {
-		int	i;
-	
-		for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
-			if (child == macio_chips[i].of_node &&
-			    (!type || macio_chips[i].type == type))
-				return &macio_chips[i];
-		child = child->parent;
-	}
-	return NULL;
-}
-
-#define MACIO_FCR32(macio, r)	((macio)->base + ((r) >> 2))
-#define MACIO_FCR8(macio, r)	(((volatile u8*)((macio)->base)) + (r))
-
-#define MACIO_IN32(r)		(in_le32(MACIO_FCR32(macio,r)))
-#define MACIO_OUT32(r,v)	(out_le32(MACIO_FCR32(macio,r), (v)))
-#define MACIO_BIS(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) | (v)))
-#define MACIO_BIC(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) & ~(v)))
-#define MACIO_IN8(r)		(in_8(MACIO_FCR8(macio,r)))
-#define MACIO_OUT8(r,v)		(out_8(MACIO_FCR8(macio,r), (v)))
-
-/*
- * Uninorth reg. access. Note that Uni-N regs are big endian
- */
- 
-#define UN_REG(r)	(uninorth_base + ((r) >> 2))
-#define UN_IN(r)	(in_be32(UN_REG(r)))
-#define UN_OUT(r,v)	(out_be32(UN_REG(r), (v)))
-#define UN_BIS(r,v)	(UN_OUT((r), UN_IN(r) | (v)))
-#define UN_BIC(r,v)	(UN_OUT((r), UN_IN(r) & ~(v)))
-
-static struct device_node* uninorth_node __pmacdata;
-static u32* uninorth_base __pmacdata;
-static u32 uninorth_rev __pmacdata;
-
-
-/*
- * For each motherboard family, we have a table of functions pointers
- * that handle the various features.
- */
-
-typedef int (*feature_call)(struct device_node* node, int param, int value);
-
-struct feature_table_entry {
-	unsigned int	selector;	
-	feature_call	function;
-};
-
-struct pmac_mb_def
-{
-	const char*			model_string;
-	const char*			model_name;
-	int				model_id;
-	struct feature_table_entry* 	features;
-	unsigned long			board_flags;
-};
-static struct pmac_mb_def pmac_mb __pmacdata;
-
-/*
- * Here are the chip specific feature functions
- */
-
-static inline int __pmac
-simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, type);
-	if (!macio)
-		return -ENODEV;
-	LOCK(flags);
-	if (value)
-		MACIO_BIS(reg, mask);
-	else
-		MACIO_BIC(reg, mask);
-	(void)MACIO_IN32(reg);
-	UNLOCK(flags);
-
-	return 0;
-}
-
-static int __pmac
-ohare_htw_scc_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		chan_mask;
-	unsigned long		fcr;
-	unsigned long		flags;
-	int			htw, trans;
-	unsigned long		rmask;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	if (!strcmp(node->name, "ch-a"))
-		chan_mask = MACIO_FLAG_SCCA_ON;
-	else if (!strcmp(node->name, "ch-b"))
-		chan_mask = MACIO_FLAG_SCCB_ON;
-	else
-		return -ENODEV;
-
-	htw = (macio->type == macio_heathrow || macio->type == macio_paddington
-		|| macio->type == macio_gatwick);
-	/* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
-	trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
-	    	 pmac_mb.model_id != PMAC_TYPE_YIKES);
-	if (value) {
-#ifdef CONFIG_ADB_PMU
-		if ((param & 0xfff) == PMAC_SCC_IRDA)
-			pmu_enable_irled(1);
-#endif /* CONFIG_ADB_PMU */		
-		LOCK(flags);
-		fcr = MACIO_IN32(OHARE_FCR);
-		/* Check if scc cell need enabling */
-		if (!(fcr & OH_SCC_ENABLE)) {
-			fcr |= OH_SCC_ENABLE;
-			if (htw) {
-				/* Side effect: this will also power up the
-				 * modem, but it's too messy to figure out on which
-				 * ports this controls the tranceiver and on which
-				 * it controls the modem
-				 */
-				if (trans)
-					fcr &= ~HRW_SCC_TRANS_EN_N;
-				MACIO_OUT32(OHARE_FCR, fcr);
-				fcr |= (rmask = HRW_RESET_SCC);
-				MACIO_OUT32(OHARE_FCR, fcr);
-			} else {
-				fcr |= (rmask = OH_SCC_RESET);
-				MACIO_OUT32(OHARE_FCR, fcr);
-			}
-			UNLOCK(flags);
-			(void)MACIO_IN32(OHARE_FCR);
-			mdelay(15);
-			LOCK(flags);
-			fcr &= ~rmask;
-			MACIO_OUT32(OHARE_FCR, fcr);
-		}
-		if (chan_mask & MACIO_FLAG_SCCA_ON)
-			fcr |= OH_SCCA_IO;
-		if (chan_mask & MACIO_FLAG_SCCB_ON)
-			fcr |= OH_SCCB_IO;
-		MACIO_OUT32(OHARE_FCR, fcr);
-		macio->flags |= chan_mask;
-		UNLOCK(flags);
-		if (param & PMAC_SCC_FLAG_XMON)
-			macio->flags |= MACIO_FLAG_SCC_LOCKED;
-	} else {
-		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
-			return -EPERM;
-		LOCK(flags);
-		fcr = MACIO_IN32(OHARE_FCR);
-		if (chan_mask & MACIO_FLAG_SCCA_ON)
-			fcr &= ~OH_SCCA_IO;
-		if (chan_mask & MACIO_FLAG_SCCB_ON)
-			fcr &= ~OH_SCCB_IO;
-		MACIO_OUT32(OHARE_FCR, fcr);
-		if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
-			fcr &= ~OH_SCC_ENABLE;
-			if (htw && trans)
-				fcr |= HRW_SCC_TRANS_EN_N;
-			MACIO_OUT32(OHARE_FCR, fcr);
-		}
-		macio->flags &= ~(chan_mask);
-		UNLOCK(flags);
-		mdelay(10);
-#ifdef CONFIG_ADB_PMU
-		if ((param & 0xfff) == PMAC_SCC_IRDA)
-			pmu_enable_irled(0);
-#endif /* CONFIG_ADB_PMU */		
-	}
-	return 0;
-}
-
-static int __pmac
-ohare_floppy_enable(struct device_node* node, int param, int value)
-{
-	return simple_feature_tweak(node, macio_ohare,
-		OHARE_FCR, OH_FLOPPY_ENABLE, value);
-}
-
-static int __pmac
-ohare_mesh_enable(struct device_node* node, int param, int value)
-{
-	return simple_feature_tweak(node, macio_ohare,
-		OHARE_FCR, OH_MESH_ENABLE, value);
-}
-
-static int __pmac
-ohare_ide_enable(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-	    	/* For some reason, setting the bit in set_initial_features()
-	    	 * doesn't stick. I'm still investigating... --BenH.
-	    	 */
-	    	if (value)
-	    		simple_feature_tweak(node, macio_ohare,
-				OHARE_FCR, OH_IOBUS_ENABLE, 1);
-		return simple_feature_tweak(node, macio_ohare,
-			OHARE_FCR, OH_IDE0_ENABLE, value);
-	    case 1:
-		return simple_feature_tweak(node, macio_ohare,
-			OHARE_FCR, OH_BAY_IDE_ENABLE, value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-ohare_ide_reset(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_ohare,
-			OHARE_FCR, OH_IDE0_RESET_N, !value);
-	    case 1:
-		return simple_feature_tweak(node, macio_ohare,
-			OHARE_FCR, OH_IDE1_RESET_N, !value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-ohare_sleep_state(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio = &macio_chips[0];
-
-	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-		return -EPERM;
-	if (value == 1) {
-		MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
-	} else if (value == 0) {
-		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-	}
-	
-	return 0;
-}
-
-static int __pmac
-heathrow_modem_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	u8			gpio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, macio_unknown);
-	if (!macio)
-		return -ENODEV;
-	gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
-	if (!value) {
-		LOCK(flags);
-		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
-		UNLOCK(flags);
-		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-		mdelay(250);
-	}
-	if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
-	    pmac_mb.model_id != PMAC_TYPE_YIKES) {
-	    	LOCK(flags);
-	    	if (value)
-	    		MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-	    	else
-	    		MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-	    	UNLOCK(flags);
-	    	(void)MACIO_IN32(HEATHROW_FCR);
-		mdelay(250);
-	}
-	if (value) {
-		LOCK(flags);
-		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
-		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
-		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
-		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250);
-	}
-	return 0;
-}
-
-static int __pmac
-heathrow_floppy_enable(struct device_node* node, int param, int value)
-{
-	return simple_feature_tweak(node, macio_unknown,
-		HEATHROW_FCR,
-		HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
-		value);
-}
-
-static int __pmac
-heathrow_mesh_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, macio_unknown);
-	if (!macio)
-		return -ENODEV;
-	LOCK(flags);
-	/* Set clear mesh cell enable */
-	if (value)
-		MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
-	else
-		MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
-	(void)MACIO_IN32(HEATHROW_FCR);
-	udelay(10);
-	/* Set/Clear termination power (todo: test ! the bit value
-	 * used by Darwin doesn't seem to match what we used so
-	 * far. If you experience problems, turn #if 1 into #if 0
-	 * and tell me about it --BenH.
-	 */
-#if 1
-	if (value)
-		MACIO_BIC(HEATHROW_MBCR, 0x00000004);
-	else
-		MACIO_BIS(HEATHROW_MBCR, 0x00000004);
-#else
-	if (value)
-		MACIO_BIC(HEATHROW_MBCR, 0x00040000);
-	else
-		MACIO_BIS(HEATHROW_MBCR, 0x00040000);
-#endif		
-	(void)MACIO_IN32(HEATHROW_MBCR);
-	udelay(10);
-	UNLOCK(flags);
-
-	return 0;
-}
-
-static int __pmac
-heathrow_ide_enable(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_unknown,
-			HEATHROW_FCR, HRW_IDE0_ENABLE, value);
-	    case 1:
-		return simple_feature_tweak(node, macio_unknown,
-			HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-heathrow_ide_reset(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_unknown,
-			HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
-	    case 1:
-		return simple_feature_tweak(node, macio_unknown,
-			HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-heathrow_bmac_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	if (value) {
-		LOCK(flags);
-		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
-		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
-		UNLOCK(flags);
-		(void)MACIO_IN32(HEATHROW_FCR);
-		mdelay(10);
-		LOCK(flags);
-		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
-		UNLOCK(flags);
-		(void)MACIO_IN32(HEATHROW_FCR);
-		mdelay(10);
-	} else {
-		LOCK(flags);
-		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
-		UNLOCK(flags);
-	}
-	return 0;
-}
-
-static int __pmac
-heathrow_sound_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-
-	/* B&W G3 and Yikes don't support that properly (the
-	 * sound appear to never come back after beeing shut down).
-	 */
-	if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
-	    pmac_mb.model_id == PMAC_TYPE_YIKES)
-		return 0;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	if (value) {
-		LOCK(flags);
-		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
-		UNLOCK(flags);
-		(void)MACIO_IN32(HEATHROW_FCR);
-	} else {
-		LOCK(flags);
-		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
-		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-		UNLOCK(flags);
-	}
-	return 0;
-}
-
-static u32 save_fcr[5] __pmacdata;
-static u32 save_mbcr __pmacdata;
-static u32 save_gpio_levels[2] __pmacdata;
-static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata;
-static u8 save_gpio_normal[KEYLARGO_GPIO_CNT] __pmacdata;
-static u32 save_unin_clock_ctl __pmacdata;
-static struct dbdma_regs save_dbdma[13] __pmacdata;
-static struct dbdma_regs save_alt_dbdma[13] __pmacdata;
-
-static void __pmac
-dbdma_save(struct macio_chip* macio, struct dbdma_regs* save)
-{
-	int i;
-	
-	/* Save state & config of DBDMA channels */
-	for (i=0; i<13; i++) {
-		volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*)
-			(macio->base + ((0x8000+i*0x100)>>2));
-		save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
-		save[i].cmdptr = in_le32(&chan->cmdptr);
-		save[i].intr_sel = in_le32(&chan->intr_sel);
-		save[i].br_sel = in_le32(&chan->br_sel);
-		save[i].wait_sel = in_le32(&chan->wait_sel);
-	}
-}
-
-static void __pmac
-dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save)
-{
-	int i;
-	
-	/* Save state & config of DBDMA channels */
-	for (i=0; i<13; i++) {
-		volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*)
-			(macio->base + ((0x8000+i*0x100)>>2));
-		out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
-		while (in_le32(&chan->status) & ACTIVE)
-			mb();
-		out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
-		out_le32(&chan->cmdptr, save[i].cmdptr);
-		out_le32(&chan->intr_sel, save[i].intr_sel);
-		out_le32(&chan->br_sel, save[i].br_sel);
-		out_le32(&chan->wait_sel, save[i].wait_sel);
-	}
-}
-
-static void __pmac
-heathrow_sleep(struct macio_chip* macio, int secondary)
-{
-	if (secondary) {
-		dbdma_save(macio, save_alt_dbdma);
-		save_fcr[2] = MACIO_IN32(0x38);
-		save_fcr[3] = MACIO_IN32(0x3c);
-	} else {
-		dbdma_save(macio, save_dbdma);
-		save_fcr[0] = MACIO_IN32(0x38);
-		save_fcr[1] = MACIO_IN32(0x3c);
-		save_mbcr = MACIO_IN32(0x34);
-		/* Make sure sound is shut down */
-		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
-		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-		/* This seems to be necessary as well or the fan
-		 * keeps coming up and battery drains fast */
-		MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
-		/* Make sure eth is down even if module or sleep
-		 * won't work properly */
-		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
-	}
-	/* Make sure modem is shut down */
-	MACIO_OUT8(HRW_GPIO_MODEM_RESET,
-		MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
-	MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-	MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
-
-	/* Let things settle */
-	(void)MACIO_IN32(HEATHROW_FCR);
-	mdelay(1);
-}
-
-static void __pmac
-heathrow_wakeup(struct macio_chip* macio, int secondary)
-{
-	if (secondary) {
-		MACIO_OUT32(0x38, save_fcr[2]);
-		(void)MACIO_IN32(0x38);
-		mdelay(1);
-		MACIO_OUT32(0x3c, save_fcr[3]);
-		(void)MACIO_IN32(0x38);
-		mdelay(10);
-		dbdma_restore(macio, save_alt_dbdma);
-	} else {
-		MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
-		(void)MACIO_IN32(0x38);
-		mdelay(1);
-		MACIO_OUT32(0x3c, save_fcr[1]);
-		(void)MACIO_IN32(0x38);
-		mdelay(1);
-		MACIO_OUT32(0x34, save_mbcr);
-		(void)MACIO_IN32(0x38);
-		mdelay(10);
-		dbdma_restore(macio, save_dbdma);
-	}
-}
-
-static int __pmac
-heathrow_sleep_state(struct device_node* node, int param, int value)
-{
-	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-		return -EPERM;
-	if (value == 1) {
-		if (macio_chips[1].type == macio_gatwick)
-			heathrow_sleep(&macio_chips[0], 1);
-		heathrow_sleep(&macio_chips[0], 0);
-	} else if (value == 0) {
-		heathrow_wakeup(&macio_chips[0], 0);
-		if (macio_chips[1].type == macio_gatwick)
-			heathrow_wakeup(&macio_chips[0], 1);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_scc_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	unsigned long		chan_mask;
-	u32			fcr;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	if (!strcmp(node->name, "ch-a"))
-		chan_mask = MACIO_FLAG_SCCA_ON;
-	else if (!strcmp(node->name, "ch-b"))
-		chan_mask = MACIO_FLAG_SCCB_ON;
-	else
-		return -ENODEV;
-
-	if (value) {
-		int need_reset_scc = 0;
-		int need_reset_irda = 0;
-		
-		LOCK(flags);
-		fcr = MACIO_IN32(KEYLARGO_FCR0);
-		/* Check if scc cell need enabling */
-		if (!(fcr & KL0_SCC_CELL_ENABLE)) {
-			fcr |= KL0_SCC_CELL_ENABLE;
-			need_reset_scc = 1;
-		}
-		if (chan_mask & MACIO_FLAG_SCCA_ON) {
-			fcr |= KL0_SCCA_ENABLE;
-			/* Don't enable line drivers for I2S modem */
-			if ((param & 0xfff) == PMAC_SCC_I2S1)
-				fcr &= ~KL0_SCC_A_INTF_ENABLE;
-			else
-				fcr |= KL0_SCC_A_INTF_ENABLE;
-		}
-		if (chan_mask & MACIO_FLAG_SCCB_ON) {
-			fcr |= KL0_SCCB_ENABLE;
-			/* Perform irda specific inits */
-			if ((param & 0xfff) == PMAC_SCC_IRDA) {
-				fcr &= ~KL0_SCC_B_INTF_ENABLE;
-				fcr |= KL0_IRDA_ENABLE;
-				fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
-				fcr |= KL0_IRDA_SOURCE1_SEL;
-				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
-				fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
-				need_reset_irda = 1;
-			} else
-				fcr |= KL0_SCC_B_INTF_ENABLE;
-		}
-		MACIO_OUT32(KEYLARGO_FCR0, fcr);
-		macio->flags |= chan_mask;
-		if (need_reset_scc)  {
-			MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			UNLOCK(flags);
-			mdelay(15);
-			LOCK(flags);
-			MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
-		}
-		if (need_reset_irda)  {
-			MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			UNLOCK(flags);
-			mdelay(15);
-			LOCK(flags);
-			MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
-		}
-		UNLOCK(flags);
-		if (param & PMAC_SCC_FLAG_XMON)
-			macio->flags |= MACIO_FLAG_SCC_LOCKED;
-	} else {
-		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
-			return -EPERM;
-		LOCK(flags);
-		fcr = MACIO_IN32(KEYLARGO_FCR0);
-		if (chan_mask & MACIO_FLAG_SCCA_ON)
-			fcr &= ~KL0_SCCA_ENABLE;
-		if (chan_mask & MACIO_FLAG_SCCB_ON) {
-			fcr &= ~KL0_SCCB_ENABLE;
-			/* Perform irda specific clears */
-			if ((param & 0xfff) == PMAC_SCC_IRDA) {
-				fcr &= ~KL0_IRDA_ENABLE;
-				fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
-				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
-				fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
-			}
-		}
-		MACIO_OUT32(KEYLARGO_FCR0, fcr);
-		if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
-			fcr &= ~KL0_SCC_CELL_ENABLE;
-			MACIO_OUT32(KEYLARGO_FCR0, fcr);
-		}
-		macio->flags &= ~(chan_mask);
-		UNLOCK(flags);
-		mdelay(10);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_modem_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	u8			gpio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-	
-	if (!value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		UNLOCK(flags);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-		mdelay(250);
-	}
-    	LOCK(flags);
-    	if (value) {
-    		MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-	    	UNLOCK(flags);
-	    	(void)MACIO_IN32(KEYLARGO_FCR2);
-		mdelay(250);
-    	} else {
-    		MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-	    	UNLOCK(flags);
-    	}
-	if (value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_ide_enable(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
-	    case 1:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
-	    case 2:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-core99_ide_reset(struct device_node* node, int param, int value)
-{
-	switch(param) {
-	    case 0:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
-	    case 1:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
-	    case 2:
-		return simple_feature_tweak(node, macio_unknown,
-			KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
-	    default:
-	    	return -ENODEV;
-	}
-}
-
-static int __pmac
-core99_gmac_enable(struct device_node* node, int param, int value)
-{
-	unsigned long flags;
-
-	LOCK(flags);
-	if (value)
-		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
-	else
-		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
-	(void)UN_IN(UNI_N_CLOCK_CNTL);
-	UNLOCK(flags);
-	udelay(20);
-
-	return 0;
-}
-
-static int __pmac
-core99_gmac_phy_reset(struct device_node* node, int param, int value)
-{
-	unsigned long flags;
-	struct macio_chip* macio;
-	
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-
-	LOCK(flags);
-	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
-	(void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
-	UNLOCK(flags);
-	mdelay(10);
-	LOCK(flags);
-	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE
-		| KEYLARGO_GPIO_OUTOUT_DATA);
-	UNLOCK(flags);
-	mdelay(10);
-
-	return 0;
-}
-
-static int __pmac
-core99_sound_chip_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-
-	/* Do a better probe code, screamer G4 desktops &
-	 * iMacs can do that too, add a recalibrate  in
-	 * the driver as well
-	 */
-	if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
-	    pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
-		LOCK(flags);
-		if (value)
-	    		MACIO_OUT8(KL_GPIO_SOUND_POWER,
-	    			KEYLARGO_GPIO_OUTPUT_ENABLE |
-	    			KEYLARGO_GPIO_OUTOUT_DATA);
-	    	else
-	    		MACIO_OUT8(KL_GPIO_SOUND_POWER,
-	    			KEYLARGO_GPIO_OUTPUT_ENABLE);
-	    	(void)MACIO_IN8(KL_GPIO_SOUND_POWER);
-	    	UNLOCK(flags);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_airport_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	unsigned long		flags;
-	int			state;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	
-	/* Hint: we allow passing of macio itself for the sake of the
-	 * sleep code
-	 */
-	if (node != macio->of_node &&
-	    (!node->parent || node->parent != macio->of_node))
-		return -ENODEV;
-	state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
-	if (value == state)
-		return 0;
-	if (value) {
-		/* This code is a reproduction of OF enable-cardslot
-		 * and init-wireless methods, slightly hacked until
-		 * I got it working.
-		 */
-		LOCK(flags);
-		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
-		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
-		UNLOCK(flags);
-		mdelay(10);
-		LOCK(flags);
-		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
-		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
-		UNLOCK(flags);
-
-		mdelay(10);
-
-		LOCK(flags);
-		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
-		(void)MACIO_IN32(KEYLARGO_FCR2);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
-		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
-		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
-		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
-		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
-		udelay(10);
-		MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
-		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
-		UNLOCK(flags);
-		udelay(10);
-		MACIO_OUT32(0x1c000, 0);
-		mdelay(1);
-		MACIO_OUT8(0x1a3e0, 0x41);
-		(void)MACIO_IN8(0x1a3e0);
-		udelay(10);
-		LOCK(flags);
-		MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
-		(void)MACIO_IN32(KEYLARGO_FCR2);
-		UNLOCK(flags);
-		mdelay(100);
-
-		macio->flags |= MACIO_FLAG_AIRPORT_ON;
-	} else {
-		LOCK(flags);
-		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
-		(void)MACIO_IN32(KEYLARGO_FCR2);
-		MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
-		MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
-		MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
-		MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
-		MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
-		(void)MACIO_IN8(KL_GPIO_AIRPORT_4);
-		UNLOCK(flags);
-
-		macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
-	}
-	return 0;
-}
-
-#ifdef CONFIG_SMP
-static int __pmac
-core99_reset_cpu(struct device_node* node, int param, int value)
-{
-	const int reset_lines[] = {	KL_GPIO_RESET_CPU0,
-					KL_GPIO_RESET_CPU1,
-					KL_GPIO_RESET_CPU2,
-					KL_GPIO_RESET_CPU3 };
-	int reset_io;
-	unsigned long flags;
-	struct macio_chip* macio;
-	
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	if (param > 3 || param < 0)
-		return -ENODEV;
-
-	reset_io = reset_lines[param];
-	
-	LOCK(flags);
-	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
-	(void)MACIO_IN8(reset_io);
-	udelay(1);
-	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-	(void)MACIO_IN8(reset_io);
-	UNLOCK(flags);
-
-	return 0;
-}
-#endif /* CONFIG_SMP */
-
-static int __pmac
-core99_usb_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip* macio;
-	unsigned long flags;
-	char* prop;
-	int number;
-	u32 reg;
-	
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	
-	prop = (char *)get_property(node, "AAPL,clock-id", NULL);
-	if (!prop)
-		return -ENODEV;
-	if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0)
-		number = 0;
-	else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0)
-		number = 2;
-	else
-		return -ENODEV;
-
-	/* Sorry for the brute-force locking, but this is only used during
-	 * sleep and the timing seem to be critical
-	 */
-	LOCK(flags);
-	if (value) {
-		/* Turn ON */
-		if (number == 0) {
-			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			UNLOCK(flags);
-			mdelay(1);
-			LOCK(flags);
-			MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
-		} else {
-			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
-			UNLOCK(flags);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			mdelay(1);
-			LOCK(flags);
-			MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
-		}
-		reg = MACIO_IN32(KEYLARGO_FCR4);
-		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
-		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
-		MACIO_OUT32(KEYLARGO_FCR4, reg);
-		(void)MACIO_IN32(KEYLARGO_FCR4);
-		udelay(10);
-	} else {
-		/* Turn OFF */
-		reg = MACIO_IN32(KEYLARGO_FCR4);
-		reg |=	KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
-		reg |=	KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
-		MACIO_OUT32(KEYLARGO_FCR4, reg);
-		(void)MACIO_IN32(KEYLARGO_FCR4);
-		udelay(1);
-		if (number == 0) {
-			MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			udelay(1);
-			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-		} else {
-			MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-			udelay(1);
-			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
-			(void)MACIO_IN32(KEYLARGO_FCR0);
-		}
-		udelay(1);
-	}
-	UNLOCK(flags);
-
-	return 0;
-}
-
-static int __pmac
-core99_firewire_enable(struct device_node* node, int param, int value)
-{
-	unsigned long flags;
-	struct macio_chip* macio;
-
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
-		return -ENODEV;
-	
-	LOCK(flags);
-	if (value) {
-		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
-		(void)UN_IN(UNI_N_CLOCK_CNTL);
-	} else {
-		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
-		(void)UN_IN(UNI_N_CLOCK_CNTL);
-	}
-	UNLOCK(flags);
-	mdelay(1);
-
-	return 0;
-}
-
-static int __pmac
-core99_firewire_cable_power(struct device_node* node, int param, int value)
-{
-	unsigned long flags;
-	struct macio_chip* macio;
-
-	/* Trick: we allow NULL node */
-	if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
-	    	return -ENODEV;
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
-		return -ENODEV;
-	
-	LOCK(flags);
-	if (value) {
-		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
-		MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
-		udelay(10);
-	} else {
-		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
-		MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
-	}
-	UNLOCK(flags);
-	mdelay(1);
-
-	return 0;
-}
-
-static int __pmac
-core99_read_gpio(struct device_node* node, int param, int value)
-{
-	struct macio_chip* macio = &macio_chips[0];
-	
-	return MACIO_IN8(param);
-}
-
-
-static int __pmac
-core99_write_gpio(struct device_node* node, int param, int value)
-{
-	struct macio_chip* macio = &macio_chips[0];
-
-	MACIO_OUT8(param, (u8)(value & 0xff));
-	return 0;
-}
-
-static void __pmac
-keylargo_shutdown(struct macio_chip* macio, int restart)
-{
-	u32 temp;
-
-	mdelay(1);
-	MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
-	(void)MACIO_IN32(KEYLARGO_FCR0);
-	mdelay(100);
-
-	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-				KL0_SCC_CELL_ENABLE |
-		      		KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
-		      		KL0_IRDA_CLK19_ENABLE);
-
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-
-	MACIO_BIC(KEYLARGO_FCR1,
-		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
-		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
-		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
-		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
-		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
-		KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
-		KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
-		KL1_UIDE_ENABLE);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
-
-	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
- 	udelay(10);
- 	MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
- 	udelay(10);
-	temp = MACIO_IN32(KEYLARGO_FCR3);
-	if (macio->rev >= 2)
-		temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL);
-		
-	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-		KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12;
-	temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
-		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
-	MACIO_OUT32(KEYLARGO_FCR3, temp);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
-}
-
-static void __pmac
-pangea_shutdown(struct macio_chip* macio, int restart)
-{
-	u32 temp;
-
-	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-				KL0_SCC_CELL_ENABLE |
-				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
-
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-
-	MACIO_BIC(KEYLARGO_FCR1,
-		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
-		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
-		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
-		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
-		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
-		KL1_UIDE_ENABLE);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
-
-	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
- 	udelay(10);
-	temp = MACIO_IN32(KEYLARGO_FCR3);
-	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-		KL3_SHUTDOWN_PLLKW35;
-	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
-		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
-	MACIO_OUT32(KEYLARGO_FCR3, temp);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
-}
-
-static int __pmac
-core99_sleep(void)
-{
-	struct macio_chip* macio;
-	int i;
-
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	
-	/* We power off the wireless slot in case it was not done
-	 * by the driver. We don't power it on automatically however
-	 */
-	if (macio->flags & MACIO_FLAG_AIRPORT_ON)
-		core99_airport_enable(macio->of_node, 0, 0);
-
-	/* We power off the FW cable. Should be done by the driver... */
-	if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
-		core99_firewire_enable(NULL, 0, 0);
-		core99_firewire_cable_power(NULL, 0, 0);
-	}
-
-	/* We make sure int. modem is off (in case driver lost it) */
-	core99_modem_enable(macio->of_node, 0, 0);
-	/* We make sure the sound is off as well */
-	core99_sound_chip_enable(macio->of_node, 0, 0);
-	 
-	/*
-	 * Save various bits of KeyLargo
-	 */
-
-	/* Save the state of the various GPIOs */
-	save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
-	save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
-	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
-		save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
-	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
-		save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
-
-	/* Save the FCRs */
-	save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
-	save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
-	save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
-	save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
-	save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
-	save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
-
-	/* Save state & config of DBDMA channels */
-	dbdma_save(macio, save_dbdma);
-	
-	/*
-	 * Turn off as much as we can
-	 */
-	if (macio->type == macio_pangea)
-		pangea_shutdown(macio, 0);
-	else if (macio->type == macio_keylargo)
-		keylargo_shutdown(macio, 0);
-	
-	/* 
-	 * Put the host bridge to sleep
-	 */
-
-	save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
-	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
-		~(UNI_N_CLOCK_CNTL_GMAC|UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
-	udelay(100);
-	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
-	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
-
-	/*
-	 * FIXME: A bit of black magic with OpenPIC (don't ask me why)
-	 */
-	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
-		MACIO_BIS(0x506e0, 0x00400000);
-		MACIO_BIS(0x506e0, 0x80000000);
-	}
-	return 0;
-}
-
-static int __pmac
-core99_wake_up(void)
-{
-	struct macio_chip* macio;
-	int i;
-
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-
-	/*
-	 * Wakeup the host bridge
-	 */
-	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
-	udelay(10);
-	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
-	udelay(10);
-	
-	/*
-	 * Restore KeyLargo
-	 */
-	 
-	MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
-	(void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
-	MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
-	(void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
-
-	dbdma_restore(macio, save_dbdma);
-
-	MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
-	MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
-	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
-		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
-	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
-		MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
-
-	/* FIXME more black magic with OpenPIC ... */
-	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
-		MACIO_BIC(0x506e0, 0x00400000);
-		MACIO_BIC(0x506e0, 0x80000000);
-	}
-
-	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
-	udelay(100);
-
-	return 0;
-}
-
-static int __pmac
-core99_sleep_state(struct device_node* node, int param, int value)
-{
-	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-		return -EPERM;
-	if (value == 1)
-		return core99_sleep();
-	else if (value == 0)
-		return core99_wake_up();
-	return 0;
-}
-
-static int __pmac
-pangea_modem_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	u8			gpio;
-	unsigned long		flags;
-	
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-	
-	if (!value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		UNLOCK(flags);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-		mdelay(250);
-	}
-    	LOCK(flags);
-	if (value) {
-		MACIO_OUT8(KL_GPIO_MODEM_POWER,
-			KEYLARGO_GPIO_OUTPUT_ENABLE);
-    		UNLOCK(flags);
-	    	(void)MACIO_IN32(KEYLARGO_FCR2);
-		mdelay(250);
-	} else {
-		MACIO_OUT8(KL_GPIO_MODEM_POWER,
-			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-    		UNLOCK(flags);
-	}
-	if (value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250);
-	}
-	return 0;
-}
-
-
-static int __pmac
-generic_get_mb_info(struct device_node* node, int param, int value)
-{
-	switch(param) {
-		case PMAC_MB_INFO_MODEL:
-			return pmac_mb.model_id;
-		case PMAC_MB_INFO_FLAGS:
-			return pmac_mb.board_flags;
-		case PMAC_MB_INFO_NAME:	
-			/* hack hack hack... but should work */
-			*((const char **)value) = pmac_mb.model_name;
-			break;
-	}
-	return 0;
-}
-
-
-/* 
- * Table definitions
- */
- 
-/* Used on any machine
- */
-static struct feature_table_entry any_features[]  __pmacdata = {
-	{ PMAC_FTR_GET_MB_INFO,		generic_get_mb_info },
-	{ 0, NULL }
-};
-
-/* OHare based motherboards. Currently, we only use these on the
- * 2400,3400 and 3500 series powerbooks. Some older desktops seem
- * to have issues with turning on/off those asic cells
- */
-static struct feature_table_entry ohare_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
-	{ PMAC_FTR_SWIM3_ENABLE,	ohare_floppy_enable },
-	{ PMAC_FTR_MESH_ENABLE,		ohare_mesh_enable },
-	{ PMAC_FTR_IDE_ENABLE,		ohare_ide_enable},
-	{ PMAC_FTR_IDE_RESET,		ohare_ide_reset},
-	{ PMAC_FTR_SLEEP_STATE,		ohare_sleep_state },
-	{ 0, NULL }
-};
-
-/* Heathrow desktop machines (Beige G3).
- * Separated as some features couldn't be properly tested
- * and the serial port control bits appear to confuse it.
- */
-static struct feature_table_entry heathrow_desktop_features[]  __pmacdata = {
-	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
-	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
-	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
-	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
-	{ 0, NULL }
-};
-
-/* Heathrow based laptop, that is the Wallstreet and mainstreet
- * powerbooks.
- */
-static struct feature_table_entry heathrow_laptop_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
-	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
-	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
-	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
-	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
-	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
-	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
-	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
-	{ 0, NULL }
-};
-
-/* Paddington based machines
- * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
- */
-static struct feature_table_entry paddington_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
-	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
-	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
-	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
-	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
-	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
-	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
-	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
-	{ 0, NULL }
-};
-
-/* Core99 & MacRISC 2 machines (all machines released since the
- * iBook (included), that is all AGP machines, except pangea
- * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
- * used on iBook2 & iMac "flow power".
- */
-static struct feature_table_entry core99_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
-	{ PMAC_FTR_MODEM_ENABLE,	core99_modem_enable },
-	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
-	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
-	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
-	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
-	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
-	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
-	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
-	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
-	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
-#ifdef CONFIG_SMP
-	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
-#endif /* CONFIG_SMP */
-	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
-	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
-	{ 0, NULL }
-};
-
-/* Pangea features
- */
-static struct feature_table_entry pangea_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
-	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
-	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
-	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
-	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
-	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
-	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
-	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
-	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
-	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
-	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
-	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
-	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
-	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
-	{ 0, NULL }
-};
-	
-static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
-	/* Warning: ordering is important as some models may claim
-	 * beeing compatible with several types
-	 */
-	{	"AAPL,8500",			"PowerMac 8500/8600",
-		PMAC_TYPE_PSURGE,		NULL,
-		0
-	},
-	{	"AAPL,9500",			"PowerMac 9500/9600",
-		PMAC_TYPE_PSURGE,		NULL,
-		0
-	},
-	{	"AAPL,7500",			"PowerMac 7500",
-		PMAC_TYPE_PSURGE,		NULL,
-		0
-	},
-	{	"AAPL,ShinerESB",		"Apple Network Server",
-		PMAC_TYPE_ANS,			NULL,
-		0
-	},
-	{	"AAPL,e407",			"Alchemy",
-		PMAC_TYPE_ALCHEMY,		NULL,
-		0
-	},
-	{	"AAPL,e411",			"Gazelle",
-		PMAC_TYPE_GAZELLE,		NULL,
-		0
-	},
-	{	"AAPL,3400/2400",		"PowerBook 3400",
-		PMAC_TYPE_HOOPER,		ohare_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"AAPL,3500",			"PowerBook 3500",
-		PMAC_TYPE_KANGA,		ohare_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"AAPL,Gossamer",		"PowerMac G3 (Gossamer)",
-		PMAC_TYPE_GOSSAMER,		heathrow_desktop_features,
-		0
-	},
-	{	"AAPL,PowerMac G3",		"PowerMac G3 (Silk)",
-		PMAC_TYPE_SILK,			heathrow_desktop_features,
-		0
-	},
-	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
-		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"AAPL,PowerBook1,1",		"PowerBook 101 (Lombard)",
-		PMAC_TYPE_101_PBOOK,		paddington_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"iMac,1",			"iMac (first generation)",
-		PMAC_TYPE_ORIG_IMAC,		paddington_features,
-		0
-	},
-	{	"PowerMac4,1",			"iMac \"Flower Power\"",
-		PMAC_TYPE_PANGEA_IMAC,		pangea_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerBook4,3",			"iBook 2 with 14\" LCD",
-		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook4,2",			"iBook 2 with 14\" LCD",
-		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook4,1",			"iBook 2",
-		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerMac4,2",			"Flat panel iMac",
-		PMAC_TYPE_FLAT_PANEL_IMAC,	pangea_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerMac1,1",			"Blue&White G3",
-		PMAC_TYPE_YOSEMITE,		paddington_features,
-		0
-	},
-	{	"PowerMac1,2",			"PowerMac G4 PCI Graphics",
-		PMAC_TYPE_YIKES,		paddington_features,
-		0
-	},
-	{	"PowerBook2,1",			"iBook (first generation)",
-		PMAC_TYPE_ORIG_IBOOK,		core99_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerMac3,1",			"PowerMac G4 AGP Graphics",
-		PMAC_TYPE_SAWTOOTH,		core99_features,
-		0
-	},
-	{	"PowerMac3,2",			"PowerMac G4 AGP Graphics",
-		PMAC_TYPE_SAWTOOTH,		core99_features,
-		0
-	},
-	{	"PowerMac3,3",			"PowerMac G4 AGP Graphics",
-		PMAC_TYPE_SAWTOOTH,		core99_features,
-		0
-	},
-	{	"PowerMac2,1",			"iMac FireWire",
-		PMAC_TYPE_FW_IMAC,		core99_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerMac2,2",			"iMac FireWire",
-		PMAC_TYPE_FW_IMAC,		core99_features,
-		PMAC_MB_CAN_SLEEP
-	},
-	{	"PowerBook2,2",			"iBook FireWire",
-		PMAC_TYPE_FW_IBOOK,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerMac5,1",			"PowerMac G4 Cube",
-		PMAC_TYPE_CUBE,			core99_features,
-	},
-	{	"PowerMac3,4",			"PowerMac G4 Silver",
-		PMAC_TYPE_QUICKSILVER,		core99_features,
-		0
-	},
-	{	"PowerMac3,5",			"PowerMac G4 Silver",
-		PMAC_TYPE_QUICKSILVER,		core99_features,
-		0
-	},
-	{	"PowerBook3,1",			"PowerBook Pismo",
-		PMAC_TYPE_PISMO,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook3,2",			"PowerBook Titanium",
-		PMAC_TYPE_TITANIUM,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook3,3",			"PowerBook Titanium II",
-		PMAC_TYPE_TITANIUM2,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-	{	"PowerBook3,4",			"PowerBook Titanium III",
-		PMAC_TYPE_TITANIUM3,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
-	},
-};
-
-/*
- * The toplevel feature_call callback
- */
-int __pmac
-pmac_do_feature_call(unsigned int selector, ...)
-{
-	struct device_node* node;
-	int param, value, i;
-	feature_call func = NULL;
-	va_list args;
-	
-	if (pmac_mb.features)
-		for (i=0; pmac_mb.features[i].function; i++)
-			if (pmac_mb.features[i].selector == selector) {
-				func = pmac_mb.features[i].function;
-				break;
-			}
-	if (!func)
-		for (i=0; any_features[i].function; i++)
-			if (any_features[i].selector == selector) {
-				func = any_features[i].function;
-				break;
-			}
-	if (!func)
-		return -ENODEV;
-
-	va_start(args, selector);
-	node = (struct device_node*)va_arg(args, void*);
-	param = va_arg(args, int);
-	value = va_arg(args, int);
-	va_end(args);
-
-	return func(node, param, value);
-}
-
-static int __init
-probe_motherboard(void)
-{
-	int i;
-	struct macio_chip* macio = &macio_chips[0];
-
-	/* Lookup known motherboard type in device-tree */
-	for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
-	    if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
-		pmac_mb = pmac_mb_defs[i];
-		goto found;
-	    }
-	}
-
-	/* Fallback to selection depending on mac-io chip type */
-	switch(macio->type) {
-	    case macio_grand_central:
-		pmac_mb.model_id = PMAC_TYPE_PSURGE;
-		pmac_mb.model_name = "Unknown PowerSurge";
-		break;
-	    case macio_ohare:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
-		pmac_mb.model_name = "Unknown OHare-based";
-	    	break;
-	    case macio_heathrow:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
-		pmac_mb.model_name = "Unknown Heathrow-based";
-		pmac_mb.features = heathrow_desktop_features;
-		break;
-	    case macio_paddington:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
-		pmac_mb.model_name = "Unknown Paddington-based";
-	    	pmac_mb.features = paddington_features;
-		break;
-	    case macio_keylargo:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
-		pmac_mb.model_name = "Unknown Keylargo-based";
-	    	pmac_mb.features = core99_features;
-		break;
-	    case macio_pangea:
-		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
-		pmac_mb.model_name = "Unknown Pangea-based";
-	    	pmac_mb.features = pangea_features;
-		break;
-	    default:
-	    	return -ENODEV;
-	}
-found:
-	/* Fixup Hooper vs. Comet */
-	if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
-		u32* mach_id_ptr = (u32*)ioremap(0xf3000034, 4);
-		if (!mach_id_ptr)
-			return -ENODEV;
-		/* Here, I used to disable the media-bay on comet. It
-		 * appears this is wrong, the floppy connector is actually
-		 * a kind of media-bay and works with the current driver.
-		 */
-		if ((*mach_id_ptr) & 0x20000000UL)
-			pmac_mb.model_id = PMAC_TYPE_COMET;
-		iounmap(mach_id_ptr);
-	}
-
-	/* Set default value of powersave_nap on machines that support it.
-	 * It appears that uninorth rev 3 has a problem with it, we don't
-	 * enable it on those. In theory, the flush-on-lock property is
-	 * supposed to be set when not supported, but I'm not very confident
-	 * that all Apple OF revs did it properly, I do it the paranoid way.
-	 */
-	while (uninorth_base && uninorth_rev > 3) {
-		struct device_node* np = find_path_device("/cpus");
-		u32 pvr = mfspr(PVR);
-		if (!np || !np->child) {
-			printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
-			break;
-		}
-		np = np->child;
-		/* Nap mode not supported on SMP */
-		if (np->sibling)
-			break;
-		/* Nap mode not supported if flush-on-lock property is present */
-		if (get_property(np, "flush-on-lock", NULL))
-			break;
-		/* Some 7450 may have problem with NAP mode too ... */
-		if (((pvr >> 16) == 0x8000) && ((pvr & 0xffff) < 0x0201))
-			break;
-		powersave_nap = 1;
-		printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
-		break;
-	}
-
-	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
-	return 0;
-}
-
-/* Initialize the Core99 UniNorth host bridge and memory controller
- */
-static void __init
-probe_uninorth(void)
-{
-	unsigned long actrl;
-	
-	/* Locate core99 Uni-N */
-	uninorth_node = find_devices("uni-n");
-	if (uninorth_node && uninorth_node->n_addrs > 0) {
-		uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x1000);
-		uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
-	} else
-		uninorth_node = NULL;
-		
-	if (!uninorth_node)
-		return;
-	
-	printk(KERN_INFO "Found Uninorth memory controller & host bridge, revision: %d\n",
-			uninorth_rev);
-
-	/* Set the arbitrer QAck delay according to what Apple does
-	 */
-	if (uninorth_rev < 0x10) {
-		actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
-		actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
-			UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
-		UN_OUT(UNI_N_ARB_CTRL, actrl);
-	}
-}	
-
-static void __init
-probe_one_macio(const char* name, const char* compat, int type)
-{
-	struct device_node*	node;
-	int			i;
-	volatile u32*		base;
-	u32*			revp;
-	
-	node = find_devices(name);
-	if (!node || !node->n_addrs)
-		return;
-	if (compat)
-		do {
-			if (device_is_compatible(node, compat))
-				break;
-			node = node->next;
-		} while (node);
-	if (!node)
-		return;
-	for(i=0; i<MAX_MACIO_CHIPS; i++) {
-		if (!macio_chips[i].of_node)
-			break;
-		if (macio_chips[i].of_node == node)
-			return;
-	}
-	if (i >= MAX_MACIO_CHIPS) {
-		printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
-		printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
-		return;
-	}
-	base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size);
-	if (!base) {
-		printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
-		return;
-	}
-	if (type == macio_keylargo) {
-		u32* did = (u32 *)get_property(node, "device-id", NULL);
-		if (*did == 0x00000025)
-			type = macio_pangea;
-	}
-	macio_chips[i].of_node	= node;
-	macio_chips[i].type	= type;
-	macio_chips[i].base	= base;
-	macio_chips[i].flags	= MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
-	revp = (u32 *)get_property(node, "revision-id", NULL);
-	if (revp)
-		macio_chips[i].rev = *revp;
-	printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
-		macio_names[type], macio_chips[i].rev, macio_chips[i].base);
-}
-
-static int __init
-probe_macios(void)
-{
-	/* Warning, ordering is important */
-	probe_one_macio("gc", NULL, macio_grand_central);
-	probe_one_macio("ohare", NULL, macio_ohare);
-	probe_one_macio("pci106b,7", NULL, macio_ohareII);
-	probe_one_macio("mac-io", "keylargo", macio_keylargo);
-	probe_one_macio("mac-io", "paddington", macio_paddington);
-	probe_one_macio("mac-io", "gatwick", macio_gatwick);
-	probe_one_macio("mac-io", "heathrow", macio_heathrow);
-
-	/* Make sure the "main" macio chip appear first */
-	if (macio_chips[0].type == macio_gatwick
-	    && macio_chips[1].type == macio_heathrow) {
-		struct macio_chip temp = macio_chips[0];
-		macio_chips[0] = macio_chips[1];
-		macio_chips[1] = temp;
-	}
-	if (macio_chips[0].type == macio_ohareII
-	    && macio_chips[1].type == macio_ohare) {
-		struct macio_chip temp = macio_chips[0];
-		macio_chips[0] = macio_chips[1];
-		macio_chips[1] = temp;
-	}
-
-	return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
-}
-
-static void __init
-initial_serial_shutdown(struct device_node* np)
-{
-	int len;
-	struct slot_names_prop {
-		int	count;
-		char	name[1];
-	} *slots;
-	char *conn;
-	int port_type = PMAC_SCC_ASYNC;
-	int modem = 0;
-	
-	slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
-	conn = get_property(np, "AAPL,connector", &len);
-	if (conn && (strcmp(conn, "infrared") == 0))
-		port_type = PMAC_SCC_IRDA;
-	else if (device_is_compatible(np, "cobalt"))
-		modem = 1;
-	else if (slots && slots->count > 0) {
-		if (strcmp(slots->name, "IrDA") == 0)
-			port_type = PMAC_SCC_IRDA;
-		else if (strcmp(slots->name, "Modem") == 0)
-			modem = 1;
-	}
-	if (modem)
-		pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
-	pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
-}
-
-static void __init
-set_initial_features(void)
-{
-	struct device_node* np;
-	
-	/* That hack appears to be necessary for some StarMax motherboards
-	 * but I'm not too sure it was audited for side-effects on other
-	 * ohare based machines...
-	 * Since I still have difficulties figuring the right way to
-	 * differenciate them all and since that hack was there for a long
-	 * time, I'll keep it around
-	 */
-	if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
-		struct macio_chip* macio = &macio_chips[0];
-		MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
-	} else if (macio_chips[0].type == macio_ohare) {
-		struct macio_chip* macio = &macio_chips[0];
-		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-	} else if (macio_chips[1].type == macio_ohare) {
-		struct macio_chip* macio = &macio_chips[1];
-		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-	}
-
-	if (macio_chips[0].type == macio_keylargo ||
-	    macio_chips[0].type == macio_pangea) {
-		/* Enable GMAC for now for PCI probing. It will be disabled
-		 * later on after PCI probe
-		 */
-		np = find_devices("ethernet");
-		while(np) {
-			if (np->parent
-			    && device_is_compatible(np->parent, "uni-north")
-			    && device_is_compatible(np, "gmac"))
-				core99_gmac_enable(np, 0, 1);
-			np = np->next;
-		}
-
-		/* Enable FW before PCI probe. Will be disabled later on
-		 * Note: We should have a batter way to check that we are
-		 * dealing with uninorth internal cell and not a PCI cell
-		 * on the external PCI. The code below works though.
-		 */
-		np = find_devices("firewire");
-		while(np) {
-			if (np->parent
-			    && device_is_compatible(np->parent, "uni-north")
-			    && (device_is_compatible(np, "pci106b,18") || 
-	     		        device_is_compatible(np, "pci106b,30") ||
-	     		        device_is_compatible(np, "pci11c1,5811"))) {
-				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
-				core99_firewire_enable(np, 0, 1);
-			}
-			np = np->next;
-		}
-		
-		/* Switch airport off */
-		np = find_devices("radio");
-		while(np) {
-			if (np && np->parent == macio_chips[0].of_node) {
-				macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
-				core99_airport_enable(np, 0, 0);
-			}
-			np = np->next;
-		}
-	}
-
-	/* On all machines that support sound PM, switch sound off */
-	if (macio_chips[0].of_node)
-		pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
-			macio_chips[0].of_node, 0, 0);
-
-	/* While on some desktop G3s, we turn it back on */
-	if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
-		&& (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
-		    pmac_mb.model_id == PMAC_TYPE_SILK)) {
-		struct macio_chip* macio = &macio_chips[0];
-		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
-	}
-
-
-	/* On all machines, switch modem & serial ports off */
-	np = find_devices("ch-a");
-	while(np) {
-		initial_serial_shutdown(np);
-		np = np->next;
-	}
-	np = find_devices("ch-b");
-	while(np) {
-		initial_serial_shutdown(np);
-		np = np->next;
-	}
-	
-	/* Let hardware settle down */
-	mdelay(10);
-}
-
-void __init
-pmac_feature_init(void)
-{
-	/* Detect the UniNorth memory controller */
-	probe_uninorth();
-
-	/* Probe mac-io controllers */
-	if (probe_macios()) {
-		printk(KERN_WARNING "No mac-io chip found\n");
-		return;
-	}
-
-	/* Probe machine type */
-	if (probe_motherboard())
-		printk(KERN_WARNING "Unknown PowerMac !\n");
-
-	/* Set some initial features (turn off some chips that will
-	 * be later turned on)
-	 */
-	set_initial_features();
-}
-
-void __init
-pmac_feature_late_init(void)
-{
-	struct device_node* np;
-	
-	/* Request some resources late */
-	if (uninorth_node)
-		request_OF_resource(uninorth_node, 0, NULL);
-	np = find_devices("hammerhead");
-	if (np)
-		request_OF_resource(np, 0, NULL);
-	np = find_devices("interrupt-controller");
-	if (np)
-		request_OF_resource(np, 0, NULL);
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pmac_nvram.c linux-2.4.20-pre2/arch/ppc/kernel/pmac_nvram.c
--- linux-2.4.20-pre1/arch/ppc/kernel/pmac_nvram.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/pmac_nvram.c	Wed Dec 31 16:00:00 1969
@@ -1,402 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_nvram.c 1.17 12/01/01 20:09:06 benh
- */
-/*
- * Miscellaneous procedures for dealing with the PowerMac hardware.
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/nvram.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-#undef DEBUG
-
-#define NVRAM_SIZE		0x2000	/* 8kB of non-volatile RAM */
-
-#define CORE99_SIGNATURE	0x5a
-#define CORE99_ADLER_START	0x14
-
-/* Core99 nvram is a flash */
-#define CORE99_FLASH_STATUS_DONE	0x80
-#define CORE99_FLASH_STATUS_ERR		0x38
-#define CORE99_FLASH_CMD_ERASE_CONFIRM	0xd0
-#define CORE99_FLASH_CMD_ERASE_SETUP	0x20
-#define CORE99_FLASH_CMD_RESET		0xff
-#define CORE99_FLASH_CMD_WRITE_SETUP	0x40
-
-/* CHRP NVRAM header */
-struct chrp_header {
-  u8		signature;
-  u8		cksum;
-  u16		len;
-  char          name[12];
-  u8		data[0];
-};
-
-struct core99_header {
-  struct chrp_header	hdr;
-  u32			adler;
-  u32			generation;
-  u32			reserved[2];
-};
-
-/*
- * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
- */
-static int nvram_naddrs;
-static volatile unsigned char *nvram_addr;
-static volatile unsigned char *nvram_data;
-static int nvram_mult, is_core_99;
-static int core99_bank = 0;
-static int nvram_partitions[3];
-
-/* FIXME: kmalloc fails to allocate the image now that I had to move it
- *        before time_init(). For now, I allocate a static buffer here
- *        but it's a waste of space on all but core99 machines
- */
-#if 0
-static char* nvram_image;
-#else
-static char nvram_image[NVRAM_SIZE] __pmacdata;
-#endif
-
-extern int pmac_newworld;
-
-static u8 __openfirmware
-chrp_checksum(struct chrp_header* hdr)
-{
-	u8 *ptr;
-	u16 sum = hdr->signature;
-	for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
-		sum += *ptr;
-	while (sum > 0xFF)
-		sum = (sum & 0xFF) + (sum>>8);
-	return sum;
-}
-
-static u32 __pmac
-core99_calc_adler(u8 *buffer)
-{
-	int cnt;
-	u32 low, high;
-
-   	buffer += CORE99_ADLER_START;
-	low = 1;
-	high = 0;
-	for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
-		if ((cnt % 5000) == 0) {
-			high  %= 65521UL;
-			high %= 65521UL;
-		}
-		low += buffer[cnt];
-		high += low;
-	}
-	low  %= 65521UL;
-	high %= 65521UL;
-  
-	return (high << 16) | low;
-}
-
-static u32 __pmac
-core99_check(u8* datas)
-{
-	struct core99_header* hdr99 = (struct core99_header*)datas;
-
-	if (hdr99->hdr.signature != CORE99_SIGNATURE) {
-#ifdef DEBUG
-		printk("Invalid signature\n");
-#endif		
-		return 0;
-	}
-	if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
-#ifdef DEBUG
-		printk("Invalid checksum\n");
-#endif
-		return 0;
-	}
-	if (hdr99->adler != core99_calc_adler(datas)) {
-#ifdef DEBUG
-		printk("Invalid adler\n");
-#endif
-		return 0;
-	}
-	return hdr99->generation;
-}
-
-static int __pmac
-core99_erase_bank(int bank)
-{
-	int stat, i;
-	
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-	
-	out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
-	out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
-	do { stat = in_8(base); }
-	while(!(stat & CORE99_FLASH_STATUS_DONE));
-	out_8(base, CORE99_FLASH_CMD_RESET);
-	if (stat & CORE99_FLASH_STATUS_ERR) {
-		printk("nvram: flash error 0x%02x on erase !\n", stat);
-		return -ENXIO;
-	}
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != 0xff) {
-			printk("nvram: flash erase failed !\n");
-			return -ENXIO;
-		}
-	return 0;
-}
-
-static int __pmac
-core99_write_bank(int bank, u8* datas)
-{
-	int i, stat = 0;
-	
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-	
-	for (i=0; i<NVRAM_SIZE; i++) {
-		out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
-		out_8(base+i, datas[i]);
-		do { stat = in_8(base); }
-		while(!(stat & CORE99_FLASH_STATUS_DONE));
-		if (stat & CORE99_FLASH_STATUS_ERR)
-			break;
-	}
-	out_8(base, CORE99_FLASH_CMD_RESET);
-	if (stat & CORE99_FLASH_STATUS_ERR) {
-		printk("nvram: flash error 0x%02x on write !\n", stat);
-		return -ENXIO;
-	}
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != datas[i]) {
-			printk("nvram: flash write failed !\n");
-			return -ENXIO;
-		}
-	return 0;	
-}
-
-static void __init
-lookup_partitions(void)
-{
-	u8 buffer[17];
-	int i, offset;
-	struct chrp_header* hdr;
-
-	if (pmac_newworld) {
-		nvram_partitions[pmac_nvram_OF] = -1;
-		nvram_partitions[pmac_nvram_XPRAM] = -1;
-		nvram_partitions[pmac_nvram_NR] = -1;
-		hdr = (struct chrp_header *)buffer;
-	
-		offset = 0;
-		buffer[16] = 0;
-		do {
-			for (i=0;i<16;i++)
-				buffer[i] = nvram_read_byte(offset+i);
-			if (!strcmp(hdr->name, "common"))
-				nvram_partitions[pmac_nvram_OF] = offset + 0x10;
-			if (!strcmp(hdr->name, "APL,MacOS75")) {
-				nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
-				nvram_partitions[pmac_nvram_NR] = offset + 0x110;
-			}
-			offset += (hdr->len * 0x10);
-		} while(offset < NVRAM_SIZE);
-	} else {
-		nvram_partitions[pmac_nvram_OF] = 0x1800;
-		nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
-		nvram_partitions[pmac_nvram_NR] = 0x1400;
-	}	
-#ifdef DEBUG
-	printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
-	printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
-	printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
-#endif	
-}
-
-void __init
-pmac_nvram_init(void)
-{
-	struct device_node *dp;
-
-	nvram_naddrs = 0;
-
-	dp = find_devices("nvram");
-	if (dp == NULL) {
-		printk(KERN_ERR "Can't find NVRAM device\n");
-		return;
-	}
-	nvram_naddrs = dp->n_addrs;
-	is_core_99 = device_is_compatible(dp, "nvram,flash");
-	if (is_core_99) {
-		int i;
-		u32 gen_bank0, gen_bank1;
-		
-		if (nvram_naddrs < 1) {
-			printk(KERN_ERR "nvram: no address\n");
-			return;
-		}
-#if 0
-		nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
-		if (!nvram_image) {
-			printk(KERN_ERR "nvram: can't allocate image\n");
-			return;
-		}
-#endif
-		nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
-#ifdef DEBUG
-		printk("nvram: Checking bank 0...\n");
-#endif
-		gen_bank0 = core99_check((u8 *)nvram_data);
-		gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
-		core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
-#ifdef DEBUG
-		printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
-		printk("nvram: Active bank is: %d\n", core99_bank);
-#endif
-		for (i=0; i<NVRAM_SIZE; i++)
-			nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
-	} else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
-		nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
-				     dp->addrs[0].size);
-		nvram_mult = 1;
-	} else if (nvram_naddrs == 1) {
-		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
-	} else if (nvram_naddrs == 2) {
-		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
-	} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
-		nvram_naddrs = -1;
-	} else {
-		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
-		       nvram_naddrs);
-	}
-	lookup_partitions();
-}
-
-void __pmac
-pmac_nvram_update(void)
-{
-	struct core99_header* hdr99;
-	
-	if (!is_core_99 || !nvram_data || !nvram_image)
-		return;
-	if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
-		NVRAM_SIZE))
-		return;
-#ifdef DEBUG
-	printk("Updating nvram...\n");
-#endif
-	hdr99 = (struct core99_header*)nvram_image;
-	hdr99->generation++;
-	hdr99->hdr.signature = CORE99_SIGNATURE;
-	hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
-	hdr99->adler = core99_calc_adler(nvram_image);
-	core99_bank = core99_bank ? 0 : 1;
-	if (core99_erase_bank(core99_bank)) {
-		printk("nvram: Error erasing bank %d\n", core99_bank);
-		return;
-	}
-	if (core99_write_bank(core99_bank, nvram_image))
-		printk("nvram: Error writing bank %d\n", core99_bank);
-}
-
-unsigned char __openfirmware
-nvram_read_byte(int addr)
-{
-	switch (nvram_naddrs) {
-#ifdef CONFIG_ADB_PMU
-	case -1: {
-		struct adb_request req;
-
-		if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
-				(addr >> 8) & 0xff, addr & 0xff))
-			break;
-		while (!req.complete)
-			pmu_poll();
-		return req.reply[0];
-	}
-#endif
-	case 1:
-		if (is_core_99)
-			return nvram_image[addr];
-		return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
-	case 2:
-		*nvram_addr = addr >> 5;
-		eieio();
-		return nvram_data[(addr & 0x1f) << 4];
-	}
-	return 0;
-}
-
-void __openfirmware
-nvram_write_byte(unsigned char val, int addr)
-{
-	switch (nvram_naddrs) {
-#ifdef CONFIG_ADB_PMU
-	case -1: {
-		struct adb_request req;
-
-		if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
-				(addr >> 8) & 0xff, addr & 0xff, val))
-			break;
-		while (!req.complete)
-			pmu_poll();
-		break;
-	}
-#endif
-	case 1:
-		if (is_core_99) {
-			nvram_image[addr] = val;
-			break;
-		}
-		nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
-		break;
-	case 2:
-		*nvram_addr = addr >> 5;
-		eieio();
-		nvram_data[(addr & 0x1f) << 4] = val;
-		break;
-	}
-	eieio();
-}
-
-int __pmac
-pmac_get_partition(int partition)
-{
-	return nvram_partitions[partition];
-}
-
-u8 __pmac
-pmac_xpram_read(int xpaddr)
-{
-	int offset = nvram_partitions[pmac_nvram_XPRAM];
-	
-	if (offset < 0)
-		return 0;
-		
-	return nvram_read_byte(xpaddr + offset);
-}
-
-void __pmac
-pmac_xpram_write(int xpaddr, u8 data)
-{
-	int offset = nvram_partitions[pmac_nvram_XPRAM];
-	
-	if (offset < 0)
-		return;
-		
-	nvram_write_byte(xpaddr + offset, data);
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pmac_pci.c linux-2.4.20-pre2/arch/ppc/kernel/pmac_pci.c
--- linux-2.4.20-pre1/arch/ppc/kernel/pmac_pci.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/pmac_pci.c	Wed Dec 31 16:00:00 1969
@@ -1,615 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_pci.c 1.35 05/06/02 01:37:30 benh
- */
-/*
- * Support for PCI bridges found on Power Macintoshes.
- * At present the "bandit" and "chaos" bridges are supported.
- * Fortunately you access configuration space in the same
- * way with either bridge.
- *
- * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-
-#include "pci.h"
-
-#undef DEBUG
-
-static void add_bridges(struct device_node *dev);
-
-/* XXX Could be per-controller, but I don't think we risk anything by
- * assuming we won't have both UniNorth and Bandit */
-static int has_uninorth;
-
-/*
- * Magic constants for enabling cache coherency in the bandit/PSX bridge.
- */
-#define BANDIT_DEVID_2	8
-#define BANDIT_REVID	3
-
-#define BANDIT_DEVNUM	11
-#define BANDIT_MAGIC	0x50
-#define BANDIT_COHERENT	0x40
-
-static int __init
-fixup_one_level_bus_range(struct device_node *node, int higher)
-{
-	for (; node != 0;node = node->sibling) {
-		int * bus_range;
-		unsigned int *class_code;			
-		int len;
-
-		/* For PCI<->PCI bridges or CardBus bridges, we go down */
-		class_code = (unsigned int *) get_property(node, "class-code", 0);
-		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
-			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
-			continue;
-		bus_range = (int *) get_property(node, "bus-range", &len);
-		if (bus_range != NULL && len > 2 * sizeof(int)) {
-			if (bus_range[1] > higher)
-				higher = bus_range[1];
-		}
-		higher = fixup_one_level_bus_range(node->child, higher);
-	}
-	return higher;
-}
-
-/* This routine fixes the "bus-range" property of all bridges in the
- * system since they tend to have their "last" member wrong on macs
- * 
- * Note that the bus numbers manipulated here are OF bus numbers, they
- * are not Linux bus numbers.
- */
-static void __init
-fixup_bus_range(struct device_node *bridge)
-{
-	int * bus_range;
-	int len;
-	
-	/* Lookup the "bus-range" property for the hose */		
-	bus_range = (int *) get_property(bridge, "bus-range", &len);
-	if (bus_range == NULL || len < 2 * sizeof(int)) {
-		printk(KERN_WARNING "Can't get bus-range for %s\n",
-			       bridge->full_name);
-		return;
-	}
-	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
-}
-
-/*
- * Apple MacRISC (UniNorth, Bandit, Chaos) PCI controllers.
- * 
- * The "Bandit" version is present in all early PCI PowerMacs,
- * and up to the first ones using Grackle. Some machines may
- * have 2 bandit controllers (2 PCI busses).
- * 
- * "Chaos" is used in some "Bandit"-type machines as a bridge
- * for the separate display bus. It is accessed the same
- * way as bandit, but cannot be probed for devices. It therefore
- * has its own config access functions.
- *
- * The "UniNorth" version is present in all Core99 machines
- * (iBook, G4, new IMacs, and all the recent Apple machines).
- * It contains 3 controllers in one ASIC.
- */
-
-#define MACRISC_CFA0(devfn, off)	\
-	((1 << (unsigned long)PCI_SLOT(dev_fn)) \
-	| (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
-	| (((unsigned long)(off)) & 0xFCUL))
-
-#define MACRISC_CFA1(bus, devfn, off)	\
-	((((unsigned long)(bus)) << 16) \
-	|(((unsigned long)(devfn)) << 8) \
-	|(((unsigned long)(off)) & 0xFCUL) \
-	|1UL)
-	
-static unsigned int __pmac
-macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset)
-{
-	unsigned int caddr;
-	
-	if (bus == hose->first_busno) {
-		if (dev_fn < (11 << 3))
-			return 0;
-		caddr = MACRISC_CFA0(dev_fn, offset);
-	} else
-		caddr = MACRISC_CFA1(bus, dev_fn, offset);
-	
-	/* Uninorth will return garbage if we don't read back the value ! */
-	do {
-		out_le32(hose->cfg_addr, caddr);
-	} while(in_le32(hose->cfg_addr) != caddr);
-
-	offset &= has_uninorth ? 0x07 : 0x03;
-	return (unsigned int)(hose->cfg_data) + (unsigned int)offset;
-}
-
-#define cfg_read(val, addr, type, op, op2)	\
-	*val = op((type)(addr))
-#define cfg_write(val, addr, type, op, op2)	\
-	op((type *)(addr), (val)); (void) op2((type *)(addr))
-
-#define cfg_read_bad(val, size)		*val = bad_##size;
-#define cfg_write_bad(val, size)
-
-#define bad_byte	0xff
-#define bad_word	0xffff
-#define bad_dword	0xffffffffU
-
-#define MACRISC_PCI_OP(rw, size, type, op, op2)				    \
-static int __pmac							    \
-macrisc_##rw##_config_##size(struct pci_dev *dev, int off, type val)	    \
-{									    \
-	struct pci_controller *hose = dev->sysdata;			    \
-	unsigned int addr;						    \
-									    \
-	addr = macrisc_cfg_access(hose, dev->bus->number, dev->devfn, off); \
-	if (!addr) {							    \
-		cfg_##rw##_bad(val, size)				    \
-		return PCIBIOS_DEVICE_NOT_FOUND;			    \
-	}								    \
-	cfg_##rw(val, addr, type, op, op2);				    \
-	return PCIBIOS_SUCCESSFUL;					    \
-}
-
-MACRISC_PCI_OP(read, byte, u8 *, in_8, x)
-MACRISC_PCI_OP(read, word, u16 *, in_le16, x)
-MACRISC_PCI_OP(read, dword, u32 *, in_le32, x)
-MACRISC_PCI_OP(write, byte, u8, out_8, in_8)
-MACRISC_PCI_OP(write, word, u16, out_le16, in_le16)
-MACRISC_PCI_OP(write, dword, u32, out_le32, in_le32)
-
-static struct pci_ops macrisc_pci_ops =
-{
-	macrisc_read_config_byte,
-	macrisc_read_config_word,
-	macrisc_read_config_dword,
-	macrisc_write_config_byte,
-	macrisc_write_config_word,
-	macrisc_write_config_dword
-};
-
-/*
- * Verifiy that a specific (bus, dev_fn) exists on chaos
- */
-static int __pmac
-chaos_validate_dev(struct pci_dev *dev, int offset)
-{
-	if(pci_device_to_OF_node(dev) == 0)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if((dev->vendor == 0x106b) && (dev->device == 3) && (offset >= 0x10) &&
-	    (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) {
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-#define CHAOS_PCI_OP(rw, size, type)					\
-static int __pmac							\
-chaos_##rw##_config_##size(struct pci_dev *dev, int off, type val)	\
-{									\
-	int result = chaos_validate_dev(dev, off);			\
-	if(result == PCIBIOS_BAD_REGISTER_NUMBER) {			\
-		cfg_##rw##_bad(val, size)				\
-		return PCIBIOS_BAD_REGISTER_NUMBER;			\
-	}								\
-	if(result == PCIBIOS_SUCCESSFUL)				\
-		return macrisc_##rw##_config_##size(dev, off, val);	\
-	return result;							\
-}
-
-CHAOS_PCI_OP(read, byte, u8 *)
-CHAOS_PCI_OP(read, word, u16 *)
-CHAOS_PCI_OP(read, dword, u32 *)
-CHAOS_PCI_OP(write, byte, u8)
-CHAOS_PCI_OP(write, word, u16)
-CHAOS_PCI_OP(write, dword, u32) 
-
-static struct pci_ops chaos_pci_ops =
-{
-	chaos_read_config_byte,
-	chaos_read_config_word,
-	chaos_read_config_dword,
-	chaos_write_config_byte,
-	chaos_write_config_word,
-	chaos_write_config_dword
-};
-
-
-/*
- * For a bandit bridge, turn on cache coherency if necessary.
- * N.B. we could clean this up using the hose ops directly.
- */
-static void __init
-init_bandit(struct pci_controller *bp)
-{
-	unsigned int vendev, magic;
-	int rev;
-
-	/* read the word at offset 0 in config space for device 11 */
-	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
-	udelay(2);
-	vendev = in_le32((volatile unsigned int *)bp->cfg_data);
-	if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + 
-			PCI_VENDOR_ID_APPLE) {
-		/* read the revision id */
-		out_le32(bp->cfg_addr,
-			 (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
-		udelay(2);
-		rev = in_8(bp->cfg_data);
-		if (rev != BANDIT_REVID)
-			printk(KERN_WARNING
-			       "Unknown revision %d for bandit\n", rev);
-	} else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
-		printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
-		return;
-	}
-
-	/* read the word at offset 0x50 */
-	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
-	udelay(2);
-	magic = in_le32((volatile unsigned int *)bp->cfg_data);
-	if ((magic & BANDIT_COHERENT) != 0)
-		return;
-	magic |= BANDIT_COHERENT;
-	udelay(2);
-	out_le32((volatile unsigned int *)bp->cfg_data, magic);
-	printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
-}
-
-
-/*
- * Tweak the PCI-PCI bridge chip on the blue & white G3s.
- */
-static void __init
-init_p2pbridge(void)
-{
-	struct device_node *p2pbridge;
-	struct pci_controller* hose;
-	u8 bus, devfn;
-	u16 val;
-
-	/* XXX it would be better here to identify the specific
-	   PCI-PCI bridge chip we have. */
-	if ((p2pbridge = find_devices("pci-bridge")) == 0
-	    || p2pbridge->parent == NULL
-	    || strcmp(p2pbridge->parent->name, "pci") != 0)
-		return;
-	if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
-#ifdef DEBUG
-		printk("Can't find PCI infos for PCI<->PCI bridge\n");
-#endif		
-		return;
-	}
-	/* Warning: At this point, we have not yet renumbered all busses. 
-	 * So we must use OF walking to find out hose
-	 */
-	hose = pci_find_hose_for_OF_device(p2pbridge);
-	if (!hose) {
-#ifdef DEBUG
-		printk("Can't find hose for PCI<->PCI bridge\n");
-#endif		
-		return;
-	}
-	if (early_read_config_word(hose, bus, devfn,
-				   PCI_BRIDGE_CONTROL, &val) < 0) {
-		printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
-		return;
-	}
-	val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
-	early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
-}
-
-void __init
-pmac_find_bridges(void)
-{
-	add_bridges(find_devices("bandit"));
-	add_bridges(find_devices("chaos"));
-	add_bridges(find_devices("pci"));
-	init_p2pbridge();
-}
-
-#define GRACKLE_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
-				 | (((o) & ~3) << 24))
-
-#define GRACKLE_PICR1_STG		0x00000040
-#define GRACKLE_PICR1_LOOPSNOOP		0x00000010
-
-/* N.B. this is called before bridges is initialized, so we can't
-   use grackle_pcibios_{read,write}_config_dword. */
-static inline void grackle_set_stg(struct pci_controller* bp, int enable)
-{
-	unsigned int val;
-
-	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-	val = in_le32((volatile unsigned int *)bp->cfg_data);
-	val = enable? (val | GRACKLE_PICR1_STG) :
-		(val & ~GRACKLE_PICR1_STG);
-	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-	out_le32((volatile unsigned int *)bp->cfg_data, val);
-	(void)in_le32((volatile unsigned int *)bp->cfg_data);
-}
-
-static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
-{
-	unsigned int val;
-
-	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-	val = in_le32((volatile unsigned int *)bp->cfg_data);
-	val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
-		(val & ~GRACKLE_PICR1_LOOPSNOOP);
-	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-	out_le32((volatile unsigned int *)bp->cfg_data, val);
-	(void)in_le32((volatile unsigned int *)bp->cfg_data);
-}
-
-static int __init
-setup_uninorth(struct pci_controller* hose, struct reg_property* addr)
-{
-	pci_assign_all_busses = 1;
-	has_uninorth = 1;
-	hose->ops = &macrisc_pci_ops;
-	hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-	hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
-	/* We "know" that the bridge at f2000000 has the PCI slots. */
-	return addr->address == 0xf2000000;
-}
-
-static void __init
-setup_bandit(struct pci_controller* hose, struct reg_property* addr)
-{
-	hose->ops = &macrisc_pci_ops;
-	hose->cfg_addr = (volatile unsigned int *)
-		ioremap(addr->address + 0x800000, 0x1000);
-	hose->cfg_data = (volatile unsigned char *)
-		ioremap(addr->address + 0xc00000, 0x1000);
-	init_bandit(hose);
-}
-
-static void __init
-setup_chaos(struct pci_controller* hose, struct reg_property* addr)
-{
-	/* assume a `chaos' bridge */
-	hose->ops = &chaos_pci_ops;
-	hose->cfg_addr = (volatile unsigned int *)
-		ioremap(addr->address + 0x800000, 0x1000);
-	hose->cfg_data = (volatile unsigned char *)
-		ioremap(addr->address + 0xc00000, 0x1000);
-}
-
-void __init
-setup_grackle(struct pci_controller *hose)
-{
-	setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
-	if (machine_is_compatible("AAPL,PowerBook1998"))
-		grackle_set_loop_snoop(hose, 1);
-#if 0	/* Disabled for now, HW problems ??? */
-	grackle_set_stg(hose, 1);
-#endif
-}
-
-/*
- * We assume that if we have a G3 powermac, we have one bridge called
- * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
- * if we have one or more bandit or chaos bridges, we don't have a MPC106.
- */
-static void __init
-add_bridges(struct device_node *dev)
-{
-	int len;
-	struct pci_controller *hose;
-	struct reg_property *addr;
-	char* disp_name;
-	int *bus_range;
-	int first = 1, primary;
-	
-	for (; dev != NULL; dev = dev->next) {
-		addr = (struct reg_property *) get_property(dev, "reg", &len);
-		if (addr == NULL || len < sizeof(*addr)) {
-			printk(KERN_WARNING "Can't use %s: no address\n",
-			       dev->full_name);
-			continue;
-		}
-		bus_range = (int *) get_property(dev, "bus-range", &len);
-		if (bus_range == NULL || len < 2 * sizeof(int)) {
-			printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
-				       dev->full_name);
-		}
-		
-		hose = pcibios_alloc_controller();
-		if (!hose)
-			continue;
-		hose->arch_data = dev;
-		hose->first_busno = bus_range ? bus_range[0] : 0;
-		hose->last_busno = bus_range ? bus_range[1] : 0xff;
-
-		disp_name = NULL;
-		primary = first;
-		if (device_is_compatible(dev, "uni-north")) {
-			primary = setup_uninorth(hose, addr);
-			disp_name = "UniNorth";
-		} else if (strcmp(dev->name, "pci") == 0) {
-			/* XXX assume this is a mpc106 (grackle) */
-			setup_grackle(hose);
-			disp_name = "Grackle (MPC106)";
-		} else if (strcmp(dev->name, "bandit") == 0) {
-			setup_bandit(hose, addr);
-			disp_name = "Bandit";
-		} else if (strcmp(dev->name, "chaos") == 0) {
-			setup_chaos(hose, addr);
-			disp_name = "Chaos";
-			primary = 0;
-		}
-		printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
-			disp_name, addr->address, hose->first_busno, hose->last_busno);
-#ifdef DEBUG
-		printk(" ->Hose at 0x%08lx, cfg_addr=0x%08lx,cfg_data=0x%08lx\n",
-			hose, hose->cfg_addr, hose->cfg_data);
-#endif		
-		
-		/* Interpret the "ranges" property */
-		/* This also maps the I/O region and sets isa_io/mem_base */
-		pci_process_bridge_OF_ranges(hose, dev, primary);
-
-		/* Fixup "bus-range" OF property */
-		fixup_bus_range(dev);
-
-		first &= !primary;
-	}
-}
-
-static void __init
-pcibios_fixup_OF_interrupts(void)
-{	
-	struct pci_dev* dev;
-	
-	/*
-	 * Open Firmware often doesn't initialize the
-	 * PCI_INTERRUPT_LINE config register properly, so we
-	 * should find the device node and apply the interrupt
-	 * obtained from the OF device-tree
-	 */
-	pci_for_each_dev(dev) {
-		struct device_node* node = pci_device_to_OF_node(dev);
-		/* this is the node, see if it has interrupts */
-		if (node && node->n_intrs > 0)
-			dev->irq = node->intrs[0].line;
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-	}
-}
-
-void __init
-pmac_pcibios_fixup(void)
-{
-	/* Fixup interrupts according to OF tree */
-	pcibios_fixup_OF_interrupts();
-}
-
-int __pmac
-pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
-{
-	struct device_node* node;
-	int updatecfg = 0;
-	int uninorth_child;
-	
-	node = pci_device_to_OF_node(dev);
-	
-	/* We don't want to enable USB controllers absent from the OF tree
-	 * (iBook second controller)
-	 */
-	if (dev->vendor == PCI_VENDOR_ID_APPLE
-	    && dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node)
-		return -EINVAL;
-
-	if (!node)
-		return 0;
-		
-	uninorth_child = node->parent &&
-		device_is_compatible(node->parent, "uni-north");
-		
-	/* Firewire & GMAC were disabled after PCI probe, the driver is
-	 * claiming them, we must re-enable them now.
-	 */
-	if (uninorth_child && !strcmp(node->name, "firewire") && 
-	    (device_is_compatible(node, "pci106b,18") || 
-	     device_is_compatible(node, "pci106b,30") ||
-	     device_is_compatible(node, "pci11c1,5811"))) {
-		pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
-		pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
-		updatecfg = 1;
-	}
-	if (uninorth_child && !strcmp(node->name, "ethernet") && 
-	    device_is_compatible(node, "gmac")) {
-		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
-		updatecfg = 1;
-	}
-
-	if (updatecfg) {
-		u16 cmd;
-		
-		/*
-		 * Make sure PCI is correctly configured
-		 *
-		 * We use old pci_bios versions of the function since, by
-		 * default, gmac is not powered up, and so will be absent
-		 * from the kernel initial PCI lookup. 
-		 * 
-		 * Should be replaced by 2.4 new PCI mecanisms and really
-		 * regiser the device.
-		 */
-		pci_read_config_word(dev, PCI_COMMAND, &cmd);
-		cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
-    		pci_write_config_word(dev, PCI_COMMAND, cmd);
-    		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
-    		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
-	}
-	
-	return 0;
-}
-
-/* We power down some devices after they have been probed. They'll
- * be powered back on later on
- */
-void __init
-pmac_pcibios_after_init(void)
-{
-	struct device_node* nd;
-
-#ifdef CONFIG_BLK_DEV_IDE
-	struct pci_dev *dev;
-
-	/* OF fails to initialize IDE controllers on macs
-	 * (and maybe other machines)
-	 * 
-	 * Ideally, this should be moved to the IDE layer, but we need
-	 * to check specifically with Andre Hedrick how to do it cleanly
-	 * since the common IDE code seem to care about the fact that the
-	 * BIOS may have disabled a controller.
-	 * 
-	 * -- BenH
-	 */
-	pci_for_each_dev(dev) {
-		if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE)
-			pci_enable_device(dev);
-	}
-#endif /* CONFIG_BLK_DEV_IDE */
-
-	nd = find_devices("firewire");
-	while (nd) {
-		if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
-				   device_is_compatible(nd, "pci106b,30") ||
-				   device_is_compatible(nd, "pci11c1,5811"))
-		    && device_is_compatible(nd->parent, "uni-north")) {
-			pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
-			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
-		}
-		nd = nd->next;
-	}
-	nd = find_devices("ethernet");
-	while (nd) {
-		if (nd->parent && device_is_compatible(nd, "gmac")
-		    && device_is_compatible(nd->parent, "uni-north"))
-			pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
-		nd = nd->next;
-	}
-}
-
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pmac_pic.c linux-2.4.20-pre2/arch/ppc/kernel/pmac_pic.c
--- linux-2.4.20-pre1/arch/ppc/kernel/pmac_pic.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/pmac_pic.c	Wed Dec 31 16:00:00 1969
@@ -1,528 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_pic.c 1.24 12/19/01 10:53:01 paulus
- */
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/pci.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/time.h>
-
-#include "pmac_pic.h"
-#include "open_pic.h"
-
-struct pmac_irq_hw {
-        unsigned int    event;
-        unsigned int    enable;
-        unsigned int    ack;
-        unsigned int    level;
-};
-
-/* Default addresses */
-static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = {
-        (struct pmac_irq_hw *) 0xf3000020,
-        (struct pmac_irq_hw *) 0xf3000010,
-        (struct pmac_irq_hw *) 0xf4000020,
-        (struct pmac_irq_hw *) 0xf4000010,
-};
-
-#define GC_LEVEL_MASK		0x3ff00000
-#define OHARE_LEVEL_MASK	0x1ff00000
-#define HEATHROW_LEVEL_MASK	0x1ff00000
-
-static int max_irqs __pmacdata;
-static int max_real_irqs __pmacdata;
-static u32 level_mask[4] __pmacdata;
-
-static spinlock_t pmac_pic_lock __pmacdata = SPIN_LOCK_UNLOCKED;
-
-
-#define GATWICK_IRQ_POOL_SIZE        10
-static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE] __pmacdata;
-
-/*
- * Mark an irq as "lost".  This is only used on the pmac
- * since it can lose interrupts (see pmac_set_irq_mask).
- * -- Cort
- */
-void __pmac
-__set_lost(unsigned long irq_nr, int nokick)
-{
-	if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
-		atomic_inc(&ppc_n_lost_interrupts);
-		if (!nokick)
-			set_dec(1);
-	}
-}
-
-static void __pmac
-pmac_mask_and_ack_irq(unsigned int irq_nr)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-        unsigned long flags;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
-                atomic_dec(&ppc_n_lost_interrupts);
-	spin_lock_irqsave(&pmac_pic_lock, flags);
-        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
-        out_le32(&pmac_irq_hw[i]->ack, bit);
-        do {
-                /* make sure ack gets to controller before we enable
-                   interrupts */
-                mb();
-        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-                != (ppc_cached_irq_mask[i] & bit));
-	spin_unlock_irqrestore(&pmac_pic_lock, flags);
-}
-
-static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-        unsigned long flags;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-	spin_lock_irqsave(&pmac_pic_lock, flags);
-        /* enable unmasked interrupts */
-        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
-
-        do {
-                /* make sure mask gets to controller before we
-                   return to user */
-                mb();
-        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-                != (ppc_cached_irq_mask[i] & bit));
-
-        /*
-         * Unfortunately, setting the bit in the enable register
-         * when the device interrupt is already on *doesn't* set
-         * the bit in the flag register or request another interrupt.
-         */
-        if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
-		__set_lost((ulong)irq_nr, nokicklost);
-	spin_unlock_irqrestore(&pmac_pic_lock, flags);
-}
-
-static void __pmac pmac_mask_irq(unsigned int irq_nr)
-{
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-        mb();
-}
-
-static void __pmac pmac_unmask_irq(unsigned int irq_nr)
-{
-        set_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-}
-
-static void __pmac pmac_end_irq(unsigned int irq_nr)
-{
-	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
-        	set_bit(irq_nr, ppc_cached_irq_mask);
-	        pmac_set_irq_mask(irq_nr, 1);
-	}
-}
-
-
-struct hw_interrupt_type pmac_pic = {
-        " PMAC-PIC ",
-        NULL,
-        NULL,
-        pmac_unmask_irq,
-        pmac_mask_irq,
-        pmac_mask_and_ack_irq,
-        pmac_end_irq,
-        NULL
-};
-
-struct hw_interrupt_type gatwick_pic = {
-	" GATWICK  ",
-	NULL,
-	NULL,
-	pmac_unmask_irq,
-	pmac_mask_irq,
-	pmac_mask_and_ack_irq,
-	pmac_end_irq,
-	NULL
-};
-
-static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	int irq, bits;
-	
-	for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
-		int i = irq >> 5;
-		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
-		/* We must read level interrupts from the level register */
-		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
-		bits &= ppc_cached_irq_mask[i];
-		if (bits == 0)
-			continue;
-		irq += __ilog2(bits);
-		break;
-	}
-	/* The previous version of this code allowed for this case, we
-	 * don't.  Put this here to check for it.
-	 * -- Cort
-	 */
-	if ( irq_desc[irq].handler != &gatwick_pic )
-		printk("gatwick irq not from gatwick pic\n");
-	else
-		ppc_irq_dispatch_handler( regs, irq );
-}
-
-int
-pmac_get_irq(struct pt_regs *regs)
-{
-	int irq;
-	unsigned long bits = 0;
-
-#ifdef CONFIG_SMP
-	void psurge_smp_message_recv(struct pt_regs *);
-	
-       	/* IPI's are a hack on the powersurge -- Cort */
-       	if ( smp_processor_id() != 0 ) {
-		psurge_smp_message_recv(regs);
-		return -2;	/* ignore, already handled */
-        }
-#endif /* CONFIG_SMP */
-	for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
-		int i = irq >> 5;
-		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
-		/* We must read level interrupts from the level register */
-		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
-		bits &= ppc_cached_irq_mask[i];
-		if (bits == 0)
-			continue;
-		irq += __ilog2(bits);
-		break;
-	}
-
-	return irq;
-}
-
-/* This routine will fix some missing interrupt values in the device tree
- * on the gatwick mac-io controller used by some PowerBooks
- */
-static void __init
-pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
-{
-	struct device_node *node;
-	int count;
-	
-	memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
-	node = gw->child;
-	count = 0;
-	while(node)
-	{
-		/* Fix SCC */
-		if (strcasecmp(node->name, "escc") == 0)
-			if (node->child) {
-				if (node->child->n_intrs < 3) {
-					node->child->intrs = &gatwick_int_pool[count];
-					count += 3;
-				}
-				node->child->n_intrs = 3;				
-				node->child->intrs[0].line = 15+irq_base;
-				node->child->intrs[1].line =  4+irq_base;
-				node->child->intrs[2].line =  5+irq_base;
-				printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
-					node->child->intrs[0].line,
-					node->child->intrs[1].line,
-					node->child->intrs[2].line);
-			}
-		/* Fix media-bay & left SWIM */
-		if (strcasecmp(node->name, "media-bay") == 0) {
-			struct device_node* ya_node;
-
-			if (node->n_intrs == 0)
-				node->intrs = &gatwick_int_pool[count++];
-			node->n_intrs = 1;
-			node->intrs[0].line = 29+irq_base;
-			printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
-					node->intrs[0].line);
-			
-			ya_node = node->child;
-			while(ya_node)
-			{
-				if (strcasecmp(ya_node->name, "floppy") == 0) {
-					if (ya_node->n_intrs < 2) {
-						ya_node->intrs = &gatwick_int_pool[count];
-						count += 2;
-					}
-					ya_node->n_intrs = 2;
-					ya_node->intrs[0].line = 19+irq_base;
-					ya_node->intrs[1].line =  1+irq_base;
-					printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
-						ya_node->intrs[0].line, ya_node->intrs[1].line);
-				} 
-				if (strcasecmp(ya_node->name, "ata4") == 0) {
-					if (ya_node->n_intrs < 2) {
-						ya_node->intrs = &gatwick_int_pool[count];
-						count += 2;
-					}
-					ya_node->n_intrs = 2;
-					ya_node->intrs[0].line = 14+irq_base;
-					ya_node->intrs[1].line =  3+irq_base;
-					printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
-						ya_node->intrs[0].line, ya_node->intrs[1].line);
-				} 
-				ya_node = ya_node->sibling;
-			}
-		}
-		node = node->sibling;
-	}
-	if (count > 10) {
-		printk("WARNING !! Gatwick interrupt pool overflow\n");
-		printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
-		printk("              requested = %d\n", count);
-	}
-}
-
-/*
- * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
- * card which includes an ohare chip that acts as a second interrupt
- * controller.  If we find this second ohare, set it up and fix the
- * interrupt value in the device tree for the ethernet chip.
- */
-static int __init enable_second_ohare(void)
-{
-	unsigned char bus, devfn;
-	unsigned short cmd;
-        unsigned long addr;
-	struct device_node *irqctrler = find_devices("pci106b,7");
-	struct device_node *ether;
-
-	if (irqctrler == NULL || irqctrler->n_addrs <= 0)
-		return -1;
-	addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
-	pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
-	max_irqs = 64;
-	if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
-		struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
-		if (!hose)
-		    printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
-		else {
-		    early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
-		    cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-	  	    cmd &= ~PCI_COMMAND_IO;
-		    early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
-		}
-	}
-
-	/* Fix interrupt for the modem/ethernet combo controller. The number
-	   in the device tree (27) is bogus (correct for the ethernet-only
-	   board but not the combo ethernet/modem board).
-	   The real interrupt is 28 on the second controller -> 28+32 = 60.
-	*/
-	ether = find_devices("pci1011,14");
-	if (ether && ether->n_intrs > 0) {
-		ether->intrs[0].line = 60;
-		printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
-		       ether->intrs[0].line);
-	}
-
-	/* Return the interrupt number of the cascade */
-	return irqctrler->intrs[0].line;
-}
-
-void __init
-pmac_pic_init(void)
-{
-        int i;
-        struct device_node *irqctrler;
-        unsigned long addr;
-	int irq_cascade = -1;
-	
-	/* We first try to detect Apple's new Core99 chipset, since mac-io
-	 * is quite different on those machines and contains an IBM MPIC2.
-	 */
-	irqctrler = find_type_devices("open-pic");
-	if (irqctrler != NULL)
-	{
-		printk("PowerMac using OpenPIC irq controller\n");
-		if (irqctrler->n_addrs > 0)
-		{
-			int nmi_irq = -1;
-			unsigned char senses[NR_IRQS];
-#ifdef CONFIG_XMON
-			struct device_node* pswitch;
-
-			pswitch = find_devices("programmer-switch");
-			if (pswitch && pswitch->n_intrs)
-				nmi_irq = pswitch->intrs[0].line;
-#endif /* CONFIG_XMON */
-			prom_get_irq_senses(senses, 0, NR_IRQS);
-			OpenPIC_InitSenses = senses;
-			OpenPIC_NumInitSenses = NR_IRQS;
-			ppc_md.get_irq = openpic_get_irq;
-			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
-					       irqctrler->addrs[0].size);
-			openpic_init(1, 0, 0, nmi_irq);
-#ifdef CONFIG_XMON
-			if (nmi_irq >= 0)
-				request_irq(nmi_irq, xmon_irq, 0,
-					    "NMI - XMON", 0);
-#endif	/* CONFIG_XMON */
-			return;
-		}
-		irqctrler = NULL;
-	}
-
-	/* Get the level/edge settings, assume if it's not
-	 * a Grand Central nor an OHare, then it's an Heathrow
-	 * (or Paddington).
-	 */
-	if (find_devices("gc"))
-		level_mask[0] = GC_LEVEL_MASK;
-	else if (find_devices("ohare")) {
-		level_mask[0] = OHARE_LEVEL_MASK;
-		/* We might have a second cascaded ohare */
-		level_mask[1] = OHARE_LEVEL_MASK;
-	} else {
-		level_mask[0] = HEATHROW_LEVEL_MASK;
-		level_mask[1] = 0;
-		/* We might have a second cascaded heathrow */
-		level_mask[2] = HEATHROW_LEVEL_MASK;
-		level_mask[3] = 0;
-	}
-
-	/*
-	 * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
-	 * 1998 G3 Series PowerBooks have 128, 
-	 * other powermacs have 32.
-	 * The combo ethernet/modem card for the Powerstar powerbooks
-	 * (2400/3400/3500, ohare based) has a second ohare chip
-	 * effectively making a total of 64.
-	 */
-	max_irqs = max_real_irqs = 32;
-	irqctrler = find_devices("mac-io");
-	if (irqctrler)
-	{
-		max_real_irqs = 64;
-		if (irqctrler->next)
-			max_irqs = 128;
-		else
-			max_irqs = 64;
-	}
-	for ( i = 0; i < max_real_irqs ; i++ )
-		irq_desc[i].handler = &pmac_pic;
-
-	/* get addresses of first controller */
-	if (irqctrler) {
-		if  (irqctrler->n_addrs > 0) {
-			addr = (unsigned long) 
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 0; i < 2; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (2 - i) * 0x10);
-		}
-		
-		/* get addresses of second controller */
-		irqctrler = irqctrler->next;
-		if (irqctrler && irqctrler->n_addrs > 0) {
-			addr = (unsigned long) 
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 2; i < 4; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (4 - i) * 0x10);
-			irq_cascade = irqctrler->intrs[0].line;
-			if (device_is_compatible(irqctrler, "gatwick"))
-				pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-		}
-	} else {
-		/* older powermacs have a GC (grand central) or ohare at
-		   f3000000, with interrupt control registers at f3000020. */
-		addr = (unsigned long) ioremap(0xf3000000, 0x40);
-		pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
-	}
-
-	/* PowerBooks 3400 and 3500 can have a second controller in a second
-	   ohare chip, on the combo ethernet/modem card */
-	if (machine_is_compatible("AAPL,3400/2400")
-	     || machine_is_compatible("AAPL,3500"))
-		irq_cascade = enable_second_ohare();
-
-	/* disable all interrupts in all controllers */
-	for (i = 0; i * 32 < max_irqs; ++i)
-		out_le32(&pmac_irq_hw[i]->enable, 0);
-	/* mark level interrupts */
-	for (i = 0; i < max_irqs; i++)
-		if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
-			irq_desc[i].status = IRQ_LEVEL;
-	
-	/* get interrupt line of secondary interrupt controller */
-	if (irq_cascade >= 0) {
-		printk(KERN_INFO "irq: secondary controller on irq %d\n",
-			(int)irq_cascade);
-		for ( i = max_real_irqs ; i < max_irqs ; i++ )
-			irq_desc[i].handler = &gatwick_pic;
-		request_irq( irq_cascade, gatwick_action, SA_INTERRUPT,
-			     "cascade", 0 );
-	}
-	printk("System has %d possible interrupts\n", max_irqs);
-	if (max_irqs != max_real_irqs)
-		printk(KERN_DEBUG "%d interrupts on main controller\n",
-			max_real_irqs);
-
-#ifdef CONFIG_XMON
-	request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
-#endif	/* CONFIG_XMON */
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * These procedures are used in implementing sleep on the powerbooks.
- * sleep_save_intrs() saves the states of all interrupt enables
- * and disables all interrupts except for the nominated one.
- * sleep_restore_intrs() restores the states of all interrupt enables.
- */
-unsigned int sleep_save_mask[2];
-
-void __pmac
-pmac_sleep_save_intrs(int viaint)
-{
-	sleep_save_mask[0] = ppc_cached_irq_mask[0];
-	sleep_save_mask[1] = ppc_cached_irq_mask[1];
-	ppc_cached_irq_mask[0] = 0;
-	ppc_cached_irq_mask[1] = 0;
-	if (viaint > 0)
-		set_bit(viaint, ppc_cached_irq_mask);
-	out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
-	if (max_real_irqs > 32)
-		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
-	(void)in_le32(&pmac_irq_hw[0]->event);
-	/* make sure mask gets to controller before we return to caller */
-	mb();
-        (void)in_le32(&pmac_irq_hw[0]->enable);
-}
-
-void __pmac
-pmac_sleep_restore_intrs(void)
-{
-	int i;
-
-	out_le32(&pmac_irq_hw[0]->enable, 0);
-	if (max_real_irqs > 32)
-		out_le32(&pmac_irq_hw[1]->enable, 0);
-	mb();
-	for (i = 0; i < max_real_irqs; ++i)
-		if (test_bit(i, sleep_save_mask))
-			pmac_unmask_irq(i);
-}
-#endif /* CONFIG_PMAC_PBOOK */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pmac_pic.h linux-2.4.20-pre2/arch/ppc/kernel/pmac_pic.h
--- linux-2.4.20-pre1/arch/ppc/kernel/pmac_pic.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/pmac_pic.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_pic.h 1.9 08/19/01 22:23:04 paulus
- */
-#ifndef _PPC_KERNEL_PMAC_PIC_H
-#define _PPC_KERNEL_PMAC_PIC_H
-
-#include "local_irq.h"
-
-extern struct hw_interrupt_type pmac_pic;
-
-void pmac_pic_init(void);
-int pmac_get_irq(struct pt_regs *regs);
-
-#endif /* _PPC_KERNEL_PMAC_PIC_H */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pmac_setup.c linux-2.4.20-pre2/arch/ppc/kernel/pmac_setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/pmac_setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/pmac_setup.c	Wed Dec 31 16:00:00 1969
@@ -1,957 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_setup.c 1.54 04/16/02 20:08:22 paulus
- */
-/*
- *  linux/arch/ppc/kernel/setup.c
- *
- *  PowerPC version 
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Adapted for Power Macintosh by Paul Mackerras
- *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *
- *  Derived from "arch/alpha/kernel/setup.c"
- *    Copyright (C) 1995 Linus Torvalds
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the 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/init.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/string.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/blk.h>
-#include <linux/vt_kern.h>
-#include <linux/console.h>
-#include <linux/ide.h>
-#include <linux/pci.h>
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <linux/seq_file.h>
-#include <linux/blkdev.h>
-#include <linux/genhd.h>
-
-#include <asm/processor.h>
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/pci-bridge.h>
-#include <asm/ohare.h>
-#include <asm/mediabay.h>
-#include <asm/machdep.h>
-#include <asm/keyboard.h>
-#include <asm/dma.h>
-#include <asm/bootx.h>
-#include <asm/cputable.h>
-#include <asm/btext.h>
-#include <asm/pmac_feature.h>
-#include <asm/time.h>
-
-#include "local_irq.h"
-#include "pmac_pic.h"
-#include "mem_pieces.h"
-#include "scsi.h" /* sd_find_target */
-#include "sd.h"
-
-extern long pmac_time_init(void);
-extern unsigned long pmac_get_rtc_time(void);
-extern int pmac_set_rtc_time(unsigned long nowtime);
-extern void pmac_read_rtc_time(void);
-extern void pmac_calibrate_decr(void);
-extern void pmac_pcibios_fixup(void);
-extern void pmac_find_bridges(void);
-extern int pmac_ide_check_base(ide_ioreg_t base);
-extern ide_ioreg_t pmac_ide_get_base(int index);
-extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
-	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
-
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
-		     char raw_mode);
-extern char mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void __init mackbd_init_hw(void);
-extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
-				 char raw_mode);
-extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
-extern void mac_hid_init_hw(void);
-extern unsigned char mac_hid_kbd_sysrq_xlate[];
-extern unsigned char pckbd_sysrq_xlate[];
-extern unsigned char mackbd_sysrq_xlate[];
-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 int keyboard_sends_linux_keycodes;
-extern void pmac_nvram_update(void);
-
-extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial);
-extern void pmac_pcibios_after_init(void);
-
-struct device_node *memory_node;
-
-unsigned char drive_info;
-
-int ppc_override_l2cr = 0;
-int ppc_override_l2cr_value;
-int has_l2cache = 0;
-
-static int current_root_goodness = -1;
-
-extern char saved_command_line[];
-
-extern int pmac_newworld;
-
-#define DEFAULT_ROOT_DEVICE 0x0801	/* sda1 - slightly silly choice */
-
-extern void zs_kgdb_hook(int tty_num);
-static void ohare_init(void);
-#ifdef CONFIG_BOOTX_TEXT
-void pmac_progress(char *s, unsigned short hex);
-#endif
-
-sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
-
-#ifdef CONFIG_SMP
-extern struct smp_ops_t psurge_smp_ops;
-extern struct smp_ops_t core99_smp_ops;
-#endif /* CONFIG_SMP */
-
-/*
- * Assume here that all clock rates are the same in a
- * smp system.  -- Cort
- */
-int __openfirmware
-of_show_percpuinfo(struct seq_file *m, int i)
-{
-	struct device_node *cpu_node;
-	int *fp, s;
-			
-	cpu_node = find_type_devices("cpu");
-	if (!cpu_node)
-		return 0;
-	for (s = 0; s < i && cpu_node->next; s++)
-		cpu_node = cpu_node->next;
-	fp = (int *) get_property(cpu_node, "clock-frequency", NULL);
-	if (fp)
-		seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
-	return 0;
-}
-
-int __pmac
-pmac_show_cpuinfo(struct seq_file *m)
-{
-	struct device_node *np;
-	char *pp;
-	int plen;
-	int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
-		NULL, PMAC_MB_INFO_MODEL, 0);
-	unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
-		NULL, PMAC_MB_INFO_FLAGS, 0);
-	char* mbname;
-
-	if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
-		mbname = "Unknown";
-		
-	/* find motherboard type */
-	seq_printf(m, "machine\t\t: ");
-	np = find_devices("device-tree");
-	if (np != NULL) {
-		pp = (char *) get_property(np, "model", NULL);
-		if (pp != NULL)
-			seq_printf(m, "%s\n", pp);
-		else
-			seq_printf(m, "PowerMac\n");
-		pp = (char *) get_property(np, "compatible", &plen);
-		if (pp != NULL) {
-			seq_printf(m, "motherboard\t:");
-			while (plen > 0) {
-				int l = strlen(pp) + 1;
-				seq_printf(m, " %s", pp);
-				plen -= l;
-				pp += l;
-			}
-			seq_printf(m, "\n");
-		}
-	} else
-		seq_printf(m, "PowerMac\n");
-
-	/* print parsed model */
-	seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
-	seq_printf(m, "pmac flags\t: %08x\n", mbflags);
-	
-	/* find l2 cache info */
-	np = find_devices("l2-cache");
-	if (np == 0)
-		np = find_type_devices("cache");
-	if (np != 0) {
-		unsigned int *ic = (unsigned int *)
-			get_property(np, "i-cache-size", NULL);
-		unsigned int *dc = (unsigned int *)
-			get_property(np, "d-cache-size", NULL);
-		seq_printf(m, "L2 cache\t:");
-		has_l2cache = 1;
-		if (get_property(np, "cache-unified", NULL) != 0 && dc) {
-			seq_printf(m, " %dK unified", *dc / 1024);
-		} else {
-			if (ic)
-				seq_printf(m, " %dK instruction", *ic / 1024);
-			if (dc)
-				seq_printf(m, "%s %dK data",
-					   (ic? " +": ""), *dc / 1024);
-		}
-		pp = get_property(np, "ram-type", NULL);
-		if (pp)
-			seq_printf(m, " %s", pp);
-		seq_printf(m, "\n");
-	}
-
-	/* find ram info */
-	np = find_devices("memory");
-	if (np != 0) {
-		int n;
-		struct reg_property *reg = (struct reg_property *)
-			get_property(np, "reg", &n);
-		
-		if (reg != 0) {
-			unsigned long total = 0;
-
-			for (n /= sizeof(struct reg_property); n > 0; --n)
-				total += (reg++)->size;
-			seq_printf(m, "memory\t\t: %luMB\n", total >> 20);
-		}
-	}
-
-	/* Checks "l2cr-value" property in the registry */
-	np = find_devices("cpus");		
-	if (np == 0)
-		np = find_type_devices("cpu");		
-	if (np != 0) {
-		unsigned int *l2cr = (unsigned int *)
-			get_property(np, "l2cr-value", NULL);
-		if (l2cr != 0) {
-			seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr);
-		}
-	}
-	
-	/* Indicate newworld/oldworld */
-	seq_printf(m, "pmac-generation\t: %s\n",
-		   pmac_newworld ? "NewWorld" : "OldWorld");
-	
-
-	return 0;
-}
-
-#ifdef CONFIG_VT
-/*
- * Dummy mksound function that does nothing.
- * The real one is in the dmasound driver.
- */
-static void __pmac
-pmac_mksound(unsigned int hz, unsigned int ticks)
-{
-}
-#endif /* CONFIG_VT */
-
-static volatile u32 *sysctrl_regs;
-
-void __init
-pmac_setup_arch(void)
-{
-	struct device_node *cpu;
-	int *fp;
-	unsigned long pvr;
-	
-	pvr = PVR_VER(mfspr(PVR));
-
-	/* Set loops_per_jiffy to a half-way reasonable value,
-	   for use until calibrate_delay gets called. */
-	cpu = find_type_devices("cpu");
-	if (cpu != 0) {
-		fp = (int *) get_property(cpu, "clock-frequency", NULL);
-		if (fp != 0) {
-			if (pvr == 4 || pvr >= 8)
-				/* 604, G3, G4 etc. */
-				loops_per_jiffy = *fp / HZ;
-			else
-				/* 601, 603, etc. */
-				loops_per_jiffy = *fp / (2*HZ);
-		} else
-			loops_per_jiffy = 50000000 / HZ;
-	}
-
-	/* this area has the CPU identification register
-	   and some registers used by smp boards */
-	sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
-	ohare_init();
-
-	/* Lookup PCI hosts */
-	pmac_find_bridges();
-	
-	/* Checks "l2cr-value" property in the registry */
-	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) {
-		struct device_node *np = find_devices("cpus");		
-		if (np == 0)
-			np = find_type_devices("cpu");		
-		if (np != 0) {
-			unsigned int *l2cr = (unsigned int *)
-				get_property(np, "l2cr-value", NULL);
-			if (l2cr != 0) {
-				ppc_override_l2cr = 1;
-				ppc_override_l2cr_value = *l2cr;
-				_set_L2CR(0);
-				_set_L2CR(ppc_override_l2cr_value);
-			}
-		}
-	}
-
-	if (ppc_override_l2cr)
-		printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
-			ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
-				? "enabled" : "disabled");
-	
-#ifdef CONFIG_KGDB
-	zs_kgdb_hook(0);
-#endif
-
-#ifdef CONFIG_ADB_CUDA
-	find_via_cuda();
-#else
-	if (find_devices("via-cuda")) {
-		printk("WARNING ! Your machine is Cuda based but your kernel\n");
-		printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
-	}
-#endif	
-#ifdef CONFIG_ADB_PMU
-	find_via_pmu();
-#else
-	if (find_devices("via-pmu")) {
-		printk("WARNING ! Your machine is PMU based but your kernel\n");
-		printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
-	}
-#endif	
-#ifdef CONFIG_NVRAM
-	pmac_nvram_init();
-#endif
-#ifdef CONFIG_DUMMY_CONSOLE
-	conswitchp = &dummy_con;
-#endif
-#ifdef CONFIG_VT
-	kd_mksound = pmac_mksound;
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start)
-		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
-	else
-#endif
-		ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
-
-#ifdef CONFIG_SMP
-	/* Check for Core99 */
-	if (find_devices("uni-n"))
-		ppc_md.smp_ops = &core99_smp_ops;
-	else
-		ppc_md.smp_ops = &psurge_smp_ops;
-#endif /* CONFIG_SMP */
-}
-
-static void __init ohare_init(void)
-{
-	/*
-	 * Turn on the L2 cache.
-	 * We assume that we have a PSX memory controller iff
-	 * we have an ohare I/O controller.
-	 */
-	if (find_devices("ohare") != NULL) {
-		if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
-			if (sysctrl_regs[4] & 0x10)
-				sysctrl_regs[4] |= 0x04000020;
-			else
-				sysctrl_regs[4] |= 0x04000000;
-			if(has_l2cache)
-				printk(KERN_INFO "Level 2 cache enabled\n");
-		}
-	}
-}
-
-extern char *bootpath;
-extern char *bootdevice;
-void *boot_host;
-int boot_target;
-int boot_part;
-extern kdev_t boot_dev;
-
-void __init
-pmac_init2(void)
-{
-#ifdef CONFIG_ADB_PMU
-	via_pmu_start();
-#endif
-#ifdef CONFIG_ADB_CUDA
-	via_cuda_start();
-#endif
-#ifdef CONFIG_PMAC_PBOOK
-	media_bay_init();
-#endif
-	pmac_feature_late_init();
-}
-
-/* That include would have to be in include/linux/ ideally */
-#include "../../../fs/partitions/mac.h"
-
-/* Borrowed from fs/partition/check.c */
-static unsigned char* __init
-read_one_block(struct block_device *bdev, unsigned long n, struct page **v)
-{
-	struct address_space *mapping = bdev->bd_inode->i_mapping;
-	int sect = PAGE_CACHE_SIZE / 512;
-	struct page *page;
-
-	page = read_cache_page(mapping, n/sect,
-			(filler_t *)mapping->a_ops->readpage, NULL);
-	if (!IS_ERR(page)) {
-		wait_on_page(page);
-		if (!Page_Uptodate(page))
-			goto fail;
-		if (PageError(page))
-			goto fail;
-		*v = page;
-		return (unsigned char *)page_address(page) + 512 * (n % sect);
-fail:
-		page_cache_release(page);
-	}
-	*v = NULL;
-	return NULL;
-}
-
-#ifdef CONFIG_SCSI
-void __init
-note_scsi_host(struct device_node *node, void *host)
-{
-	int l;
-	char *p;
-
-	l = strlen(node->full_name);
-	if (bootpath != NULL && bootdevice != NULL
-	    && strncmp(node->full_name, bootdevice, l) == 0
-	    && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
-		boot_host = host;
-		/*
-		 * There's a bug in OF 1.0.5.  (Why am I not surprised.)
-		 * If you pass a path like scsi/sd@1:0 to canon, it returns
-		 * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
-		 * That is, the scsi target number doesn't get preserved.
-		 * So we pick the target number out of bootpath and use that.
-		 */
-		p = strstr(bootpath, "/sd@");
-		if (p != NULL) {
-			p += 4;
-			boot_target = simple_strtoul(p, NULL, 10);
-			p = strchr(p, ':');
-			if (p != NULL)
-				boot_part = simple_strtoul(p + 1, NULL, 10);
-		}
-	}
-}
-#endif /* CONFIG_SCSI */
-
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-kdev_t __init
-find_ide_boot(void)
-{
-	char *p;
-	int n;
-	kdev_t __init pmac_find_ide_boot(char *bootdevice, int n);
-
-	if (bootdevice == NULL)
-		return 0;
-	p = strrchr(bootdevice, '/');
-	if (p == NULL)
-		return 0;
-	n = p - bootdevice;
-
-	return pmac_find_ide_boot(bootdevice, n);
-}
-#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
-
-void __init
-find_boot_device(void)
-{
-#if defined(CONFIG_SCSI) && defined(CONFIG_BLK_DEV_SD)
-	if (boot_host != NULL) {
-		boot_dev = sd_find_target(boot_host, boot_target);
-		if (boot_dev != 0)
-			return;
-	}
-#endif
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-	boot_dev = find_ide_boot();
-#endif
-}
-
-static void __init
-check_bootable_part(kdev_t dev, int blk, struct mac_partition *part)
-{
-	int goodness = 0;
-
-	macpart_fix_string(part->processor, 16);
-	macpart_fix_string(part->name, 32);
-	macpart_fix_string(part->type, 32);					
-    
-	if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
-	    && strcasecmp(part->processor, "powerpc") == 0)
-		goodness++;
-
-	if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
-	    || (strnicmp(part->type, "Linux", 5) == 0
-	    && strcasecmp(part->type, "Linux_swap") != 0)) {
-		int i, l;
-
-		goodness++;
-		l = strlen(part->name);
-		if (strcmp(part->name, "/") == 0)
-			goodness++;
-		for (i = 0; i <= l - 4; ++i) {
-			if (strnicmp(part->name + i, "root",
-				     4) == 0) {
-				goodness += 2;
-				break;
-			}
-		}
-		if (strnicmp(part->name, "swap", 4) == 0)
-			goodness--;
-	}
-
-	if (goodness > current_root_goodness) {
-		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + blk);
-		current_root_goodness = goodness;
-	}
-}
-
-static void __init
-check_bootable_disk(kdev_t dev, struct block_device *bdev)
-{
-	struct mac_partition *part;
-	struct mac_driver_desc *md;
-	struct page* pg;
-	unsigned secsize, blocks_in_map, blk;
-	unsigned char* data;
-	
-	/* Check driver descriptor */
-	md = (struct mac_driver_desc *) read_one_block(bdev, 0, &pg);
-	if (!md)
-		return;
-	if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
-		goto fail;
-	secsize = be16_to_cpu(md->block_size);
-	page_cache_release(pg);
-	
-	/* Check if it looks like a mac partition map */
-	data = read_one_block(bdev, secsize/512, &pg);
-	if (!data)
-		goto fail;
-	part = (struct mac_partition *) (data + secsize%512);
-	if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
-		goto fail;
-
-	/* Iterate the partition map */
-	blocks_in_map = be32_to_cpu(part->map_count);
-	for (blk = 1; blk <= blocks_in_map; ++blk) {
-		int pos = blk * secsize;
-		page_cache_release(pg);
-		data = read_one_block(bdev, pos/512, &pg);
-		if (!data)
-			break;
-		part = (struct mac_partition *) (data + pos%512);
-		if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
-			break;
-		check_bootable_part(dev, blk, part);
-	}
-fail:
-	if (pg)	
-		page_cache_release(pg);
-}
-
-static int __init
-walk_bootable(struct gendisk *hd, void *data)
-{
-	int drive;
-	
-	for (drive=0; drive<hd->nr_real; drive++) {
-		kdev_t dev;
-		struct block_device *bdev;
-		int rc;
-
-		dev = MKDEV(hd->major, drive << hd->minor_shift);
-		if (boot_dev && boot_dev != dev)
-			continue;
-		bdev = bdget(kdev_t_to_nr(dev));
-		if (bdev == NULL)
-			continue;
-		rc = blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW);
-		if (rc == 0) {
-			check_bootable_disk(dev, bdev);
-			blkdev_put(bdev, BDEV_RAW);
-		}
-	}
-
-	return 0;
-}
-
-void __init
-pmac_discover_root(void)
-{
-	char* p;
-
-	/* Check if root devices already got selected by other ways */
-	if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))
-		return;
-	p = strstr(saved_command_line, "root=");
-	if (p != NULL && (p == saved_command_line || p[-1] == ' '))
-		return;
-
-	/* Find the device used for booting if we can */
-	find_boot_device();
-
-	/* Try to locate a partition */
-	walk_gendisk(walk_bootable, NULL);
-}
-
-void __pmac
-pmac_restart(char *cmd)
-{
-#ifdef CONFIG_ADB_CUDA
-	struct adb_request req;
-#endif /* CONFIG_ADB_CUDA */
-
-#ifdef CONFIG_NVRAM
-	pmac_nvram_update();
-#endif
-	
-	switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-	case SYS_CTRLER_CUDA:
-		cuda_request(&req, NULL, 2, CUDA_PACKET,
-			     CUDA_RESET_SYSTEM);
-		for (;;)
-			cuda_poll();
-		break;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU		
-	case SYS_CTRLER_PMU:
-		pmu_restart();
-		break;
-#endif /* CONFIG_ADB_PMU */		
-	default: ;
-	}
-}
-
-void __pmac
-pmac_power_off(void)
-{
-#ifdef CONFIG_ADB_CUDA
-	struct adb_request req;
-#endif /* CONFIG_ADB_CUDA */
-
-#ifdef CONFIG_NVRAM
-	pmac_nvram_update();
-#endif
-	
-	switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-	case SYS_CTRLER_CUDA:
-		cuda_request(&req, NULL, 2, CUDA_PACKET,
-			     CUDA_POWERDOWN);
-		for (;;)
-			cuda_poll();
-		break;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-	case SYS_CTRLER_PMU:
-		pmu_shutdown();
-		break;
-#endif /* CONFIG_ADB_PMU */
-	default: ;
-	}
-}
-
-void __pmac
-pmac_halt(void)
-{
-   pmac_power_off();
-}
-
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-static int __pmac
-pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return 0;
-#endif
-	return check_region(from, extent);
-}
-
-static void __pmac
-pmac_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	request_region(from, extent, name);
-}
-
-static void __pmac
-pmac_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	release_region(from, extent);
-}
-
-#ifndef CONFIG_BLK_DEV_IDE_PMAC
-/*
- * This is only used if we have a PCI IDE controller, not
- * for the IDE controller in the ohare/paddington/heathrow/keylargo.
- */
-static void __pmac
-pmac_ide_pci_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;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-}
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
-/*
- * Read in a property describing some pieces of memory.
- */
-
-static int __init
-get_mem_prop(char *name, struct mem_pieces *mp)
-{
-	struct reg_property *rp;
-	int i, s;
-	unsigned int *ip;
-	int nac = prom_n_addr_cells(memory_node);
-	int nsc = prom_n_size_cells(memory_node);
-
-	ip = (unsigned int *) get_property(memory_node, name, &s);
-	if (ip == NULL) {
-		printk(KERN_ERR "error: couldn't get %s property on /memory\n",
-		       name);
-		return 0;
-	}
-	s /= (nsc + nac) * 4;
-	rp = mp->regions;
-	for (i = 0; i < s; ++i, ip += nac+nsc) {
-		if (nac >= 2 && ip[nac-2] != 0)
-			continue;
-		rp->address = ip[nac-1];
-		if (nsc >= 2 && ip[nac+nsc-2] != 0)
-			rp->size = ~0U;
-		else
-			rp->size = ip[nac+nsc-1];
-		++rp;
-	}
-	mp->n_regions = rp - mp->regions;
-
-	/* Make sure the pieces are sorted. */
-	mem_pieces_sort(mp);
-	mem_pieces_coalesce(mp);
-	return 1;
-}
-
-/*
- * On systems with Open Firmware, collect information about
- * physical RAM and which pieces are already in use.
- * At this point, we have (at least) the first 8MB mapped with a BAT.
- * Our text, data, bss use something over 1MB, starting at 0.
- * Open Firmware may be using 1MB at the 4MB point.
- */
-unsigned long __init
-pmac_find_end_of_memory(void)
-{
-	unsigned long a, total;
-	struct mem_pieces phys_mem;
-
-	/*
-	 * Find out where physical memory is, and check that it
-	 * starts at 0 and is contiguous.  It seems that RAM is
-	 * always physically contiguous on Power Macintoshes.
-	 *
-	 * Supporting discontiguous physical memory isn't hard,
-	 * it just makes the virtual <-> physical mapping functions
-	 * more complicated (or else you end up wasting space
-	 * in mem_map).
-	 */
-	memory_node = find_devices("memory");
-	if (memory_node == NULL || !get_mem_prop("reg", &phys_mem)
-	    || phys_mem.n_regions == 0)
-		panic("No RAM??");
-	a = phys_mem.regions[0].address;
-	if (a != 0)
-		panic("RAM doesn't start at physical address 0");
-	total = phys_mem.regions[0].size;
-
-	if (phys_mem.n_regions > 1) {
-		printk("RAM starting at 0x%x is not contiguous\n",
-		       phys_mem.regions[1].address);
-		printk("Using RAM from 0 to 0x%lx\n", total-1);
-	}
-
-	return total;
-}
-
-void __init
-select_adb_keyboard(void)
-{
-#ifdef CONFIG_VT
-#ifdef CONFIG_INPUT
-	ppc_md.kbd_init_hw       = mac_hid_init_hw;
-	ppc_md.kbd_translate     = mac_hid_kbd_translate;
-	ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
-	ppc_md.kbd_setkeycode    = 0;
-	ppc_md.kbd_getkeycode    = 0;
-	ppc_md.kbd_leds		 = 0;
-#ifdef CONFIG_MAGIC_SYSRQ
-#ifdef CONFIG_MAC_ADBKEYCODES
-	if (!keyboard_sends_linux_keycodes) {
-		ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
-		SYSRQ_KEY = 0x69;
-	} else
-#endif /* CONFIG_MAC_ADBKEYCODES */
-	{
-		ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
-		SYSRQ_KEY = 0x54;
-	}
-#endif /* CONFIG_MAGIC_SYSRQ */
-#elif defined(CONFIG_ADB_KEYBOARD)
-	ppc_md.kbd_setkeycode       = mackbd_setkeycode;
-	ppc_md.kbd_getkeycode       = mackbd_getkeycode;
-	ppc_md.kbd_translate        = mackbd_translate;
-	ppc_md.kbd_unexpected_up    = mackbd_unexpected_up;
-	ppc_md.kbd_leds             = mackbd_leds;
-	ppc_md.kbd_init_hw          = mackbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate  = mackbd_sysrq_xlate;
-	SYSRQ_KEY = 0x69;
-#endif /* CONFIG_MAGIC_SYSRQ */
-#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */
-#endif /* CONFIG_VT */
-}
-
-void __init
-pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	  unsigned long r6, unsigned long r7)
-{
-	/* isa_io_base gets set in pmac_find_bridges */
-	isa_mem_base = PMAC_ISA_MEM_BASE;
-	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-	ISA_DMA_THRESHOLD = ~0L;
-	DMA_MODE_READ = 1;
-	DMA_MODE_WRITE = 2;
-
-	ppc_md.setup_arch     = pmac_setup_arch;
-	ppc_md.show_cpuinfo   = pmac_show_cpuinfo;
-	ppc_md.show_percpuinfo = of_show_percpuinfo;
-	ppc_md.irq_cannonicalize = NULL;
-	ppc_md.init_IRQ       = pmac_pic_init;
-	ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
-	ppc_md.init           = pmac_init2;
-	
-	ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
-	ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
-	ppc_md.pcibios_after_init = pmac_pcibios_after_init;
-
-	ppc_md.discover_root  = pmac_discover_root;
-
-	ppc_md.restart        = pmac_restart;
-	ppc_md.power_off      = pmac_power_off;
-	ppc_md.halt           = pmac_halt;
-
-	ppc_md.time_init      = pmac_time_init;
-	ppc_md.set_rtc_time   = pmac_set_rtc_time;
-	ppc_md.get_rtc_time   = pmac_get_rtc_time;
-	ppc_md.calibrate_decr = pmac_calibrate_decr;
-
-	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
-
-	ppc_md.feature_call   = pmac_do_feature_call;
-
-	select_adb_keyboard();
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region	= pmac_ide_check_region;
-        ppc_ide_md.ide_request_region	= pmac_ide_request_region;
-        ppc_ide_md.ide_release_region	= pmac_ide_release_region;
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-        ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
-        ppc_ide_md.default_io_base	= pmac_ide_get_base;
-#else /* CONFIG_BLK_DEV_IDE_PMAC */
-        ppc_ide_md.ide_init_hwif	= pmac_ide_pci_init_hwif_ports;
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
-#ifdef CONFIG_BOOTX_TEXT
-	ppc_md.progress = pmac_progress;
-#endif /* CONFIG_BOOTX_TEXT */
-
-	if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
-	
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-void __init
-pmac_progress(char *s, unsigned short hex)
-{
-	if (boot_text_mapped) {
-		btext_drawstring(s);
-		btext_drawchar('\n');
-	}
-}
-#endif /* CONFIG_BOOTX_TEXT */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pmac_smp.c linux-2.4.20-pre2/arch/ppc/kernel/pmac_smp.c
--- linux-2.4.20-pre1/arch/ppc/kernel/pmac_smp.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/pmac_smp.c	Wed Dec 31 16:00:00 1969
@@ -1,622 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * SMP support for power macintosh.
- *
- * We support both the old "powersurge" SMP architecture
- * and the current Core99 (G4 PowerMac) machines.
- *
- * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
- * and Ben Herrenschmidt <benh@kernel.crashing.org>.
- *
- * Support for DayStar quad CPU cards
- * Copyright (C) XLR8, Inc. 1994-2000
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the 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/spinlock.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/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/residual.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/time.h>
-#include <asm/gemini.h>
-#include <asm/processor.h>
-
-#include "open_pic.h"
-
-/*
- * Powersurge (old powermac SMP) support.
- */
-
-extern void __secondary_start_psurge(void);
-extern void __secondary_start_psurge2(void);	/* Temporary horrible hack */
-extern void __secondary_start_psurge3(void);	/* Temporary horrible hack */
-
-/* Addresses for powersurge registers */
-#define HAMMERHEAD_BASE		0xf8000000
-#define HHEAD_CONFIG		0x90
-#define HHEAD_SEC_INTR		0xc0
-
-/* register for interrupting the primary processor on the powersurge */
-/* N.B. this is actually the ethernet ROM! */
-#define PSURGE_PRI_INTR		0xf3019000
-
-/* register for storing the start address for the secondary processor */
-/* N.B. this is the PCI config space address register for the 1st bridge */
-#define PSURGE_START		0xf2800000
-
-/* Daystar/XLR8 4-CPU card */
-#define PSURGE_QUAD_REG_ADDR	0xf8800000
-
-#define PSURGE_QUAD_IRQ_SET	0
-#define PSURGE_QUAD_IRQ_CLR	1
-#define PSURGE_QUAD_IRQ_PRIMARY	2
-#define PSURGE_QUAD_CKSTOP_CTL	3
-#define PSURGE_QUAD_PRIMARY_ARB	4
-#define PSURGE_QUAD_BOARD_ID	6
-#define PSURGE_QUAD_WHICH_CPU	7
-#define PSURGE_QUAD_CKSTOP_RDBK	8
-#define PSURGE_QUAD_RESET_CTL	11
-
-#define PSURGE_QUAD_OUT(r, v)	(out_8(quad_base + ((r) << 4) + 4, (v)))
-#define PSURGE_QUAD_IN(r)	(in_8(quad_base + ((r) << 4) + 4) & 0x0f)
-#define PSURGE_QUAD_BIS(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
-#define PSURGE_QUAD_BIC(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
-
-/* virtual addresses for the above */
-static volatile u8 *hhead_base;
-static volatile u8 *quad_base;
-static volatile u32 *psurge_pri_intr;
-static volatile u8 *psurge_sec_intr;
-static volatile u32 *psurge_start;
-
-/* what sort of powersurge board we have */
-static int psurge_type;
-
-/* values for psurge_type */
-#define PSURGE_DUAL		0
-#define PSURGE_QUAD_OKEE	1
-#define PSURGE_QUAD_COTTON	2
-#define PSURGE_QUAD_ICEGRASS	3
-
-volatile static long int core99_l2_cache;
-volatile static long int core99_l3_cache;
-
-static void __init
-core99_init_caches(void)
-{
-	int cpu = smp_processor_id();
-
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
-		return;
-
-	if (cpu == 0){
-		core99_l2_cache = _get_L2CR();
-		printk("CPU0: L2CR is %lx\n", core99_l2_cache);
-	} else {
-		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
-		_set_L2CR(0);
-		_set_L2CR(core99_l2_cache);
-		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
-	}
-
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
-		return;
-
-	if (cpu == 0){
-		core99_l3_cache = _get_L3CR();
-		printk("CPU0: L3CR is %lx\n", core99_l3_cache);
-	} else {
-		printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
-		_set_L3CR(0);
-		_set_L3CR(core99_l3_cache);
-		printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
-	}
-}
-
-/* Some CPU registers have to be saved from the first CPU and
- * applied to others. Note that we override what is setup by
- * the cputable intentionally.
- */
-
-#define	reg_hid0	0
-#define	reg_hid1	1
-#define	reg_msscr0	2
-#define	reg_msssr0	3
-#define	reg_ictrl	4
-#define	reg_ldstcr	5
-#define	reg_ldstdb	6
-#define	reg_count	7
-
-static unsigned long cpu_regs[reg_count];
-
-static void __pmac
-cpu_setup_grab(void)
-{
-	unsigned int pvers = mfspr(SPRN_PVR)>>16;
-
-	/* Read cache setting of CPU 0 */
-	core99_init_caches();
-
-	/* 7400/7410/7450 */
-	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
-		cpu_regs[reg_hid0] = mfspr(SPRN_HID0);
-		cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0);
-		cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0);
-	}
-	/* 7450 only */
-	if (pvers == 0x8000) {
-		cpu_regs[reg_hid1] = mfspr(SPRN_HID1);
-		cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL);
-		cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR);
-		cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB);
-	}
-	flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]);
-}
-
-static void __pmac
-cpu_setup_apply(int cpu_nr)
-{
-	unsigned int pvers = mfspr(SPRN_PVR)>>16;
-
-	/* Apply cache setting from CPU 0 */
-	core99_init_caches();
-
-	/* 7400/7410/7450 */
-	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"lwz	%0,4*"stringify(reg_hid0)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_HID0)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_msscr0)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_MSSCR0)", %0\n"
-			"isync;sync\n"
-//			"lwz	%0, "stringify(reg_msssr0)"(%1)\n"
-//			"sync\n"
-//			"mtspr	"stringify(SPRN_MSSSR0)", %0\n"
-//			"isync;sync\n"
-		: "=&r" (tmp) : "r" (cpu_regs));			
-	}
-	/* 7410 only */
-	if (pvers == 0x800c) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"li	%0, 0\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_L2CR2)", %0\n"
-			"isync;sync\n"
-		: "=&r" (tmp));		
-	}
-	/* 7450 only */
-	if (pvers == 0x8000) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"lwz	%0, 4*"stringify(reg_hid1)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_HID1)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ictrl)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_ICTRL)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ldstcr)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_LDSTCR)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ldstdb)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_LDSTDB)", %0\n"
-			"isync;sync\n"
-		: "=&r" (tmp) : "r" (cpu_regs));		
-	}
-}
-
-/*
- * Set and clear IPIs for powersurge.
- */
-static inline void psurge_set_ipi(int cpu)
-{
-	if (cpu == 0)
-		in_be32(psurge_pri_intr);
-	else if (psurge_type == PSURGE_DUAL)
-		out_8(psurge_sec_intr, 0);
-	else
-		PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
-}
-
-static inline void psurge_clr_ipi(int cpu)
-{
-	if (cpu > 0) {
-		if (psurge_type == PSURGE_DUAL)
-			out_8(psurge_sec_intr, ~0);
-		else
-			PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
-	}
-}
-
-/*
- * On powersurge (old SMP powermac architecture) we don't have
- * separate IPIs for separate messages like openpic does.  Instead
- * we have a bitmap for each processor, where a 1 bit means that
- * the corresponding message is pending for that processor.
- * Ideally each cpu's entry would be in a different cache line.
- *  -- paulus.
- */
-static unsigned long psurge_smp_message[NR_CPUS];
-
-void __pmac
-psurge_smp_message_recv(struct pt_regs *regs)
-{
-	int cpu = smp_processor_id();
-	int msg;
-
-	/* clear interrupt */
-	psurge_clr_ipi(cpu);
-
-	if (smp_num_cpus < 2)
-		return;
-
-	/* make sure there is a message there */
-	for (msg = 0; msg < 4; msg++)
-		if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
-			smp_message_recv(msg, regs);
-}
-
-void __pmac
-psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
-{
-	psurge_smp_message_recv(regs);
-}
-
-static void __pmac
-smp_psurge_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	int i;
-
-	if (smp_num_cpus < 2)
-		return;
-
-	for (i = 0; i < smp_num_cpus; i++) {
-		if (target == MSG_ALL
-		    || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
-		    || target == i) {
-			set_bit(msg, &psurge_smp_message[i]);
-			psurge_set_ipi(i);
-		}
-	}
-}
-
-/*
- * Determine a quad card presence. We read the board ID register, we
- * force the data bus to change to something else, and we read it again.
- * It it's stable, then the register probably exist (ugh !)
- */
-static int __init psurge_quad_probe(void)
-{
-	int type;
-	unsigned int i;
-
-	type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
-	if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
-	    || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-		return PSURGE_DUAL;
-
-	/* looks OK, try a slightly more rigorous test */
-	/* bogus is not necessarily cacheline-aligned,
-	   though I don't suppose that really matters.  -- paulus */
-	for (i = 0; i < 100; i++) {
-		volatile u32 bogus[8];
-		bogus[(0+i)%8] = 0x00000000;
-		bogus[(1+i)%8] = 0x55555555;
-		bogus[(2+i)%8] = 0xFFFFFFFF;
-		bogus[(3+i)%8] = 0xAAAAAAAA;
-		bogus[(4+i)%8] = 0x33333333;
-		bogus[(5+i)%8] = 0xCCCCCCCC;
-		bogus[(6+i)%8] = 0xCCCCCCCC;
-		bogus[(7+i)%8] = 0x33333333;
-		wmb();
-		asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
-		mb();
-		if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-			return PSURGE_DUAL;
-	}
-	return type;
-}
-
-static void __init psurge_quad_init(void)
-{
-	int procbits;
-
-	if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
-	procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
-	if (psurge_type == PSURGE_QUAD_ICEGRASS)
-		PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-	else
-		PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
-	mdelay(33);
-	out_8(psurge_sec_intr, ~0);
-	PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
-	PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-	if (psurge_type != PSURGE_QUAD_ICEGRASS)
-		PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
-	PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
-	mdelay(33);
-	PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
-	mdelay(33);
-	PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
-	mdelay(33);
-}
-
-static int __init smp_psurge_probe(void)
-{
-	int i, ncpus;
-
-	/* We don't do SMP on the PPC601 -- paulus */
-	if (PVR_VER(mfspr(PVR)) == 1)
-		return 1;
-
-	/*
-	 * The powersurge cpu board can be used in the generation
-	 * of powermacs that have a socket for an upgradeable cpu card,
-	 * including the 7500, 8500, 9500, 9600.
-	 * The device tree doesn't tell you if you have 2 cpus because
-	 * OF doesn't know anything about the 2nd processor.
-	 * Instead we look for magic bits in magic registers,
-	 * in the hammerhead memory controller in the case of the
-	 * dual-cpu powersurge board.  -- paulus.
-	 */
-	if (find_devices("hammerhead") == NULL)
-		return 1;
-
-	hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
-	quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
-	psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
-
-	psurge_type = psurge_quad_probe();
-	if (psurge_type != PSURGE_DUAL) {
-		psurge_quad_init();
-		/* All released cards using this HW design have 4 CPUs */
-		ncpus = 4;
-	} else {
-		iounmap((void *) quad_base);
-		if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
-			/* not a dual-cpu card */
-			iounmap((void *) hhead_base);
-			return 1;
-		}
-		ncpus = 2;
-	}
-
-	psurge_start = ioremap(PSURGE_START, 4);
-	psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
-
-	/* this is not actually strictly necessary -- paulus. */
-	for (i = 1; i < ncpus; ++i)
-		smp_hw_index[i] = i;
-
-	if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
-
-	return ncpus;
-}
-
-static void __init smp_psurge_kick_cpu(int nr)
-{
-	void (*start)(void) = __secondary_start_psurge;
-	unsigned long a;
-
-	/* may need to flush here if secondary bats aren't setup */
-	for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
-		asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
-	asm volatile("sync");
-
-	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
-
-	/* setup entry point of secondary processor */
-	switch (nr) {
-	case 2:
-		start = __secondary_start_psurge2;
-		break;
-	case 3:
-		start = __secondary_start_psurge3;
-		break;
-	}
-
-	out_be32(psurge_start, __pa(start));
-	mb();
-
-	psurge_set_ipi(nr);
-	udelay(10);
-	psurge_clr_ipi(nr);
-
-	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
-}
-
-/*
- * With the dual-cpu powersurge board, the decrementers and timebases
- * of both cpus are frozen after the secondary cpu is started up,
- * until we give the secondary cpu another interrupt.  This routine
- * uses this to get the timebases synchronized.
- *  -- paulus.
- */
-static void __init psurge_dual_sync_tb(int cpu_nr)
-{
-	static volatile int sec_tb_reset = 0;
-	int t;
-
-	set_dec(tb_ticks_per_jiffy);
-	set_tb(0, 0);
-	last_jiffy_stamp(cpu_nr) = 0;
-
-	if (cpu_nr > 0) {
-		mb();
-		sec_tb_reset = 1;
-		return;
-	}
-
-	/* wait for the secondary to have reset its TB before proceeding */
-	for (t = 10000000; t > 0 && !sec_tb_reset; --t)
-		;
-
-	/* now interrupt the secondary, starting both TBs */
-	psurge_set_ipi(1);
-
-	smp_tb_synchronized = 1;
-}
-
-static void __init
-smp_psurge_setup_cpu(int cpu_nr)
-{
-
-	if (cpu_nr == 0) {
-		if (smp_num_cpus < 2)
-			return;
-		/* reset the entry point so if we get another intr we won't
-		 * try to startup again */
-		out_be32(psurge_start, 0x100);
-		if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0))
-			printk(KERN_ERR "Couldn't get primary IPI interrupt");
-	}
-
-	if (psurge_type == PSURGE_DUAL)
-		psurge_dual_sync_tb(cpu_nr);
-}
-
-static int __init
-smp_core99_probe(void)
-{
-	struct device_node *cpus;
-	int i, ncpus = 1;
-	extern int powersave_nap;
-
-	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
-	cpus = find_type_devices("cpu");
-	if (cpus)
-		while ((cpus = cpus->next) != NULL)
-			++ncpus;
-	printk("smp_core99_probe: found %d cpus\n", ncpus);
-	if (ncpus > 1) {
-		openpic_request_IPIs();
-		for (i = 1; i < ncpus; ++i)
-			smp_hw_index[i] = i;
-		powersave_nap = 0;
-		cpu_setup_grab();
-	}
-
-	return ncpus;
-}
-
-static void __init
-smp_core99_kick_cpu(int nr)
-{
-	unsigned long save_vector, new_vector;
-	unsigned long flags;
-
-	volatile unsigned long *vector
-		 = ((volatile unsigned long *)(KERNELBASE+0x100));
-	if (nr < 1 || nr > 3)
-		return;
-	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
-
-	local_irq_save(flags);
-	local_irq_disable();
-	
-	/* Save reset vector */
-	save_vector = *vector;
-	
-	/* Setup fake reset vector that does	  
-	 *   b __secondary_start_psurge - KERNELBASE
-	 */  
-	switch(nr) {
-		case 1:
-			new_vector = (unsigned long)__secondary_start_psurge;
-			break;
-		case 2:
-			new_vector = (unsigned long)__secondary_start_psurge2;
-			break;
-		case 3:
-			new_vector = (unsigned long)__secondary_start_psurge3;
-			break;
-	}
-	*vector = 0x48000002 + new_vector - KERNELBASE;
-	
-	/* flush data cache and inval instruction cache */
-	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-	
-	/* Put some life in our friend */
-	pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
-	
-	/* FIXME: We wait a bit for the CPU to take the exception, I should
-	 * instead wait for the entry code to set something for me. Well,
-	 * ideally, all that crap will be done in prom.c and the CPU left
-	 * in a RAM-based wait loop like CHRP.
-	 */
-	mdelay(1);
-	
-	/* Restore our exception vector */
-	*vector = save_vector;
-	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-	
-	local_irq_restore(flags);
-	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
-}
-
-static void __init
-smp_core99_setup_cpu(int cpu_nr)
-{
-	/* Setup some registers */
-	if (cpu_nr != 0)
-		cpu_setup_apply(cpu_nr);
-	
-	/* Setup openpic */
-	do_openpic_setup_cpu();
-
-	/* Setup L2/L3 */
-	if (cpu_nr == 0)
-		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
-}
-
-/* PowerSurge-style Macs */
-struct smp_ops_t psurge_smp_ops __pmacdata = {
-	smp_psurge_message_pass,
-	smp_psurge_probe,
-	smp_psurge_kick_cpu,
-	smp_psurge_setup_cpu,
-};
-
-/* Core99 Macs (dual G4s) */
-struct smp_ops_t core99_smp_ops __pmacdata = {
-	smp_openpic_message_pass,
-	smp_core99_probe,
-	smp_core99_kick_cpu,
-	smp_core99_setup_cpu,
-};
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/pmac_time.c linux-2.4.20-pre2/arch/ppc/kernel/pmac_time.c
--- linux-2.4.20-pre1/arch/ppc/kernel/pmac_time.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/pmac_time.c	Wed Dec 31 16:00:00 1969
@@ -1,282 +0,0 @@
-/*
- * BK Id: SCCS/s.pmac_time.c 1.19 12/04/01 01:24:51 benh
- */
-/*
- * Support for periodic interrupts (100 per second) and for getting
- * the current time from the RTC on Power Macintoshes.
- *
- * We use the decrementer register for our periodic interrupts.
- *
- * Paul Mackerras	August 1996.
- * Copyright (C) 1996 Paul Mackerras.
- */
-#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/init.h>
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/hardirq.h>
-#include <asm/time.h>
-#include <asm/nvram.h>
-
-extern rwlock_t xtime_lock;
-
-/* Apparently the RTC stores seconds since 1 Jan 1904 */
-#define RTC_OFFSET	2082844800
-
-/*
- * Calibrate the decrementer frequency with the VIA timer 1.
- */
-#define VIA_TIMER_FREQ_6	4700000	/* time 1 frequency * 6 */
-
-/* VIA registers */
-#define RS		0x200		/* skip between registers */
-#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
-#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
-#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
-#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
-#define ACR		(11*RS)		/* Auxiliary control register */
-#define IFR		(13*RS)		/* Interrupt flag register */
-
-/* Bits in ACR */
-#define T1MODE		0xc0		/* Timer 1 mode */
-#define T1MODE_CONT	0x40		/*  continuous interrupts */
-
-/* Bits in IFR and IER */
-#define T1_INT		0x40		/* Timer 1 interrupt */
-
-extern struct timezone sys_tz;
-
-long __init
-pmac_time_init(void)
-{
-#ifdef CONFIG_NVRAM
-	s32 delta = 0;
-	int dst;
-	
-	delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
-	delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
-	delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
-	if (delta & 0x00800000UL)
-		delta |= 0xFF000000UL;
-	dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
-	printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
-		dst ? "on" : "off");
-	return delta;
-#else
-	return 0;
-#endif
-}
-
-unsigned long __pmac
-pmac_get_rtc_time(void)
-{
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
-	struct adb_request req;
-	unsigned long now;
-#endif
-
-	/* Get the time from the RTC */
-	switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-	case SYS_CTRLER_CUDA:
-		if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
-			return 0;
-		while (!req.complete)
-			cuda_poll();
-		if (req.reply_len != 7)
-			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-			       req.reply_len);
-		now = (req.reply[3] << 24) + (req.reply[4] << 16)
-			+ (req.reply[5] << 8) + req.reply[6];
-		return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-	case SYS_CTRLER_PMU:
-		if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
-			return 0;
-		while (!req.complete)
-			pmu_poll();
-		if (req.reply_len != 4)
-			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-			       req.reply_len);
-		now = (req.reply[0] << 24) + (req.reply[1] << 16)
-			+ (req.reply[2] << 8) + req.reply[3];
-		return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_PMU */
-	default: ;
-	}
-	return 0;
-}
-
-int __pmac
-pmac_set_rtc_time(unsigned long nowtime)
-{
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
-	struct adb_request req;
-#endif
-
-	nowtime += RTC_OFFSET;
-
-	switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-	case SYS_CTRLER_CUDA:
-		if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
-				 nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
-			return 0;
-		while (!req.complete)
-			cuda_poll();
-		if ((req.reply_len != 3) && (req.reply_len != 7))
-			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-			       req.reply_len);
-		return 1;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-	case SYS_CTRLER_PMU:
-		if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
-				nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
-			return 0;
-		while (!req.complete)
-			pmu_poll();
-		if (req.reply_len != 0)
-			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-			       req.reply_len);
-		return 1;
-#endif /* CONFIG_ADB_PMU */
-	default:
-		return 0;
-	}
-}
-
-/*
- * Calibrate the decrementer register using VIA timer 1.
- * This is used both on powermacs and CHRP machines.
- */
-int __init
-via_calibrate_decr(void)
-{
-	struct device_node *vias;
-	volatile unsigned char *via;
-	int count = VIA_TIMER_FREQ_6 / HZ;
-	unsigned int dstart, dend;
-
-	vias = find_devices("via-cuda");
-	if (vias == 0)
-		vias = find_devices("via-pmu");
-	if (vias == 0)
-		vias = find_devices("via");
-	if (vias == 0 || vias->n_addrs == 0)
-		return 0;
-	via = (volatile unsigned char *)
-		ioremap(vias->addrs[0].address, vias->addrs[0].size);
-
-	/* set timer 1 for continuous interrupts */
-	out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
-	/* set the counter to a small value */
-	out_8(&via[T1CH], 2);
-	/* set the latch to `count' */
-	out_8(&via[T1LL], count);
-	out_8(&via[T1LH], count >> 8);
-	/* wait until it hits 0 */
-	while ((in_8(&via[IFR]) & T1_INT) == 0)
-		;
-	dstart = get_dec();
-	/* clear the interrupt & wait until it hits 0 again */
-	in_8(&via[T1CL]);
-	while ((in_8(&via[IFR]) & T1_INT) == 0)
-		;
-	dend = get_dec();
-
-	tb_ticks_per_jiffy = (dstart - dend) / 6;
-	tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
-
-	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
-	       tb_ticks_per_jiffy, dstart - dend);
-
-	return 1;
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Reset the time after a sleep.
- */
-static int __pmac
-time_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-	static unsigned long time_diff;
-	unsigned long flags;
-
-	switch (when) {
-	case PBOOK_SLEEP_NOW:
-		read_lock_irqsave(&xtime_lock, flags);
-		time_diff = xtime.tv_sec - pmac_get_rtc_time();
-		read_unlock_irqrestore(&xtime_lock, flags);
-		break;
-	case PBOOK_WAKE:
-		write_lock_irqsave(&xtime_lock, flags);
-		xtime.tv_sec = pmac_get_rtc_time() + time_diff;
-		xtime.tv_usec = 0;
-		last_rtc_update = xtime.tv_sec;
-		write_unlock_irqrestore(&xtime_lock, flags);
-		break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
-	time_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-/*
- * Query the OF and get the decr frequency.
- * This was taken from the pmac time_init() when merging the prep/pmac
- * time functions.
- */
-void __init
-pmac_calibrate_decr(void)
-{
-	struct device_node *cpu;
-	unsigned int freq, *fp;
-
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-
-	/* We assume MacRISC2 machines have correct device-tree
-	 * calibration. That's better since the VIA itself seems
-	 * to be slightly off. --BenH
-	 */
-	if (!machine_is_compatible("MacRISC2"))
-		if (via_calibrate_decr())
-			return;
-
-	/*
-	 * The cpu node should have a timebase-frequency property
-	 * to tell us the rate at which the decrementer counts.
-	 */
-	cpu = find_type_devices("cpu");
-	if (cpu == 0)
-		panic("can't find cpu node in time_init");
-	fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
-	if (fp == 0)
-		panic("can't get cpu timebase frequency");
-	freq = *fp;
-	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
-	       freq/1000000, freq%1000000);
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/ppc4xx_pic.c linux-2.4.20-pre2/arch/ppc/kernel/ppc4xx_pic.c
--- linux-2.4.20-pre1/arch/ppc/kernel/ppc4xx_pic.c	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/ppc4xx_pic.c	Mon Aug 12 16:34:15 2002
@@ -33,10 +33,7 @@
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/irq.h>
-
-#include "local_irq.h"
-#include "ppc4xx_pic.h"
-
+#include <asm/ppc4xx_pic.h>
 
 /* Global Variables */
 
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/ppc4xx_pic.h linux-2.4.20-pre2/arch/ppc/kernel/ppc4xx_pic.h
--- linux-2.4.20-pre1/arch/ppc/kernel/ppc4xx_pic.h	Mon Jul  2 14:34:57 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/ppc4xx_pic.h	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-/*
- * BK Id: SCCS/s.ppc4xx_pic.h 1.8 06/15/01 13:56:56 paulus
- */
-/*
- *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: ppc4xx_pic.h
- *
- *    Description:
- *      Interrupt controller driver for PowerPC 4xx-based processors.
- */
-
-#ifndef	__PPC4XX_PIC_H__
-#define	__PPC4XX_PIC_H__
-
-#include <linux/config.h>
-#include "local_irq.h"
-
-/* External Global Variables */
-
-extern struct hw_interrupt_type *ppc4xx_pic;
-
-
-/* Function Prototypes */
-
-extern void	 ppc4xx_pic_init(void);
-extern int	 ppc4xx_pic_get_irq(struct pt_regs *regs);
-
-#endif /* __PPC4XX_PIC_H__ */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/ppc8260_pic.h linux-2.4.20-pre2/arch/ppc/kernel/ppc8260_pic.h
--- linux-2.4.20-pre1/arch/ppc/kernel/ppc8260_pic.h	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/ppc8260_pic.h	Mon Aug 12 16:34:15 2002
@@ -1,11 +1,11 @@
 /*
- * BK Id: SCCS/s.ppc8260_pic.h 1.7 05/17/01 18:14:21 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 
 #ifndef _PPC_KERNEL_PPC8260_H
 #define _PPC_KERNEL_PPC8260_H
 
-#include "local_irq.h"
+#include <linux/irq.h>
 
 extern struct hw_interrupt_type ppc8260_pic;
 
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/ppc8xx_pic.h linux-2.4.20-pre2/arch/ppc/kernel/ppc8xx_pic.h
--- linux-2.4.20-pre1/arch/ppc/kernel/ppc8xx_pic.h	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/ppc8xx_pic.h	Mon Aug 12 16:34:15 2002
@@ -1,11 +1,11 @@
 /*
- * BK Id: SCCS/s.ppc8xx_pic.h 1.7 05/17/01 18:14:21 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifndef _PPC_KERNEL_PPC8xx_H
 #define _PPC_KERNEL_PPC8xx_H
 
 #include <linux/config.h>
-#include "local_irq.h"
+#include <linux/irq.h>
 
 extern struct hw_interrupt_type ppc8xx_pic;
 
@@ -15,7 +15,7 @@
 int m8xx_get_irq(struct pt_regs *regs);
 
 #ifdef CONFIG_MBX
-#include "i8259.h"
+#include <asm/i8259.h>
 #include <asm/io.h>
 void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs);
 #endif
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/ppc_asm.h linux-2.4.20-pre2/arch/ppc/kernel/ppc_asm.h
--- linux-2.4.20-pre1/arch/ppc/kernel/ppc_asm.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/ppc_asm.h	Wed Dec 31 16:00:00 1969
@@ -1,159 +0,0 @@
-/*
- * BK Id: SCCS/s.ppc_asm.h 1.20 03/19/02 15:04:39 benh
- */
-/*
- * 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)	stw	n,GPR0+4*(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)	lwz	n,GPR0+4*(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)
-
-/*
- * Once a version of gas that understands the AltiVec instructions
- * is freely available, we can do this the normal way...  - paulus
- */
-#define LVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1)
-#define STVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
-#define MFVSCR(r)	.long	(4<<26)+((r)<<21)+(770<<1)
-#define MTVSCR(r)	.long	(4<<26)+((r)<<11)+(802<<1)
-#define DSSALL		.long	(0x1f<<26)+(0x10<<21)+(0x336<<1)
-
-#define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); STVX(n,b,base)
-#define SAVE_2VR(n,b,base)	SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) 
-#define SAVE_4VR(n,b,base)	SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) 
-#define SAVE_8VR(n,b,base)	SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) 
-#define SAVE_16VR(n,b,base)	SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base)
-#define SAVE_32VR(n,b,base)	SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base)
-#define REST_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); LVX(n,b,base)
-#define REST_2VR(n,b,base)	REST_VR(n,b,base); REST_VR(n+1,b,base) 
-#define REST_4VR(n,b,base)	REST_2VR(n,b,base); REST_2VR(n+2,b,base) 
-#define REST_8VR(n,b,base)	REST_4VR(n,b,base); REST_4VR(n+4,b,base) 
-#define REST_16VR(n,b,base)	REST_8VR(n,b,base); REST_8VR(n+8,b,base) 
-#define REST_32VR(n,b,base)	REST_16VR(n,b,base); REST_16VR(n+16,b,base)
-
-#ifdef CONFIG_PPC601_SYNC_FIX
-#define SYNC				\
-BEGIN_FTR_SECTION			\
-	sync;				\
-	isync;				\
-END_FTR_SECTION_IFSET(CPU_FTR_601)
-#define SYNC_601			\
-BEGIN_FTR_SECTION			\
-	sync;				\
-END_FTR_SECTION_IFSET(CPU_FTR_601)
-#define ISYNC_601			\
-BEGIN_FTR_SECTION			\
-	isync;				\
-END_FTR_SECTION_IFSET(CPU_FTR_601)
-#else
-#define	SYNC
-#define SYNC_601
-#define ISYNC_601
-#endif
-
-#ifndef CONFIG_SMP
-#define TLBSYNC
-#else /* CONFIG_SMP */
-/* tlbsync is not implemented on 601 */
-#define TLBSYNC				\
-BEGIN_FTR_SECTION			\
-	tlbsync;			\
-	sync;				\
-END_FTR_SECTION_IFCLR(CPU_FTR_601)
-#endif
-
-/*
- * This instruction is not implemented on the PPC 603 or 601; however, on
- * the 403GCX and 405GP tlbia IS defined and tlbie is not.
- * All of these instructions exist in the 8xx, they have magical powers,
- * and they must be used.
- */
-
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
-#define tlbia					\
-	li	r4,1024;			\
-	mtctr	r4;				\
-	lis	r4,KERNELBASE@h;		\
-0:	tlbie	r4;				\
-	addi	r4,r4,0x1000;			\
-	bdnz	0b
-#endif
-
-/*
- * On APUS (Amiga PowerPC cpu upgrade board), we don't know the
- * physical base address of RAM at compile time.
- */
-#define tophys(rd,rs)				\
-0:	addis	rd,rs,-KERNELBASE@h;		\
-	.section ".vtop_fixup","aw";		\
-	.align  1;				\
-	.long   0b;				\
-	.previous
-
-#define tovirt(rd,rs)				\
-0:	addis	rd,rs,KERNELBASE@h;		\
-	.section ".ptov_fixup","aw";		\
-	.align  1;				\
-	.long   0b;				\
-	.previous
-
-/*
- * On 64-bit cpus, we use the rfid instruction instead of rfi, but
- * we then have to make sure we preserve the top 32 bits except for
- * the 64-bit mode bit, which we clear.
- */
-#ifdef CONFIG_PPC64BRIDGE
-#define	FIX_SRR1(ra, rb)	\
-	mr	rb,ra;		\
-	mfmsr	ra;		\
-	clrldi	ra,ra,1;		/* turn off 64-bit mode */ \
-	rldimi	ra,rb,0,32
-#define	RFI		.long	0x4c000024	/* rfid instruction */
-#define MTMSRD(r)	.long	(0x7c000164 + ((r) << 21))	/* mtmsrd */
-#define CLR_TOP32(r)	rlwinm	(r),(r),0,0,31	/* clear top 32 bits */
-
-#else
-#define FIX_SRR1(ra, rb)
-#define	RFI		rfi
-#define MTMSRD(r)	mtmsr	r
-#define CLR_TOP32(r)
-#endif /* CONFIG_PPC64BRIDGE */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/ppc_asm.tmpl linux-2.4.20-pre2/arch/ppc/kernel/ppc_asm.tmpl
--- linux-2.4.20-pre1/arch/ppc/kernel/ppc_asm.tmpl	Sun Feb 13 10:47:01 2000
+++ linux-2.4.20-pre2/arch/ppc/kernel/ppc_asm.tmpl	Wed Dec 31 16:00:00 1969
@@ -1,115 +0,0 @@
-/* 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.20-pre1/arch/ppc/kernel/prep_nvram.c linux-2.4.20-pre2/arch/ppc/kernel/prep_nvram.c
--- linux-2.4.20-pre1/arch/ppc/kernel/prep_nvram.c	Sat Sep  8 12:38:42 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/prep_nvram.c	Mon Aug 12 16:34:15 2002
@@ -1,8 +1,8 @@
 /*
- * BK Id: SCCS/s.prep_nvram.c 1.12 09/08/01 15:47:42 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
- *  linux/arch/ppc/kernel/prep_nvram.c
+ *  arch/ppc/platforms/prep_nvram.c
  *
  *  Copyright (C) 1998  Corey Minyard
  *
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/prep_pci.c linux-2.4.20-pre2/arch/ppc/kernel/prep_pci.c
--- linux-2.4.20-pre1/arch/ppc/kernel/prep_pci.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/prep_pci.c	Wed Dec 31 16:00:00 1969
@@ -1,1271 +0,0 @@
-/*
- * BK Id: SCCS/s.prep_pci.c 1.33 12/20/01 15:36:12 trini
- */
-/*
- * PReP pci functions.
- * Originally by Gary Thomas
- * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
- *
- * The motherboard routes/maps will disappear shortly. -- Cort
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/sections.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/ptrace.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/residual.h>
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/machdep.h>
-
-#include "pci.h"
-#include "open_pic.h"
-
-#define MAX_DEVNR 22
-
-/* Which PCI interrupt line does a given device [slot] use? */
-/* Note: This really should be two dimensional based in slot/pin used */
-static unsigned char *Motherboard_map;
-unsigned char *Motherboard_map_name;
-
-/* How is the 82378 PIRQ mapping setup? */
-static unsigned char *Motherboard_routes;
-
-static void (*Motherboard_non0)(struct pci_dev *);
-
-static void Powerplus_Map_Non0(struct pci_dev *);
-
-/* Used for Motorola to store system config register */
-static unsigned long	*ProcInfo;
-
-/* Tables for known hardware */   
-
-/* Motorola PowerStackII - Utah */
-static char Utah_pci_IRQ_map[23] __prepdata =
-{
-        0,   /* Slot 0  - unused */
-        0,   /* Slot 1  - unused */
-        5,   /* Slot 2  - SCSI - NCR825A  */
-        0,   /* Slot 3  - unused */
-        1,   /* Slot 4  - Ethernet - DEC2114x */
-        0,   /* Slot 5  - unused */
-        3,   /* Slot 6  - PCI Card slot #1 */
-        4,   /* Slot 7  - PCI Card slot #2 */
-        5,   /* Slot 8  - PCI Card slot #3 */
-        5,   /* Slot 9  - PCI Bridge */
-             /* added here in case we ever support PCI bridges */
-             /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
-        0,   /* Slot 10 - unused */
-        0,   /* Slot 11 - unused */
-        5,   /* Slot 12 - SCSI - NCR825A */
-        0,   /* Slot 13 - unused */
-        3,   /* Slot 14 - enet */
-        0,   /* Slot 15 - unused */
-        2,   /* Slot 16 - unused */
-        3,   /* Slot 17 - unused */
-        5,   /* Slot 18 - unused */
-        0,   /* Slot 19 - unused */
-        0,   /* Slot 20 - unused */
-        0,   /* Slot 21 - unused */
-        0,   /* Slot 22 - unused */
-};
-
-static char Utah_pci_IRQ_routes[] __prepdata =
-{
-        0,   /* Line 0 - Unused */
-        9,   /* Line 1 */
-	10,  /* Line 2 */
-        11,  /* Line 3 */
-        14,  /* Line 4 */
-        15,  /* Line 5 */
-};
-
-/* Motorola PowerStackII - Omaha */
-/* no integrated SCSI or ethernet */
-static char Omaha_pci_IRQ_map[23] __prepdata =
-{
-        0,   /* Slot 0  - unused */
-        0,   /* Slot 1  - unused */
-        3,   /* Slot 2  - Winbond EIDE */
-        0,   /* Slot 3  - unused */
-        0,   /* Slot 4  - unused */
-        0,   /* Slot 5  - unused */
-        1,   /* Slot 6  - PCI slot 1 */
-        2,   /* Slot 7  - PCI slot 2  */
-        3,   /* Slot 8  - PCI slot 3 */
-        4,   /* Slot 9  - PCI slot 4 */ /* needs indirect access */
-        0,   /* Slot 10 - unused */
-        0,   /* Slot 11 - unused */
-        0,   /* Slot 12 - unused */
-        0,   /* Slot 13 - unused */
-        0,   /* Slot 14 - unused */
-        0,   /* Slot 15 - unused */
-        1,   /* Slot 16  - PCI slot 1 */
-        2,   /* Slot 17  - PCI slot 2  */
-        3,   /* Slot 18  - PCI slot 3 */
-        4,   /* Slot 19  - PCI slot 4 */ /* needs indirect access */
-        0,
-        0,
-        0,
-};
-
-static char Omaha_pci_IRQ_routes[] __prepdata =
-{
-        0,   /* Line 0 - Unused */
-        9,   /* Line 1 */
-        11,  /* Line 2 */
-        14,  /* Line 3 */
-        15   /* Line 4 */
-};
-
-/* Motorola PowerStack */
-static char Blackhawk_pci_IRQ_map[19] __prepdata =
-{
-  	0,	/* Slot 0  - unused */
-  	0,	/* Slot 1  - unused */
-  	0,	/* Slot 2  - unused */
-  	0,	/* Slot 3  - unused */
-  	0,	/* Slot 4  - unused */
-  	0,	/* Slot 5  - unused */
-  	0,	/* Slot 6  - unused */
-  	0,	/* Slot 7  - unused */
-  	0,	/* Slot 8  - unused */
-  	0,	/* Slot 9  - unused */
-  	0,	/* Slot 10 - unused */
-  	0,	/* Slot 11 - unused */
-  	3,	/* Slot 12 - SCSI */
-  	0,	/* Slot 13 - unused */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - unused */
- 	1,	/* Slot P7 */
- 	2,	/* Slot P6 */
- 	3,	/* Slot P5 */
-};
-
-static char Blackhawk_pci_IRQ_routes[] __prepdata =
-{
-   	0,	/* Line 0 - Unused */
-   	9,	/* Line 1 */
-   	11,	/* Line 2 */
-   	15,	/* Line 3 */
-   	15	/* Line 4 */
-};
-   
-/* Motorola Mesquite */
-static char Mesquite_pci_IRQ_map[23] __prepdata =
-{
-	0,	/* Slot 0  - unused */
-	0,	/* Slot 1  - unused */
-	0,	/* Slot 2  - unused */
-	0,	/* Slot 3  - unused */
-	0,	/* Slot 4  - unused */
-	0,	/* Slot 5  - unused */
-	0,	/* Slot 6  - unused */
-	0,	/* Slot 7  - unused */
-	0,	/* Slot 8  - unused */
-	0,	/* Slot 9  - unused */
-	0,	/* Slot 10 - unused */
-	0,	/* Slot 11 - unused */
-	0,	/* Slot 12 - unused */
-	0,	/* Slot 13 - unused */
-	2,	/* Slot 14 - Ethernet */
-	0,	/* Slot 15 - unused */
-	3,	/* Slot 16 - PMC */
-	0,	/* Slot 17 - unused */
-	0,	/* Slot 18 - unused */
-	0,	/* Slot 19 - unused */
-	0,	/* Slot 20 - unused */
-	0,	/* Slot 21 - unused */
-	0,	/* Slot 22 - unused */
-};
-
-/* Motorola Sitka */
-static char Sitka_pci_IRQ_map[21] __prepdata =
-{
-	0,      /* Slot 0  - unused */
-	0,      /* Slot 1  - unused */
-	0,      /* Slot 2  - unused */
-	0,      /* Slot 3  - unused */
-	0,      /* Slot 4  - unused */
-	0,      /* Slot 5  - unused */
-	0,      /* Slot 6  - unused */
-	0,      /* Slot 7  - unused */
-	0,      /* Slot 8  - unused */
-	0,      /* Slot 9  - unused */
-	0,      /* Slot 10 - unused */
-	0,      /* Slot 11 - unused */
-	0,      /* Slot 12 - unused */
-	0,      /* Slot 13 - unused */
-	2,      /* Slot 14 - Ethernet */
-	0,      /* Slot 15 - unused */
-	9,      /* Slot 16 - PMC 1  */
-	12,     /* Slot 17 - PMC 2  */
-	0,      /* Slot 18 - unused */
-	0,      /* Slot 19 - unused */
-	4,      /* Slot 20 - NT P2P bridge */
-};
-
-/* Motorola MTX */
-static char MTX_pci_IRQ_map[23] __prepdata =
-{
-	0,	/* Slot 0  - unused */
-	0,	/* Slot 1  - unused */
-	0,	/* Slot 2  - unused */
-	0,	/* Slot 3  - unused */
-	0,	/* Slot 4  - unused */
-	0,	/* Slot 5  - unused */
-	0,	/* Slot 6  - unused */
-	0,	/* Slot 7  - unused */
-	0,	/* Slot 8  - unused */
-	0,	/* Slot 9  - unused */
-	0,	/* Slot 10 - unused */
-	0,	/* Slot 11 - unused */
-	3,	/* Slot 12 - SCSI */
-	0,	/* Slot 13 - unused */
-	2,	/* Slot 14 - Ethernet */
-	0,	/* Slot 15 - unused */
-	9,      /* Slot 16 - PCI/PMC slot 1 */
-	10,     /* Slot 17 - PCI/PMC slot 2 */
-	11,     /* Slot 18 - PCI slot 3 */
-	0,	/* Slot 19 - unused */
-	0,	/* Slot 20 - unused */
-	0,	/* Slot 21 - unused */
-	0,	/* Slot 22 - unused */
-};
-
-/* Motorola MTX Plus */
-/* Secondary bus interrupt routing is not supported yet */
-static char MTXplus_pci_IRQ_map[23] __prepdata =
-{
-        0,      /* Slot 0  - unused */
-        0,      /* Slot 1  - unused */
-        0,      /* Slot 2  - unused */
-        0,      /* Slot 3  - unused */
-        0,      /* Slot 4  - unused */
-        0,      /* Slot 5  - unused */
-        0,      /* Slot 6  - unused */
-        0,      /* Slot 7  - unused */
-        0,      /* Slot 8  - unused */
-        0,      /* Slot 9  - unused */
-        0,      /* Slot 10 - unused */
-        0,      /* Slot 11 - unused */
-        3,      /* Slot 12 - SCSI */
-        0,      /* Slot 13 - unused */
-        2,      /* Slot 14 - Ethernet 1 */
-        0,      /* Slot 15 - unused */
-        9,      /* Slot 16 - PCI slot 1P */
-        10,     /* Slot 17 - PCI slot 2P */
-        11,     /* Slot 18 - PCI slot 3P */
-        10,     /* Slot 19 - Ethernet 2 */
-        0,      /* Slot 20 - P2P Bridge */
-        0,      /* Slot 21 - unused */
-        0,      /* Slot 22 - unused */
-};
-
-static char Raven_pci_IRQ_routes[] __prepdata =
-{
-   	0,	/* This is a dummy structure */
-};
-   
-/* Motorola MVME16xx */
-static char Genesis_pci_IRQ_map[16] __prepdata =
-{
-  	0,	/* Slot 0  - unused */
-  	0,	/* Slot 1  - unused */
-  	0,	/* Slot 2  - unused */
-  	0,	/* Slot 3  - unused */
-  	0,	/* Slot 4  - unused */
-  	0,	/* Slot 5  - unused */
-  	0,	/* Slot 6  - unused */
-  	0,	/* Slot 7  - unused */
-  	0,	/* Slot 8  - unused */
-  	0,	/* Slot 9  - unused */
-  	0,	/* Slot 10 - unused */
-  	0,	/* Slot 11 - unused */
-  	3,	/* Slot 12 - SCSI */
-  	0,	/* Slot 13 - unused */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - unused */
-};
-
-static char Genesis_pci_IRQ_routes[] __prepdata =
-{
-   	0,	/* Line 0 - Unused */
-   	10,	/* Line 1 */
-   	11,	/* Line 2 */
-   	14,	/* Line 3 */
-   	15	/* Line 4 */
-};
-   
-static char Genesis2_pci_IRQ_map[23] __prepdata =
-{
-	0,	/* Slot 0  - unused */
-	0,	/* Slot 1  - unused */
-	0,	/* Slot 2  - unused */
-	0,	/* Slot 3  - unused */
-	0,	/* Slot 4  - unused */
-	0,	/* Slot 5  - unused */
-	0,	/* Slot 6  - unused */
-	0,	/* Slot 7  - unused */
-	0,	/* Slot 8  - unused */
-	0,	/* Slot 9  - unused */
-	0,	/* Slot 10 - Ethernet */
-	0,	/* Slot 11 - Universe PCI - VME Bridge */
-	3,	/* Slot 12 - unused */
-	0,	/* Slot 13 - unused */
-	2,	/* Slot 14 - SCSI */
-	0,	/* Slot 15 - unused */
-	9,	/* Slot 16 - PMC 1 */
-	12,	/* Slot 17 - pci */
-	11,	/* Slot 18 - pci */
-	10,	/* Slot 19 - pci */
-	0,	/* Slot 20 - pci */
-	0,	/* Slot 21 - unused */
-	0,	/* Slot 22 - unused */
-};
-
-/* Motorola Series-E */
-static char Comet_pci_IRQ_map[23] __prepdata =
-{
-  	0,	/* Slot 0  - unused */
-  	0,	/* Slot 1  - unused */
-  	0,	/* Slot 2  - unused */
-  	0,	/* Slot 3  - unused */
-  	0,	/* Slot 4  - unused */
-  	0,	/* Slot 5  - unused */
-  	0,	/* Slot 6  - unused */
-  	0,	/* Slot 7  - unused */
-  	0,	/* Slot 8  - unused */
-  	0,	/* Slot 9  - unused */
-  	0,	/* Slot 10 - unused */
-  	0,	/* Slot 11 - unused */
-  	3,	/* Slot 12 - SCSI */
-  	0,	/* Slot 13 - unused */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - unused */
-	1,	/* Slot 16 - PCI slot 1 */
-	2,	/* Slot 17 - PCI slot 2 */
-	3,	/* Slot 18 - PCI slot 3 */
-	4,	/* Slot 19 - PCI bridge */
-	0,
-	0,
-	0,
-};
-
-static char Comet_pci_IRQ_routes[] __prepdata =
-{
-   	0,	/* Line 0 - Unused */
-   	10,	/* Line 1 */
-   	11,	/* Line 2 */
-   	14,	/* Line 3 */
-   	15	/* Line 4 */
-};
-
-/* Motorola Series-EX */
-static char Comet2_pci_IRQ_map[23] __prepdata =
-{
-	0,	/* Slot 0  - unused */
-	0,	/* Slot 1  - unused */
-	3,	/* Slot 2  - SCSI - NCR825A */
-	0,	/* Slot 3  - unused */
-	1,	/* Slot 4  - Ethernet - DEC2104X */
-	0,	/* Slot 5  - unused */
-	1,	/* Slot 6  - PCI slot 1 */
-	2,	/* Slot 7  - PCI slot 2 */
-	3,	/* Slot 8  - PCI slot 3 */
-	4,	/* Slot 9  - PCI bridge  */
-	0,	/* Slot 10 - unused */
-	0,	/* Slot 11 - unused */
-	3,	/* Slot 12 - SCSI - NCR825A */
-	0,	/* Slot 13 - unused */
-	1,	/* Slot 14 - Ethernet - DEC2104X */
-	0,	/* Slot 15 - unused */
-	1,	/* Slot 16 - PCI slot 1 */
-	2,	/* Slot 17 - PCI slot 2 */
-	3,	/* Slot 18 - PCI slot 3 */
-	4,	/* Slot 19 - PCI bridge */
-	0,
-	0,
-	0,
-};
-
-static char Comet2_pci_IRQ_routes[] __prepdata =
-{
-	0,	/* Line 0 - Unused */
-	10,	/* Line 1 */
-	11,	/* Line 2 */
-	14,	/* Line 3 */
-	15,	/* Line 4 */
-};
-
-/*
- * ibm 830 (and 850?).
- * This is actually based on the Carolina motherboard
- * -- Cort
- */
-static char ibm8xx_pci_IRQ_map[23] __prepdata = {
-        0, /* Slot 0  - unused */
-        0, /* Slot 1  - unused */
-        0, /* Slot 2  - unused */
-        0, /* Slot 3  - unused */
-        0, /* Slot 4  - unused */
-        0, /* Slot 5  - unused */
-        0, /* Slot 6  - unused */
-        0, /* Slot 7  - unused */
-        0, /* Slot 8  - unused */
-        0, /* Slot 9  - unused */
-        0, /* Slot 10 - unused */
-        0, /* Slot 11 - FireCoral */
-        4, /* Slot 12 - Ethernet  PCIINTD# */
-        2, /* Slot 13 - PCI Slot #2 */
-        2, /* Slot 14 - S3 Video PCIINTD# */
-        0, /* Slot 15 - onboard SCSI (INDI) [1] */
-        3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
-        0, /* Slot 17 - unused */
-        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
-        0, /* Slot 19 - unused */
-        0, /* Slot 20 - unused */
-        0, /* Slot 21 - unused */
-        2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
-};
-
-static char ibm8xx_pci_IRQ_routes[] __prepdata = {
-        0,      /* Line 0 - unused */
-        15,     /* Line 1 */
-        15,     /* Line 2 */
-        15,     /* Line 3 */
-        15,     /* Line 4 */
-};
-
-/*
- * a 6015 ibm board
- * -- Cort
- */
-static char ibm6015_pci_IRQ_map[23] __prepdata = {
-        0, /* Slot 0  - unused */
-        0, /* Slot 1  - unused */
-        0, /* Slot 2  - unused */
-        0, /* Slot 3  - unused */
-        0, /* Slot 4  - unused */
-        0, /* Slot 5  - unused */
-        0, /* Slot 6  - unused */
-        0, /* Slot 7  - unused */
-        0, /* Slot 8  - unused */
-        0, /* Slot 9  - unused */
-        0, /* Slot 10 - unused */
-        0, /* Slot 11 -  */
-        1, /* Slot 12 - SCSI */
-        2, /* Slot 13 -  */
-        2, /* Slot 14 -  */
-        1, /* Slot 15 -  */
-        1, /* Slot 16 -  */
-        0, /* Slot 17 -  */
-        2, /* Slot 18 -  */
-        0, /* Slot 19 -  */
-        0, /* Slot 20 -  */
-        0, /* Slot 21 -  */
-        2, /* Slot 22 -  */
-};
-
-static char ibm6015_pci_IRQ_routes[] __prepdata = {
-        0,      /* Line 0 - unused */
-        13,     /* Line 1 */
-        15,     /* Line 2 */
-        15,     /* Line 3 */
-        15,     /* Line 4 */
-};
-
-
-/* IBM Nobis and Thinkpad 850 */
-static char Nobis_pci_IRQ_map[23] __prepdata ={
-        0, /* Slot 0  - unused */
-        0, /* Slot 1  - unused */
-        0, /* Slot 2  - unused */
-        0, /* Slot 3  - unused */
-        0, /* Slot 4  - unused */
-        0, /* Slot 5  - unused */
-        0, /* Slot 6  - unused */
-        0, /* Slot 7  - unused */
-        0, /* Slot 8  - unused */
-        0, /* Slot 9  - unused */
-        0, /* Slot 10 - unused */
-        0, /* Slot 11 - unused */
-        3, /* Slot 12 - SCSI */
-        0, /* Slot 13 - unused */
-        0, /* Slot 14 - unused */
-        0, /* Slot 15 - unused */
-};
-
-static char Nobis_pci_IRQ_routes[] __prepdata = {
-        0, /* Line 0 - Unused */
-        13, /* Line 1 */
-        13, /* Line 2 */
-        13, /* Line 3 */
-        13      /* Line 4 */
-};
-
-/*
- * IBM RS/6000 43p/140  -- paulus
- * XXX we should get all this from the residual data
- */
-static char ibm43p_pci_IRQ_map[23] __prepdata = {
-        0, /* Slot 0  - unused */
-        0, /* Slot 1  - unused */
-        0, /* Slot 2  - unused */
-        0, /* Slot 3  - unused */
-        0, /* Slot 4  - unused */
-        0, /* Slot 5  - unused */
-        0, /* Slot 6  - unused */
-        0, /* Slot 7  - unused */
-        0, /* Slot 8  - unused */
-        0, /* Slot 9  - unused */
-        0, /* Slot 10 - unused */
-        0, /* Slot 11 - FireCoral ISA bridge */
-        6, /* Slot 12 - Ethernet  */
-        0, /* Slot 13 - openpic */
-        0, /* Slot 14 - unused */
-        0, /* Slot 15 - unused */
-        7, /* Slot 16 - NCR58C825a onboard scsi */
-        0, /* Slot 17 - unused */
-        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
-        0, /* Slot 19 - unused */
-        0, /* Slot 20 - unused */
-        0, /* Slot 21 - unused */
-        1, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
-};
-
-static char ibm43p_pci_IRQ_routes[] __prepdata = {
-        0,      /* Line 0 - unused */
-        15,     /* Line 1 */
-        15,     /* Line 2 */
-        15,     /* Line 3 */
-        15,     /* Line 4 */
-};
-
-/* Motorola PowerPlus architecture PCI IRQ tables */
-/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
-
-struct powerplus_irq_list
-{
-	unsigned char primary[4];       /* INT A-D */
-	unsigned char secondary[4];     /* INT A-D */
-};
-
-/*
- * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
- * OpenPIC inputs 9-12.  PCI INTs A-D from the on board P2P bridge
- * are routed to OpenPIC inputs 5-8.  These values are offset by
- * 16 in the table to reflect the Linux kernel interrupt value.
- */
-struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata =
-{
-	{25, 26, 27, 28},
-	{21, 22, 23, 24}
-};
-
-/*
- * For the MCP750 (system slot board), cPCI INTs A-D are routed to
- * OpenPIC inputs 8-11 and the PMC INTs A-D are routed to OpenPIC
- * input 3.  On a hot swap MCP750, the companion card PCI INTs A-D
- * are routed to OpenPIC inputs 12-15. These values are offset by
- * 16 in the table to reflect the Linux kernel interrupt value.
- */
-struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata =
-{
-	{24, 25, 26, 27},
-	{28, 29, 30, 31}
-};
-
-/*
- * This table represents the standard PCI swizzle defined in the
- * PCI bus specification.
- */
-static unsigned char prep_pci_intpins[4][4] __prepdata =
-{
-	{ 1, 2, 3, 4},  /* Buses 0, 4, 8, ... */
-	{ 2, 3, 4, 1},  /* Buses 1, 5, 9, ... */
-	{ 3, 4, 1, 2},  /* Buses 2, 6, 10 ... */
-	{ 4, 1, 2, 3},  /* Buses 3, 7, 11 ... */
-};
-
-/* We have to turn on LEVEL mode for changed IRQ's */
-/* All PCI IRQ's need to be level mode, so this should be something
- * other than hard-coded as well... IRQ's are individually mappable
- * to either edge or level.
- */
-
-/*
- * 8259 edge/level control definitions
- */
-#define ISA8259_M_ELCR 0x4d0
-#define ISA8259_S_ELCR 0x4d1
-
-#define ELCRS_INT15_LVL         0x80
-#define ELCRS_INT14_LVL         0x40
-#define ELCRS_INT12_LVL         0x10
-#define ELCRS_INT11_LVL         0x08
-#define ELCRS_INT10_LVL         0x04
-#define ELCRS_INT9_LVL          0x02
-#define ELCRS_INT8_LVL          0x01
-#define ELCRM_INT7_LVL          0x80
-#define ELCRM_INT5_LVL          0x20
-
-#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset)
-#define DEVNO(dev)  (dev>>3)                                  
-
-#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
-#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
-
-#define cfg_read_bad(val, size)		*val = bad_##size;
-#define cfg_write_bad(val, size)
-
-#define bad_byte	0xff
-#define bad_word	0xffff
-#define bad_dword	0xffffffffU
-
-#define PREP_PCI_OP(rw, size, type, op)					\
-static int __prep							\
-prep_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
-{									\
-	if ((dev->bus->number != 0) || (DEVNO(dev->devfn) > MAX_DEVNR))	\
-	{                   						\
-		cfg_##rw##_bad(val, size)				\
-		return PCIBIOS_DEVICE_NOT_FOUND;    			\
-	}								\
-	cfg_##rw(val, CFGPTR(dev->devfn), type, op);			\
-	return PCIBIOS_SUCCESSFUL;					\
-}
-
-PREP_PCI_OP(read, byte, u8 *, in_8)
-PREP_PCI_OP(read, word, u16 *, in_le16)
-PREP_PCI_OP(read, dword, u32 *, in_le32)
-PREP_PCI_OP(write, byte, u8, out_8)
-PREP_PCI_OP(write, word, u16, out_le16)
-PREP_PCI_OP(write, dword, u32, out_le32)
-
-static struct pci_ops prep_pci_ops =
-{
-	prep_read_config_byte,
-	prep_read_config_word,
-	prep_read_config_dword,
-	prep_write_config_byte,
-	prep_write_config_word,
-	prep_write_config_dword
-};
-
-#define MOTOROLA_CPUTYPE_REG	0x800
-#define MOTOROLA_BASETYPE_REG	0x803
-#define MPIC_RAVEN_ID		0x48010000
-#define	MPIC_HAWK_ID		0x48030000
-#define	MOT_PROC2_BIT		0x800
-
-static u_char mvme2600_openpic_initsenses[] __initdata = {
-    1,	/* MVME2600_INT_SIO */
-    0,	/* MVME2600_INT_FALCN_ECC_ERR */
-    1,	/* MVME2600_INT_PCI_ETHERNET */
-    1,	/* MVME2600_INT_PCI_SCSI */
-    1,	/* MVME2600_INT_PCI_GRAPHICS */
-    1,	/* MVME2600_INT_PCI_VME0 */
-    1,	/* MVME2600_INT_PCI_VME1 */
-    1,	/* MVME2600_INT_PCI_VME2 */
-    1,	/* MVME2600_INT_PCI_VME3 */
-    1,	/* MVME2600_INT_PCI_INTA */
-    1,	/* MVME2600_INT_PCI_INTB */
-    1,	/* MVME2600_INT_PCI_INTC */
-    1,	/* MVME2600_INT_PCI_INTD */
-    1,	/* MVME2600_INT_LM_SIG0 */
-    1,	/* MVME2600_INT_LM_SIG1 */
-};
-
-#define MOT_RAVEN_PRESENT	0x1
-#define MOT_HAWK_PRESENT	0x2
-
-int mot_entry = -1;
-int prep_keybd_present = 1;
-int MotMPIC;
-int mot_multi;
-
-int __init
-raven_init(void)
-{
-	unsigned int	devid;
-	unsigned int	pci_membase;
-	unsigned char	base_mod;
-
-	/* Check to see if the Raven chip exists. */
-	if ( _prep_type != _PREP_Motorola) {
-		OpenPIC_Addr = NULL;
-		return 0;
-	}
-
-	/* Check to see if this board is a type that might have a Raven. */
-	if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
-		OpenPIC_Addr = NULL;
-		return 0;
-	}
-
-	/* Check the first PCI device to see if it is a Raven. */
-	early_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &devid);
-
-	switch (devid & 0xffff0000) {
-	case MPIC_RAVEN_ID:
-		MotMPIC = MOT_RAVEN_PRESENT;
-		break;
-	case MPIC_HAWK_ID:
-		MotMPIC = MOT_HAWK_PRESENT;
-		break;
-	default:
-		OpenPIC_Addr = NULL;
-		return 0;
-	}
-
-
-	/* Read the memory base register. */
-	early_read_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
-
-	if (pci_membase == 0) {
-		OpenPIC_Addr = NULL;
-		return 0;
-	}
-
-	/* Map the Raven MPIC registers to virtual memory. */
-	OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000);
-
-	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
-
-	ppc_md.get_irq = openpic_get_irq;
-	
-	/* If raven is present on Motorola store the system config register
-	 * for later use.
-	 */
-	ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
-
-	/* Indicate to system if this is a multiprocessor board */
-	if (!(*ProcInfo & MOT_PROC2_BIT)) {
-		mot_multi = 1;
-	}
-
-	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
-	 * no keyboard controller and we have to indicate that.
-	 */
-	base_mod = inb(MOTOROLA_BASETYPE_REG);
-	if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
-	    (base_mod == 0xFA) || (base_mod == 0xE1))
-		prep_keybd_present = 0;
-
-	return 1;
-}
-
-struct mot_info {
-	int		cpu_type;	/* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
-					/* 0x200 if this board has a Hawk chip. */
-	int		base_type;
-	int		max_cpu;	/* ored with 0x80 if this board should be checked for multi CPU */
-	const char	*name;
-	unsigned char	*map;
-	unsigned char	*routes;
-	void            (*map_non0_bus)(struct pci_dev *);      /* For boards with more than bus 0 devices. */
-	struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
-	unsigned char   secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */
-} mot_info[] __prepdata = {
-	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes, NULL, NULL, 0x00},
-	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
-	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
-	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
-	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
-	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
-	{0x000, 0x00, 0x00, "",					NULL,			NULL, NULL, NULL, 0x00}
-};
-
-void __init
-ibm_prep_init(void)
-{
-	u32 addr;
-#ifdef CONFIG_PREP_RESIDUAL
-	PPC_DEVICE *mpic;
-#endif
-
-	if (inb(0x0852) == 0xd5) {
-		/* This is for the 43p-140 */
-		early_read_config_dword(0, 0, PCI_DEVFN(13, 0),
-					PCI_BASE_ADDRESS_0, &addr);
-		if (addr != 0xffffffff
-		    && !(addr & PCI_BASE_ADDRESS_SPACE_IO)
-		    && (addr &= PCI_BASE_ADDRESS_MEM_MASK) != 0) {
-			addr += PREP_ISA_MEM_BASE;
-			OpenPIC_Addr = ioremap(addr, 0x40000);
-			ppc_md.get_irq = openpic_get_irq;
-		}
-	}
-
-#ifdef CONFIG_PREP_RESIDUAL
-	mpic = residual_find_device(-1, NULL, SystemPeripheral,
-				    ProgrammableInterruptController, MPIC, 0);
-	if (mpic != NULL)
-		printk("mpic = %p\n", mpic);
-#endif
-}
-
-static void __init
-ibm43p_pci_map_non0(struct pci_dev *dev)
-{
-	unsigned char intpin;
-	static unsigned char bridge_intrs[4] = { 3, 4, 5, 8 };
-
-	if (dev == NULL)
-		return;
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin);
-	if (intpin < 1 || intpin > 4)
-		return;
-	intpin = (PCI_SLOT(dev->devfn) + intpin - 1) & 3;
-	dev->irq = openpic_to_irq(bridge_intrs[intpin]);
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-}
-
-void __init
-prep_route_pci_interrupts(void)
-{
-	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
-	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
-	int i;
-	
-	if ( _prep_type == _PREP_Motorola)
-	{
-		unsigned short irq_mode;
-		unsigned char  cpu_type;
-		unsigned char  base_mod;
-		int	       entry;
-
-		cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
-		base_mod = inb(MOTOROLA_BASETYPE_REG);
-
-		for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
-			if (mot_info[entry].cpu_type & 0x200) {		 	/* Check for Hawk chip */
-				if (!(MotMPIC & MOT_HAWK_PRESENT))
-					continue;
-			} else {						/* Check non hawk boards */
-				if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
-					continue;
-
-				if (mot_info[entry].base_type == 0) {
-					mot_entry = entry;
-					break;
-				}
-
-				if (mot_info[entry].base_type != base_mod)
-					continue;
-			}
-
-			if (!(mot_info[entry].max_cpu & 0x80)) {
-				mot_entry = entry;
-				break;
-			}
-
-			/* processor 1 not present and max processor zero indicated */
-			if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
-				mot_entry = entry;
-				break;
-			}
-
-			/* processor 1 present and max processor zero indicated */
-			if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
-				mot_entry = entry;
-				break;
-			}
-		}
-
-		if (mot_entry == -1) 	/* No particular cpu type found - assume Blackhawk */
-			mot_entry = 3;
-
-		Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
-		Motherboard_map = mot_info[mot_entry].map;
-		Motherboard_routes = mot_info[mot_entry].routes;
-		Motherboard_non0 = mot_info[mot_entry].map_non0_bus;
-
-		if (!(mot_info[entry].cpu_type & 0x100)) {
-			/* AJF adjust level/edge control according to routes */
-			irq_mode = 0;
-			for (i = 1;  i <= 4;  i++)
-				irq_mode |= ( 1 << Motherboard_routes[i] );
-			outb( irq_mode & 0xff, 0x4d0 );
-			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
-		}
-	} else if ( _prep_type == _PREP_IBM ) {
-		unsigned char planar_id = inb(0x0852);
-		unsigned char irq_edge_mask_lo, irq_edge_mask_hi;
-
-		printk("IBM ID: %08x\n", planar_id);
-		switch(planar_id) {
-		case 0xff:
-			Motherboard_map_name = "IBM Thinkpad 850/860";
-			Motherboard_map = Nobis_pci_IRQ_map;
-			Motherboard_routes = Nobis_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		case 0xfc:
-			Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
-			Motherboard_map = ibm6015_pci_IRQ_map;
-			Motherboard_routes = ibm6015_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		case 0xd5:
-			Motherboard_map_name = "IBM 43P-140 (Tiger1)";
-			Motherboard_map = ibm43p_pci_IRQ_map;
-			Motherboard_routes = ibm43p_pci_IRQ_routes;
-			Motherboard_non0 = ibm43p_pci_map_non0;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		default:
-			printk(KERN_ERR "Unknown IBM motherboard! Defaulting to Carolina.\n");
-		case 0xf0: /* PowerSeries 830/850 */
-		case 0xf1: /* PowerSeries 830/850 */
-		case 0xf2: /* PowerSeries 830/850 */
-		case 0xf4: /* 7248-43P */
-		case 0xf5: /* 7248-43P */
-		case 0xf6: /* 7248-43P */
-		case 0xf7: /* 7248-43P (missing from Carolina Tech Spec) */
-			Motherboard_map_name = "IBM PS830/PS850/7248 (Carolina)";
-			Motherboard_map = ibm8xx_pci_IRQ_map;
-			Motherboard_routes = ibm8xx_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
-			break;
-		}
-
-		outb(inb(0x04d0)|irq_edge_mask_lo, 0x04d0); /* primary 8259 */
-		outb(inb(0x04d1)|irq_edge_mask_hi, 0x04d1); /* cascaded 8259 */
-	} else {
-		printk("No known machine pci routing!\n");
-		return;
-	}
-	
-	/* Set up mapping from slots */
-	for (i = 1;  i <= 4;  i++)
-		ibc_pirq[i-1] = Motherboard_routes[i];
-	/* Enable PCI interrupts */
-	*ibc_pcicon |= 0x20;
-}
-
-void __init
-prep_pib_init(void)
-{
-	unsigned char   reg;
-	unsigned short  short_reg;
-
-	struct pci_dev *dev = NULL;
-
-	if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) {
-		/*
-		 * Perform specific configuration for the Via Tech or
-		 * or Winbond PCI-ISA-Bridge part.
-		 */
-		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, 
-					PCI_DEVICE_ID_VIA_82C586_1, dev))) {
-			/*
-			 * PPCBUG does not set the enable bits
-			 * for the IDE device. Force them on here.
-			 */
-			pci_read_config_byte(dev, 0x40, &reg);
-
-			reg |= 0x03; /* IDE: Chip Enable Bits */
-			pci_write_config_byte(dev, 0x40, reg);
-		}
-		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
-						PCI_DEVICE_ID_VIA_82C586_2,
-						dev)) && (dev->devfn = 0x5a)) {
-			/* Force correct USB interrupt */
-			dev->irq = 11;
-			pci_write_config_byte(dev,
-					PCI_INTERRUPT_LINE,
-					dev->irq);
-		}
-		if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
-					PCI_DEVICE_ID_WINBOND_83C553, dev))) {
-			 /* Clear PCI Interrupt Routing Control Register. */
-			short_reg = 0x0000;
-			pci_write_config_word(dev, 0x44, short_reg);
-			if (OpenPIC_Addr){
-				/* Route IDE interrupts to IRQ 14 */
-				reg = 0xEE;
-				pci_write_config_byte(dev, 0x43, reg);
-			}
-		}
-	}
-
-	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
-				   PCI_DEVICE_ID_WINBOND_82C105, dev))){
-		if (OpenPIC_Addr){
-			/*
-			 * Disable LEGIRQ mode so PCI INTS are routed
-			 * directly to the 8259 and enable both channels
-			 */
-			pci_write_config_dword(dev, 0x40, 0x10ff0033);
-
-			/* Force correct IDE interrupt */
-			dev->irq = 14;
-			pci_write_config_byte(dev,
-					PCI_INTERRUPT_LINE,
-					dev->irq);
-		} else {
-			/* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
-			pci_write_config_dword(dev, 0x40, 0x10ff08a1);
-		}
-	}
-}
-
-static void __init
-Powerplus_Map_Non0(struct pci_dev *dev)
-{
-	struct pci_bus  *pbus;          /* Parent bus structure pointer */
-	struct pci_dev  *tdev = dev;    /* Temporary device structure */
-	unsigned int    devnum;         /* Accumulated device number */
-	unsigned char   intline;        /* Linux interrupt value */
-	unsigned char   intpin;         /* PCI interrupt pin */
-
-	/* Check for valid PCI dev pointer */
-	if (dev == NULL) return;
-
-	/* Initialize bridge IDSEL variable */
-	devnum = PCI_SLOT(tdev->devfn);
-
-	/* Read the interrupt pin of the device and adjust for indexing */
-	pcibios_read_config_byte(dev->bus->number, dev->devfn,
-			PCI_INTERRUPT_PIN, &intpin);
-
-	/* If device doesn't request an interrupt, return */
-	if ( (intpin < 1) || (intpin > 4) )
-		return;
-
-	intpin--;
-
-	/*
-	 * Walk up to bus 0, adjusting the interrupt pin for the standard
-	 * PCI bus swizzle.
-	 */
-	do {
-		intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
-		pbus = tdev->bus;        /* up one level */
-		tdev = pbus->self;
-		devnum = PCI_SLOT(tdev->devfn);
-	} while(tdev->bus->number);
-
-	/* Use the primary interrupt inputs by default */
-	intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
-
-	/*
-	 * If the board has secondary interrupt inputs, walk the bus and
-	 * note the devfn of the bridge from bus 0.  If it is the same as
-	 * the devfn of the bus bridge with secondary inputs, use those.
-	 * Otherwise, assume it's a PMC site and get the interrupt line
-	 * value from the interrupt routing table.
-	 */ 
-	if (mot_info[mot_entry].secondary_bridge_devfn) {
-		pbus = dev->bus;
-
-		while (pbus->primary != 0)
-			pbus = pbus->parent;
-
-		if ((pbus->self)->devfn != 0xA0) {
-			if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
-				intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
-			else {
-				if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map)
-					intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16;
-				else {
-					int i;
-					for (i=0;i<3;i++)
-						intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
-					intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
-				}
-			}
-		}
-	}
-
-	/* Write calculated interrupt value to header and device list */
-	dev->irq = intline;
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)dev->irq);
-}
-
-void __init
-prep_pcibios_fixup(void)
-{
-        struct pci_dev *dev;
-        extern unsigned char *Motherboard_map;
-        extern unsigned char *Motherboard_routes;
-        unsigned char i;
-
-	prep_route_pci_interrupts();
-
-	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
-	if (OpenPIC_Addr) {
-		/* PCI interrupts are controlled by the OpenPIC */
-		pci_for_each_dev(dev) {
-			if (dev->bus->number == 0) {
-                       		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
-				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq);
-			} else {
-				if (Motherboard_non0 != NULL)
-					Motherboard_non0(dev);
-			}
-		}
-
-		/* Setup the Winbond or Via PIB */
-		prep_pib_init();
-
-		return;
-	}
-
-	pci_for_each_dev(dev) {
-		/*
-		 * Use our old hard-coded kludge to figure out what
-		 * irq this device uses.  This is necessary on things
-		 * without residual data. -- Cort
-		 */
-		unsigned char d = PCI_SLOT(dev->devfn);
-		dev->irq = Motherboard_routes[Motherboard_map[d]];
-
-		for ( i = 0 ; i <= 5 ; i++ ) {
-			/*
-			 * Relocate PCI I/O resources if necessary so the
-			 * standard 256MB BAT covers them.
-			 */
-			if ( (pci_resource_flags(dev, i) & IORESOURCE_IO) &&
-				      (dev->resource[i].start > 0x10000000))  {
-				printk("Relocating PCI address %lx -> %lx\n",
-						dev->resource[i].start,
-						(dev->resource[i].start & 
-						 0x00FFFFFF)| 0x01000000);
-				dev->resource[i].start =
-					(dev->resource[i].start & 0x00FFFFFF)
-					| 0x01000000;
-		                pci_write_config_dword(dev,
-						PCI_BASE_ADDRESS_0 + (i*0x4),
-						dev->resource[i].start);
-				dev->resource[i].end = 
-					(dev->resource[i].end & 0x00FFFFFF)
-					| 0x01000000;
-		        }
-		}
-#if 0
-		/*
-		 * If we have residual data and if it knows about this
-		 * device ask it what the irq is.
-		 *  -- Cort
-		 */
-		ppcd = residual_find_device_id( ~0L, dev->device,
-		                                -1,-1,-1, 0);
-#endif
-	}
-}
-
-static void __init
-prep_pcibios_after_init(void)
-{
-	struct pci_dev *dev;
-	
-	/* If there is a WD 90C, reset the IO BAR to 0x0 (it started that 
-	 * way, but the PCI layer relocated it because it thought 0x0 was
-	 * invalid for a BAR).
-	 * If you don't do this, the card's VGA base will be <IO BAR>+0xc0000
-	 * instead of 0xc0000. vgacon.c (for example) is completely unaware of
-	 * this little quirk.
-	 */
-	dev = pci_find_device(PCI_VENDOR_ID_WD, PCI_DEVICE_ID_WD_90C, NULL);
-	if (dev) {
-		dev->resource[1].end -= dev->resource[1].start;
-		dev->resource[1].start = 0;
-		/* tell the hardware */
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0x0);
-	}
-}
-
-static void __init
-prep_init_resource(struct resource *res, unsigned long start,
-		   unsigned long end, int flags)
-{
-	res->flags = flags;
-	res->start = start;
-	res->end = end;
-	res->name = "PCI host bridge";
-	res->parent = NULL;
-	res->sibling = NULL;
-	res->child = NULL;
-}
-
-void __init
-prep_find_bridges(void)
-{
-	struct pci_controller* hose;
-
-	hose = pcibios_alloc_controller();
-	if (!hose)
-		return;
-
-	hose->first_busno = 0;
-	hose->last_busno = 0xff;
-	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
-	hose->io_base_phys = PREP_ISA_IO_BASE;
-	hose->io_base_virt = (void *)0x80000000; /* see prep_map_io() */
-	prep_init_resource(&hose->io_resource, 0, 0x0fffffff, IORESOURCE_IO);
-	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
-			   IORESOURCE_MEM);
-	
-	printk("PReP architecture\n");
-	{
-#ifdef CONFIG_PREP_RESIDUAL	  
-		PPC_DEVICE *hostbridge;
-
-		hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
-			BridgeController, PCIBridge, -1, 0);
-		if (hostbridge &&
-			hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
-			PnP_TAG_PACKET * pkt;
-			pkt = PnP_find_large_vendor_packet(
-				res->DevicePnPHeap+hostbridge->AllocatedOffset,
-				3, 0);
-			if(pkt) {
-#define p pkt->L4_Pack.L4_Data.L4_PPCPack
-				setup_indirect_pci(hose, 
-					ld_le32((unsigned *) (p.PPCData)),
-					ld_le32((unsigned *) (p.PPCData+8)));
-			} else
-				setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
-		} else
-#endif /* CONFIG_PREP_RESIDUAL */
-			hose->ops = &prep_pci_ops;
-	}
-
-	ppc_md.pcibios_fixup = prep_pcibios_fixup;
-	ppc_md.pcibios_after_init = prep_pcibios_after_init;
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/prep_setup.c linux-2.4.20-pre2/arch/ppc/kernel/prep_setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/prep_setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/prep_setup.c	Wed Dec 31 16:00:00 1969
@@ -1,906 +0,0 @@
-/*
- * BK Id: SCCS/s.prep_setup.c 1.52 04/05/02 10:17:22 trini
- */
-/*
- *  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)
- *
- * Support for PReP (Motorola MTX/MVME)
- * by Troy Benjegerdes (hozer@drgw.net)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/module.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/timex.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-
-#include <asm/sections.h>
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/cache.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-#include <asm/mk48t59.h>
-#include <asm/prep_nvram.h>
-#include <asm/raven.h>
-#include <asm/keyboard.h>
-#include <asm/vga.h>
-#include <asm/time.h>
-
-#include "local_irq.h"
-#include "i8259.h"
-#include "open_pic.h"
-
-#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
-#include <../drivers/sound/sound_config.h>
-#include <../drivers/sound/dev_table.h>
-#endif
-
-unsigned char ucSystemType;
-unsigned char ucBoardRev;
-unsigned char ucBoardRevMaj, ucBoardRevMin;
-
-extern unsigned long mc146818_get_rtc_time(void);
-extern int mc146818_set_rtc_time(unsigned long nowtime);
-extern unsigned long mk48t59_get_rtc_time(void);
-extern int mk48t59_set_rtc_time(unsigned long nowtime);
-
-extern unsigned char prep_nvram_read_val(int addr);
-extern void prep_nvram_write_val(int addr,
-				 unsigned char val);
-extern unsigned char rs_nvram_read_val(int addr);
-extern void rs_nvram_write_val(int addr,
-				 unsigned char val);
-extern void ibm_prep_init(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[];
-
-extern void prep_find_bridges(void);
-extern char saved_command_line[];
-
-int _prep_type;
-
-#define cached_21	(((char *)(ppc_cached_irq_mask))[3])
-#define cached_A1	(((char *)(ppc_cached_irq_mask))[2])
-
-/* for the mac fs */
-kdev_t boot_dev;
-/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
-long ppc_cs4232_dma, ppc_cs4232_dma2;
-
-extern PTE *Hash, *Hash_end;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
-extern unsigned long loops_per_jiffy;
-
-#ifdef CONFIG_SOUND_MODULE
-EXPORT_SYMBOL(ppc_cs4232_dma);
-EXPORT_SYMBOL(ppc_cs4232_dma2);
-#endif
-
-static int __prep
-prep_show_cpuinfo(struct seq_file *m)
-{
-	extern char *Motherboard_map_name;
-	int cachew;
-#ifdef CONFIG_PREP_RESIDUAL
-	int i;
-#endif
-
-	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
-
-	switch ( _prep_type ) {
-	case _PREP_IBM:
-		cachew = inw(0x80c);
-		if (cachew & (1<<6))
-			seq_printf(m, "Upgrade CPU\n");
-		seq_printf(m, "L2\t\t: ");
-		if (cachew & (1<<7)) {
-			seq_printf(m, "not present\n");
-			goto no_l2;
-		}
-		seq_printf(m, "%sKb,", (cachew & (1 << 10))? "512" : "256");
-		seq_printf(m, "%ssync\n", (cachew & (1 << 15))? "" : "a");
-		break;
-	case _PREP_Motorola:
-		cachew = *((unsigned char *)CACHECRBA);
-		seq_printf(m, "L2\t\t: ");
-		switch (cachew & L2CACHE_MASK) {
-		case L2CACHE_512KB:
-			seq_printf(m, "512Kb");
-			break;
-		case L2CACHE_256KB:
-			seq_printf(m, "256Kb");
-			break;
-		case L2CACHE_1MB:
-			seq_printf(m, "1MB");
-			break;
-		case L2CACHE_NONE:
-			seq_printf(m, "none\n");
-			goto no_l2;
-			break;
-		default:
-			seq_printf(m, "%x\n", cachew);
-		}
-		
-		seq_printf(m, ", parity %s",
-			   (cachew & L2CACHE_PARITY)? "enabled" : "disabled");
-
-		seq_printf(m, " SRAM:");
-		
-		switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
-		case 1: seq_printf(m, "synchronous,parity,flow-through\n");
-			break;
-		case 2: seq_printf(m, "asynchronous,no parity\n");
-			break;
-		case 3: seq_printf(m, "asynchronous,parity\n");
-			break;
-		default:seq_printf(m, "synchronous,pipelined,no parity\n");
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-
-no_l2:
-#ifdef CONFIG_PREP_RESIDUAL
-	if (res->ResidualLength != 0) {
-		/* print info about SIMMs */
-		seq_printf(m, "simms\t\t: ");
-		for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
-			if (res->Memories[i].SIMMSize != 0)
-				seq_printf(m, "%d:%ldM ", i,
-					(res->Memories[i].SIMMSize > 1024) ? 
-					res->Memories[i].SIMMSize>>20 : 
-					res->Memories[i].SIMMSize);
-		}
-		seq_printf(m, "\n");
-	}
-#endif
-
-	return 0;
-}
-
-static int __prep
-prep_show_percpuinfo(struct seq_file *m, int i)
-{
-	/* PREP's without residual data will give incorrect values here */
-	seq_printf(m, "clock\t\t: ");
-#ifdef CONFIG_PREP_RESIDUAL	
-	if (res->ResidualLength)
-		seq_printf(m, "%ldMHz\n",
-			   (res->VitalProductData.ProcessorHz > 1024) ?
-			   res->VitalProductData.ProcessorHz / 1000000 :
-			   res->VitalProductData.ProcessorHz);
-	else
-#endif /* CONFIG_PREP_RESIDUAL */
-		seq_printf(m, "???\n");
-
-	return 0;
-}
-
-static void __init
-prep_setup_arch(void)
-{
-	unsigned char reg;
-#if 0 /* unused?? */
-	unsigned char ucMothMemType;
-	unsigned char ucEquipPres1;
-#endif
-
-	/* init to some ~sane value until calibrate_delay() runs */
-	loops_per_jiffy = 50000000;
-	
-	/* Lookup PCI host bridges */
-	prep_find_bridges();
-	
-	/* Set up floppy in PS/2 mode */
-	outb(0x09, SIO_CONFIG_RA);
-	reg = inb(SIO_CONFIG_RD);
-	reg = (reg & 0x3F) | 0x40;
-	outb(reg, SIO_CONFIG_RD);
-	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
-
-	/* we should determine this according to what we find! -- Cort */
-	switch ( _prep_type )
-	{
-	case _PREP_IBM:
-		/* Enable L2.  Assume we don't need to flush -- Cort*/
-		*(unsigned char *)(0x8000081c) |= 3;
-		ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
-		break;
-	case _PREP_Motorola:
-		/* Enable L2.  Assume we don't need to flush -- Cort*/
-		*(unsigned char *)(0x8000081c) |= 3;
-#ifdef CONFIG_BLK_DEV_INITRD
-		if (initrd_start)
-			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */
-		else
-#endif
-#ifdef CONFIG_ROOT_NFS
-			ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs */
-#else
-			ROOT_DEV = to_kdev_t(0x0802); /* /dev/sda2 */
-#endif
-		break;
-	}
-
-	/* Read in NVRAM data */ 
-	init_prep_nvram();
-
-	/* if no bootargs, look in NVRAM */
-	if ( cmd_line[0] == '\0' ) {
-		char *bootargs;
-		 bootargs = prep_nvram_get_var("bootargs");
-		 if (bootargs != NULL) {
-			 strcpy(cmd_line, bootargs);
-			 /* again.. */
-			 strcpy(saved_command_line, cmd_line);
-		}
-	}
-
-#ifdef CONFIG_SOUND_CS4232
-	/*
-	 * setup proper values for the cs4232 driver so we don't have
-	 * to recompile for the motorola or ibm workstations sound systems.
-	 * This is a really nasty hack, but unless we change the driver
-	 * it's the only way to support both addrs from one binary.
-	 * -- Cort
-	 */
-	if ( _machine == _MACH_prep )
-	{
-		extern struct card_info snd_installed_cards[];
-		struct card_info *snd_ptr;
-
-		for ( snd_ptr = snd_installed_cards; 
-			snd_ptr < &snd_installed_cards[num_sound_cards];
-			snd_ptr++ )
-		{
-			if ( snd_ptr->card_type == SNDCARD_CS4232 )
-			{
-				if ( _prep_type == _PREP_Motorola )
-				{
-					snd_ptr->config.io_base = 0x830;
-					snd_ptr->config.irq = 10;
-					snd_ptr->config.dma = ppc_cs4232_dma = 6;
-					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
-				}
-				if ( _prep_type == _PREP_IBM )
-				{
-					snd_ptr->config.io_base = 0x530;
-					snd_ptr->config.irq = 5;
-					snd_ptr->config.dma = ppc_cs4232_dma = 1;
-					/* this is wrong - but leave it for now */
-					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
-				}
-			}
-		}
-	}
-#endif /* CONFIG_SOUND_CS4232 */	
-
-	/*print_residual_device_info();*/
-
-	switch (_prep_type) {
-	case _PREP_Motorola:
-		raven_init();
-		break;
-	case _PREP_IBM:
-		ibm_prep_init();
-		break;
-	}
-
-#ifdef CONFIG_VGA_CONSOLE
-	/* remap the VGA memory */
-	vgacon_remap_base = 0xf0000000;
-	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
-	conswitchp = &vga_con;
-#elif defined(CONFIG_DUMMY_CONSOLE)
-	conswitchp = &dummy_con;
-#endif
-}
-
-/*
- * Determine the decrementer frequency from the residual data
- * This allows for a faster boot as we do not need to calibrate the
- * decrementer against another clock. This is important for embedded systems.
- */
-static int __init
-prep_res_calibrate_decr(void)
-{
-#ifdef CONFIG_PREP_RESIDUAL
-	unsigned long freq, divisor = 4;
-
-	if ( res->VitalProductData.ProcessorBusHz ) {
-		freq = res->VitalProductData.ProcessorBusHz;
-		printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-				(freq/divisor)/1000000,
-				(freq/divisor)%1000000);
-		tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
-		tb_ticks_per_jiffy = freq / HZ / divisor;
-		return 0;
-	} else
-#endif	
-		return 1;
-}
-
-/*
- * Uses the on-board timer to calibrate the on-chip decrementer register
- * for prep systems.  On the pmac the OF tells us what the frequency is
- * but on prep we have to figure it out.
- * -- Cort
- */
-/* Done with 3 interrupts: the first one primes the cache and the
- * 2 following ones measure the interval. The precision of the method
- * is still doubtful due to the short interval sampled.
- */
-static volatile int calibrate_steps __initdata = 3;
-static unsigned tbstamp __initdata = 0;
-
-static void __init
-prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *regs)
-{
-	unsigned long t, freq;
-	int step=--calibrate_steps;
-
-	t = get_tbl();
-	if (step > 0) {
-		tbstamp = t;
-	} else {
-		freq = (t - tbstamp)*HZ;
-		printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-			 freq/1000000, freq%1000000);
-		tb_ticks_per_jiffy = freq / HZ;
-		tb_to_us = mulhwu_scale_factor(freq, 1000000);
-	}
-}
-
-static void __init
-prep_calibrate_decr(void)
-{
-	int res;
-
-	/* Try and get this from the residual data. */
-	res = prep_res_calibrate_decr();
-
-	/* If we didn't get it from the residual data, try this. */
-	if ( res ) {
-		unsigned long flags;
-
-		save_flags(flags);
-
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
-		/* set timer to periodic mode */
-		outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
-		/* set the clock to ~100 Hz */
-		outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
-		outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
-
-		if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
-			panic("Could not allocate timer IRQ!");
-		__sti();
-		/* wait for calibrate */
-		while ( calibrate_steps )
-			;
-		restore_flags(flags);
-		free_irq( 0, NULL);
-	}
-}
-
-static long __init
-mk48t59_init(void) {
-	unsigned char tmp;
-
-	tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
-	if (tmp & MK48T59_RTC_CB_STOP) {
-		printk("Warning: RTC was stopped, date will be wrong.\n");
-		ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB, 
-					 tmp & ~MK48T59_RTC_CB_STOP);
-		/* Low frequency crystal oscillators may take a very long
-		 * time to startup and stabilize. For now just ignore the
-		 * the issue, but attempting to calibrate the decrementer
-		 * from the RTC just after this wakeup is likely to be very 
-		 * inaccurate. Firmware should not allow to load
-		 * the OS with the clock stopped anyway...
-		 */
-	}
-	/* Ensure that the clock registers are updated */
-	tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
-	tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE);
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp);
-	return 0;
-}
-
-/* We use the NVRAM RTC to time a second to calibrate the decrementer,
- * the RTC registers have just been set up in the right state by the
- * preceding routine.
- */
-static void __init
-mk48t59_calibrate_decr(void)
-{
-	unsigned long freq;
-	unsigned long t1;
-	unsigned char save_control;
-	long i;
-	unsigned char sec;
- 
-		
-	/* Make sure the time is not stopped. */
-	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
-	
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
-			(save_control & (~MK48T59_RTC_CB_STOP)));
-
-	/* Now make sure the read bit is off so the value will change. */
-	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
-	save_control &= ~MK48T59_RTC_CA_READ;
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
-
-
-	/* Read the seconds value to see when it changes. */
-	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
-	/* Actually this is bad for precision, we should have a loop in
-	 * which we only read the seconds counter. nvram_read_val writes
-	 * the address bytes on every call and this takes a lot of time.
-	 * Perhaps an nvram_wait_change method returning a time
-	 * stamp with a loop count as parameter would be the  solution.
-	 */
-	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
-		t1 = get_tbl();
-		if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
-			break;
-		}
-	}
-
-	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
-	for (i = 0 ; i < 1000000 ; i++)	{ /* Should take up 1 second... */
-		freq = get_tbl()-t1;
-		if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec)
-			break;
-	}
-
-	printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-		 freq/1000000, freq%1000000);
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-}
-
-static void __prep
-prep_restart(char *cmd)
-{
-	unsigned long i = 10000;
-
-	__cli();
-
-	/* set exception prefix high - to the prom */
-	_nmask_and_or_msr(0, MSR_IP);
-
-	/* make sure bit 0 (reset) is a 0 */
-	outb( inb(0x92) & ~1L , 0x92 );
-	/* signal a reset to system control port A - soft reset */
-	outb( inb(0x92) | 1 , 0x92 );
-
-	while ( i != 0 ) i++;
-	panic("restart failed\n");
-}
-
-static void __prep
-prep_halt(void)
-{
-	unsigned long flags;
-	__cli();
-	/* set exception prefix high - to the prom */
-	save_flags( flags );
-	restore_flags( flags|MSR_IP );
-
-	/* make sure bit 0 (reset) is a 0 */
-	outb( inb(0x92) & ~1L , 0x92 );
-	/* signal a reset to system control port A - soft reset */
-	outb( inb(0x92) | 1 , 0x92 );
-
-	while ( 1 ) ;
-	/*
-	 * Not reached
-	 */
-}
-
-/*
- * On IBM PReP's, power management is handled by a Signetics 87c750 behind the
- * Utah component on the ISA bus. To access the 750 you must write a series of
- * nibbles to port 0x82a (decoded by the Utah). This is described somewhat in
- * the IBM Carolina Technical Specification.
- * -Hollis
- */
-static void __prep
-utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
-{
-	/*
-	 * byte1: 0 0 0 1 0  d  a5 a4
-	 * byte2: 0 0 0 1 a3 a2 a1 a0
-	 *
-	 * d = the bit's value, enabled or disabled
-	 * (a5 a4 a3) = the byte number, minus 20
-	 * (a2 a1 a0) = the bit number
-	 *
-	 * example: set the 5th bit of byte 21 (21.5)
-	 *     a5 a4 a3 = 001 (byte 1)
-	 *     a2 a1 a0 = 101 (bit 5)
-	 *
-	 *     byte1 = 0001 0100 (0x14)
-	 *     byte2 = 0001 1101 (0x1d)
-	 */
-	unsigned char byte1=0x10, byte2=0x10;
-	const unsigned int pm_reg_1=0x82a; /* ISA address */
-
-	/* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
-	bytenum -= 20;
-
-	byte1 |= (!!value) << 2;		/* set d */
-	byte1 |= (bytenum >> 1) & 0x3;	/* set a5, a4 */
-
-	byte2 |= (bytenum & 0x1) << 3;	/* set a3 */
-	byte2 |= bitnum & 0x7;			/* set a2, a1, a0 */
-
-	outb(byte1, pm_reg_1);		/* first nibble */
-	mb();
-	udelay(100);				/* important: let controller recover */
-
-	outb(byte2, pm_reg_1);		/* second nibble */
-	mb();
-	udelay(100);				/* important: let controller recover */
-}
-
-static void __prep
-prep_power_off(void)
-{
-	if ( _prep_type == _PREP_IBM) {
-		/* tested on:
-		 * 		Carolina's: 7248-43P, 6070 (PowerSeries 850)
-		 * should work on:
-		 * 		Carolina: 6050 (PowerSeries 830)
-		 * 		7043-140 (Tiger 1)
-		 */
-		unsigned long flags;
-		__cli();
-		/* set exception prefix high - to the prom */
-		save_flags( flags );
-		restore_flags( flags|MSR_IP );
-
-		utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
-
-		while ( 1 ) ;
-		/* not reached */
-	} else {
-		prep_halt();
-	}
-}
-
-static unsigned int __prep
-prep_irq_cannonicalize(u_int irq)
-{
-	if (irq == 2)
-	{
-		return 9;
-	}
-	else
-	{
-		return irq;
-	}
-}
-
-static int __prep
-prep_get_irq(struct pt_regs *regs)
-{
-	return i8259_irq();
-}		
-
-static void __init
-prep_init_IRQ(void)
-{
-	int i;
-
-	if (OpenPIC_Addr != NULL)
-		openpic_init(1, NUM_8259_INTERRUPTS, 0, -1);
-	for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
-		irq_desc[i].handler = &i8259_pic;
-	i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */
-}
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-static int __prep
-prep_ide_default_irq(ide_ioreg_t base)
-{
-	switch (base) {
-		case 0x1f0: return 13;
-		case 0x170: return 13;
-		case 0x1e8: return 11;
-		case 0x168: return 10;
-		case 0xfff0: return 14;		/* MCP(N)750 ide0 */
-		case 0xffe0: return 15;		/* MCP(N)750 ide1 */
-		default: return 0;
-	}
-}
-
-static ide_ioreg_t __prep
-prep_ide_default_io_base(int index)
-{
-	switch (index) {
-		case 0: return 0x1f0;
-		case 1: return 0x170;
-		case 2: return 0x1e8;
-		case 3: return 0x168;
-		default:
-			return 0;
-	}
-}
-
-static int __prep
-prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	return check_region(from, extent);
-}
-
-static void __prep
-prep_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-	request_region(from, extent, name);
-}
-
-static void __prep
-prep_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-	release_region(from, extent);
-}
-
-static void __init
-prep_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;
-}
-#endif
-
-#ifdef CONFIG_SMP
-/* PReP (MTX) support */
-static int __init
-smp_prep_probe(void)
-{
-	extern int mot_multi;
-
-	if (mot_multi) {
-		openpic_request_IPIs();
-		smp_hw_index[1] = 1;
-		return 2;
-	}
-
-	return 1;
-}
-
-static void __init
-smp_prep_kick_cpu(int nr)
-{
-	*(unsigned long *)KERNELBASE = nr;
-	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-	printk("CPU1 reset, waiting\n");
-}
-
-static void __init
-smp_prep_setup_cpu(int cpu_nr)
-{
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-}
-
-static struct smp_ops_t prep_smp_ops __prepdata = {
-	smp_openpic_message_pass,
-	smp_prep_probe,
-	smp_prep_kick_cpu,
-	smp_prep_setup_cpu,
-};
-#endif /* CONFIG_SMP */
-
-/*
- * This finds the amount of physical ram and does necessary
- * setup for prep.  This is pretty architecture specific so
- * this will likely stay separate from the pmac.
- * -- Cort
- */
-static unsigned long __init
-prep_find_end_of_memory(void)
-{
-	unsigned long total = 0;
-	extern unsigned int boot_mem_size;
-
-#ifdef CONFIG_PREP_RESIDUAL	
-	total = res->TotalMemory;
-#endif	
-
-	if (total == 0 && boot_mem_size != 0)
-		total = boot_mem_size;
-	else if (total == 0) {
-		/*
-		 * I need a way to probe the amount of memory if the residual
-		 * data doesn't contain it. -- Cort
-		 */
-		total = 0x02000000;
-		printk(KERN_INFO "Ramsize from residual data was 0"
-			 " -- defaulting to %ldM\n", total>>20);
-	}
-
-	return (total);
-}
-
-/*
- * Setup the bat mappings we're going to load that cover
- * the io areas.  RAM was mapped by mapin_ram().
- * -- Cort
- */
-static void __init
-prep_map_io(void)
-{
-	io_block_mapping(0x80000000, PREP_ISA_IO_BASE, 0x10000000, _PAGE_IO);
-	io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO);
-}
-
-static void __init
-prep_init2(void)
-{
-#ifdef CONFIG_NVRAM
-	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
-#endif
-	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
-prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
-		unsigned long r6, unsigned long r7)
-{
-#ifdef CONFIG_PREP_RESIDUAL	
-	/* make a copy of residual data */
-	if ( r3 ) {
-		memcpy((void *)res,(void *)(r3+KERNELBASE),
-			 sizeof(RESIDUAL));
-	}
-#endif
-
-	isa_io_base = PREP_ISA_IO_BASE;
-	isa_mem_base = PREP_ISA_MEM_BASE;
-	pci_dram_offset = PREP_PCI_DRAM_OFFSET;
-	ISA_DMA_THRESHOLD = 0x00ffffff;
-	DMA_MODE_READ = 0x44;
-	DMA_MODE_WRITE = 0x48;
-
-	/* figure out what kind of prep workstation we are */
-#ifdef CONFIG_PREP_RESIDUAL	
-	if ( res->ResidualLength != 0 )
-	{
-		if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
-			_prep_type = _PREP_IBM;
-		else
-			_prep_type = _PREP_Motorola;
-	}
-	else /* assume motorola if no residual (netboot?) */
-#endif
-	{
-		_prep_type = _PREP_Motorola;
-	}
-
-	ppc_md.setup_arch     = prep_setup_arch;
-	ppc_md.show_percpuinfo = prep_show_percpuinfo;
-	ppc_md.show_cpuinfo   = prep_show_cpuinfo;
-	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
-	ppc_md.init_IRQ       = prep_init_IRQ;
-	/* this gets changed later on if we have an OpenPIC -- Cort */
-	ppc_md.get_irq        = prep_get_irq;
-	ppc_md.init           = prep_init2;
-
-	ppc_md.restart        = prep_restart;
-	ppc_md.power_off      = prep_power_off;
-	ppc_md.halt           = prep_halt;
-
-	ppc_md.nvram_read_val = prep_nvram_read_val;
-	ppc_md.nvram_write_val = prep_nvram_write_val;
-
-	ppc_md.time_init      = NULL;
-	if (_prep_type == _PREP_IBM) {
-		ppc_md.set_rtc_time   = mc146818_set_rtc_time;
-		ppc_md.get_rtc_time   = mc146818_get_rtc_time;
-		ppc_md.calibrate_decr = prep_calibrate_decr;
-	} else {
-		ppc_md.set_rtc_time   = mk48t59_set_rtc_time;
-		ppc_md.get_rtc_time   = mk48t59_get_rtc_time;
-		ppc_md.calibrate_decr = mk48t59_calibrate_decr;
-		ppc_md.time_init      = mk48t59_init;
-	}
-
-	ppc_md.find_end_of_memory = prep_find_end_of_memory;
-	ppc_md.setup_io_mappings = prep_map_io;
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-	ppc_ide_md.default_irq = prep_ide_default_irq;
-	ppc_ide_md.default_io_base = prep_ide_default_io_base;
-	ppc_ide_md.ide_check_region = prep_ide_check_region;
-	ppc_ide_md.ide_request_region = prep_ide_request_region;
-	ppc_ide_md.ide_release_region = prep_ide_release_region;
-	ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
-#endif
-
-#ifdef CONFIG_VT
-	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-	ppc_md.kbd_translate     = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-	SYSRQ_KEY = 0x54;
-#endif
-#endif
-
-#ifdef CONFIG_SMP
-	ppc_md.smp_ops		 = &prep_smp_ops;
-#endif /* CONFIG_SMP */
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/prep_time.c linux-2.4.20-pre2/arch/ppc/kernel/prep_time.c
--- linux-2.4.20-pre1/arch/ppc/kernel/prep_time.c	Sat Sep  8 12:38:42 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/prep_time.c	Wed Dec 31 16:00:00 1969
@@ -1,228 +0,0 @@
-/*
- * BK Id: SCCS/s.prep_time.c 1.10 09/08/01 15:47:42 paulus
- */
-/*
- *  linux/arch/i386/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * Adapted for PowerPC (PreP) by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- *  copied and modified from intel version
- *
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/kernel_stat.h>
-#include <linux/init.h>
-
-#include <asm/sections.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/machdep.h>
-#include <asm/prep_nvram.h>
-#include <asm/mk48t59.h>
-
-#include <asm/time.h>
-
-extern spinlock_t rtc_lock;
-
-/*
- * The motorola uses the m48t18 rtc (includes DS1643) whose registers
- * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
- * rtc (ds1386) which has regs at addr 0-d).  The intel gets
- * past this because the bios emulates the mc146818.
- *
- * Why in the world did they have to use different clocks?
- *
- * Right now things are hacked to check which machine we're on then
- * use the appropriate macro.  This is very very ugly and I should
- * probably have a function that checks which machine we're on then
- * does things correctly transparently or a function pointer which
- * is setup at boot time to use the correct addresses.
- * -- Cort
- */
-
-/*
- * Set the hardware clock. -- Cort
- */
-__prep
-int mc146818_set_rtc_time(unsigned long nowtime)
-{
-	unsigned char save_control, save_freq_select;
-	struct rtc_time tm;
-
-	spin_lock(&rtc_lock);
-	to_tm(nowtime, &tm);
-
-	/* tell the clock it's being set */
-	save_control = CMOS_READ(RTC_CONTROL);
-	
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-	
-	/* stop and reset prescaler */
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
-	
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-	
-        tm.tm_year = (tm.tm_year - 1900) % 100;
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BIN_TO_BCD(tm.tm_sec);
-		BIN_TO_BCD(tm.tm_min);
-		BIN_TO_BCD(tm.tm_hour);
-		BIN_TO_BCD(tm.tm_mon);
-		BIN_TO_BCD(tm.tm_mday);
-		BIN_TO_BCD(tm.tm_year);
-	}
-	CMOS_WRITE(tm.tm_sec,  RTC_SECONDS);
-	CMOS_WRITE(tm.tm_min,  RTC_MINUTES);
-	CMOS_WRITE(tm.tm_hour, RTC_HOURS);
-	CMOS_WRITE(tm.tm_mon,  RTC_MONTH);
-	CMOS_WRITE(tm.tm_mday, RTC_DAY_OF_MONTH);
-	CMOS_WRITE(tm.tm_year, RTC_YEAR);
-	
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	CMOS_WRITE(save_control,     RTC_CONTROL);
-	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-	spin_unlock(&rtc_lock);
-
-	return 0;
-}
-
-__prep
-unsigned long mc146818_get_rtc_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	int uip, i;
-
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-
-	/* Since the UIP flag is set for about 2.2 ms and the clock
-	 * is typically written with a precision of 1 jiffy, trying
-	 * to obtain a precision better than a few milliseconds is 
-	 * an illusion. Only consistency is interesting, this also
-	 * allows to use the routine for /dev/rtc without a potential
-	 * 1 second kernel busy loop triggered by any reader of /dev/rtc. 
-	 */
-
-	for ( i = 0; i<1000000; i++) {
-		uip = CMOS_READ(RTC_FREQ_SELECT);
-		sec = CMOS_READ(RTC_SECONDS);
-		min = CMOS_READ(RTC_MINUTES);
-		hour = CMOS_READ(RTC_HOURS);
-		day = CMOS_READ(RTC_DAY_OF_MONTH);
-		mon = CMOS_READ(RTC_MONTH);
-		year = CMOS_READ(RTC_YEAR);
-		uip |= CMOS_READ(RTC_FREQ_SELECT);
-		if ((uip & RTC_UIP)==0) break;
-	}
-
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
-	    || RTC_ALWAYS_BCD)
-	{
-		BCD_TO_BIN(sec);
-		BCD_TO_BIN(min);
-		BCD_TO_BIN(hour);
-		BCD_TO_BIN(day);
-		BCD_TO_BIN(mon);
-		BCD_TO_BIN(year);
-	}
-	if ((year += 1900) < 1970)
-		year += 100;
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-__prep
-int mk48t59_set_rtc_time(unsigned long nowtime)
-{
-	unsigned char save_control;
-	struct rtc_time tm;
-
-	spin_lock(&rtc_lock);
-	to_tm(nowtime, &tm);
-
-	/* tell the clock it's being written */
-	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
-	
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
-			     (save_control | MK48T59_RTC_CA_WRITE));
-
-        tm.tm_year = (tm.tm_year - 1900) % 100;
-	BIN_TO_BCD(tm.tm_sec);
-	BIN_TO_BCD(tm.tm_min);
-	BIN_TO_BCD(tm.tm_hour);
-	BIN_TO_BCD(tm.tm_mon);
-	BIN_TO_BCD(tm.tm_mday);
-	BIN_TO_BCD(tm.tm_year);
-
-	ppc_md.nvram_write_val(MK48T59_RTC_SECONDS,      tm.tm_sec);
-	ppc_md.nvram_write_val(MK48T59_RTC_MINUTES,      tm.tm_min);
-	ppc_md.nvram_write_val(MK48T59_RTC_HOURS,        tm.tm_hour);
-	ppc_md.nvram_write_val(MK48T59_RTC_MONTH,        tm.tm_mon);
-	ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday);
-	ppc_md.nvram_write_val(MK48T59_RTC_YEAR,         tm.tm_year);
-	
-	/* Turn off the write bit. */
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
-	spin_unlock(&rtc_lock);
-
-	return 0;
-}
-
-__prep
-unsigned long mk48t59_get_rtc_time(void)
-{
-	unsigned char save_control;
-	unsigned int year, mon, day, hour, min, sec;
-
-	/* Simple: freeze the clock, read it and allow updates again */
-	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
-	save_control &= ~MK48T59_RTC_CA_READ;
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
-
-	/* Set the register to read the value. */
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
-			     (save_control | MK48T59_RTC_CA_READ));
-
-	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
-	min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES);
-	hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS);
-	day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH);
-	mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH);
-	year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR);
-
-	/* Let the time values change again. */
-	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
-
-	BCD_TO_BIN(sec);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(year);
-
-	year = year + 1900;
-	if (year < 1970) {
-		year += 100;
-	}
-
-	return mktime(year, mon, day, hour, min, sec);
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/proc_rtas.c linux-2.4.20-pre2/arch/ppc/kernel/proc_rtas.c
--- linux-2.4.20-pre1/arch/ppc/kernel/proc_rtas.c	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/proc_rtas.c	Wed Dec 31 16:00:00 1969
@@ -1,787 +0,0 @@
-/*
- * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort
- */
-/*
- *   arch/ppc/kernel/proc_rtas.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/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;
-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 = find_devices("rtas");
-	if ((rtas == 0) || (_machine != _MACH_chrp)) {
-		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 = call_rtas("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 = call_rtas("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 = call_rtas("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[MAX_LINELENGTH*MAX_SENSORS]; /* May not be enough */
-
-	if (count < 0)
-		return -EINVAL;
-
-	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 =	call_rtas("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;
-		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;
-	return n;
-}
-
-/* ****************************************************************** */
-
-int ppc_rtas_find_all_sensors (void)
-{
-	unsigned long *utmp;
-	int len, i, j;
-
-	utmp = (unsigned long *) get_property(rtas, "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, 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 = call_rtas("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 = call_rtas("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.20-pre1/arch/ppc/kernel/prom.c linux-2.4.20-pre2/arch/ppc/kernel/prom.c
--- linux-2.4.20-pre1/arch/ppc/kernel/prom.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/prom.c	Mon Aug 12 16:34:15 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prom.c 1.52 04/09/02 21:01:58 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Procedures for interfacing to the Open Firmware PROM on
@@ -26,6 +26,7 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/irq.h>
+#include <asm/open_pic.h>
 #include <asm/system.h>
 #include <asm/btext.h>
 #include <asm/pci-bridge.h>
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/ptrace.c linux-2.4.20-pre2/arch/ppc/kernel/ptrace.c
--- linux-2.4.20-pre1/arch/ppc/kernel/ptrace.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/ptrace.c	Mon Aug 12 16:34:15 2002
@@ -16,8 +16,7 @@
  * 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.
+ * Public License.  Please read the COPYING file for all license details.
  */
 
 #include <linux/kernel.h>
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/qspan_pci.c linux-2.4.20-pre2/arch/ppc/kernel/qspan_pci.c
--- linux-2.4.20-pre1/arch/ppc/kernel/qspan_pci.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/qspan_pci.c	Mon Aug 12 16:34:15 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.qspan_pci.c 1.5 05/17/01 18:14:22 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * QSpan pci routines.
@@ -29,8 +29,7 @@
 #include <asm/mpc8xx.h>
 #include <asm/system.h>
 #include <asm/machdep.h>
-
-#include "pci.h"
+#include <asm/pci-bridge.h>
 
 
 /*
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/residual.c linux-2.4.20-pre2/arch/ppc/kernel/residual.c
--- linux-2.4.20-pre1/arch/ppc/kernel/residual.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/residual.c	Wed Dec 31 16:00:00 1969
@@ -1,913 +0,0 @@
-/*
- * BK Id: SCCS/s.residual.c 1.15 02/05/02 18:08:35 trini
- */
-/*
- * Code to deal with the PReP residual data.
- *
- * Written by: Cort Dougan (cort@cs.nmt.edu)
- * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es)
- *
- *  This file is based on the following documentation:
- *
- *	IBM Power Personal Systems Architecture
- *	Residual Data
- * 	Document Number: PPS-AR-FW0001
- *
- *  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/string.h>
-#include <asm/residual.h>
-#include <asm/pnp.h>
-#include <asm/byteorder.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/pci.h>
-#include <linux/ide.h>
-
-#include <asm/sections.h>
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/ide.h>
-
-
-unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,};
-RESIDUAL *res = (RESIDUAL *)&__res;
-
-char * PnP_BASE_TYPES[] __initdata = {
-  "Reserved",
-  "MassStorageDevice",
-  "NetworkInterfaceController",
-  "DisplayController",
-  "MultimediaController",
-  "MemoryController",
-  "BridgeController",
-  "CommunicationsDevice",
-  "SystemPeripheral",
-  "InputDevice",
-  "ServiceProcessor"
-  };
-
-/* Device Sub Type Codes */
-
-unsigned char * PnP_SUB_TYPES[] __initdata = {
-  "\001\000SCSIController",
-  "\001\001IDEController",
-  "\001\002FloppyController",
-  "\001\003IPIController",
-  "\001\200OtherMassStorageController",
-  "\002\000EthernetController",
-  "\002\001TokenRingController",
-  "\002\002FDDIController",
-  "\002\0x80OtherNetworkController",
-  "\003\000VGAController",
-  "\003\001SVGAController",
-  "\003\002XGAController",
-  "\003\200OtherDisplayController",
-  "\004\000VideoController",
-  "\004\001AudioController",
-  "\004\200OtherMultimediaController",
-  "\005\000RAM",
-  "\005\001FLASH",
-  "\005\200OtherMemoryDevice",
-  "\006\000HostProcessorBridge",
-  "\006\001ISABridge",
-  "\006\002EISABridge",
-  "\006\003MicroChannelBridge",
-  "\006\004PCIBridge",
-  "\006\005PCMCIABridge",
-  "\006\006VMEBridge",
-  "\006\200OtherBridgeDevice",
-  "\007\000RS232Device",
-  "\007\001ATCompatibleParallelPort",
-  "\007\200OtherCommunicationsDevice",
-  "\010\000ProgrammableInterruptController",
-  "\010\001DMAController",
-  "\010\002SystemTimer",
-  "\010\003RealTimeClock",
-  "\010\004L2Cache",
-  "\010\005NVRAM",
-  "\010\006PowerManagement",
-  "\010\007CMOS",
-  "\010\010OperatorPanel",
-  "\010\011ServiceProcessorClass1",
-  "\010\012ServiceProcessorClass2",
-  "\010\013ServiceProcessorClass3",
-  "\010\014GraphicAssist",
-  "\010\017SystemPlanar",
-  "\010\200OtherSystemPeripheral",
-  "\011\000KeyboardController",
-  "\011\001Digitizer",
-  "\011\002MouseController",
-  "\011\003TabletController",
-  "\011\0x80OtherInputController",
-  "\012\000GeneralMemoryController",
-  NULL
-};
-
-/* Device Interface Type Codes */
-
-unsigned char * PnP_INTERFACES[] __initdata = {
-  "\000\000\000General",
-  "\001\000\000GeneralSCSI",
-  "\001\001\000GeneralIDE",
-  "\001\001\001ATACompatible",
-
-  "\001\002\000GeneralFloppy",
-  "\001\002\001Compatible765",
-  "\001\002\002NS398_Floppy",         /* NS Super I/O wired to use index
-                                         register at port 398 and data
-                                         register at port 399               */
-  "\001\002\003NS26E_Floppy",         /* Ports 26E and 26F                  */
-  "\001\002\004NS15C_Floppy",         /* Ports 15C and 15D                  */
-  "\001\002\005NS2E_Floppy",          /* Ports 2E and 2F                    */
-  "\001\002\006CHRP_Floppy",          /* CHRP Floppy in PR*P system         */
-
-  "\001\003\000GeneralIPI",
-  
-  "\002\000\000GeneralEther",
-  "\002\001\000GeneralToken",
-  "\002\002\000GeneralFDDI",
-  
-  "\003\000\000GeneralVGA",
-  "\003\001\000GeneralSVGA",
-  "\003\002\000GeneralXGA",
-  
-  "\004\000\000GeneralVideo",
-  "\004\001\000GeneralAudio",
-  "\004\001\001CS4232Audio",            /* CS 4232 Plug 'n Play Configured    */
-
-  "\005\000\000GeneralRAM",
-  /* This one is obviously wrong ! */
-  "\005\000\000PCIMemoryController",    /* PCI Config Method                  */
-  "\005\000\001RS6KMemoryController",   /* RS6K Config Method                 */
-  "\005\001\000GeneralFLASH",
-  
-  "\006\000\000GeneralHostBridge",
-  "\006\001\000GeneralISABridge",
-  "\006\002\000GeneralEISABridge",
-  "\006\003\000GeneralMCABridge",
-  /* GeneralPCIBridge = 0, */
-  "\006\004\000PCIBridgeDirect",
-  "\006\004\001PCIBridgeIndirect",
-  "\006\004\002PCIBridgeRS6K",
-  "\006\005\000GeneralPCMCIABridge",
-  "\006\006\000GeneralVMEBridge",
-  
-  "\007\000\000GeneralRS232",
-  "\007\000\001COMx",
-  "\007\000\002Compatible16450",
-  "\007\000\003Compatible16550",
-  "\007\000\004NS398SerPort",         /* NS Super I/O wired to use index
-                                         register at port 398 and data
-                                         register at port 399               */
-  "\007\000\005NS26ESerPort",         /* Ports 26E and 26F                  */
-  "\007\000\006NS15CSerPort",         /* Ports 15C and 15D                  */
-  "\007\000\007NS2ESerPort",          /* Ports 2E and 2F                    */
-
-  "\007\001\000GeneralParPort",
-  "\007\001\001LPTx",
-  "\007\001\002NS398ParPort",         /* NS Super I/O wired to use index
-                                         register at port 398 and data
-                                         register at port 399               */
-  "\007\001\003NS26EParPort",         /* Ports 26E and 26F                  */
-  "\007\001\004NS15CParPort",         /* Ports 15C and 15D                  */
-  "\007\001\005NS2EParPort",          /* Ports 2E and 2F                    */
-  
-  "\010\000\000GeneralPIC",
-  "\010\000\001ISA_PIC",
-  "\010\000\002EISA_PIC",
-  "\010\000\003MPIC",
-  "\010\000\004RS6K_PIC",
-
-  "\010\001\000GeneralDMA",
-  "\010\001\001ISA_DMA",
-  "\010\001\002EISA_DMA",
-
-  "\010\002\000GeneralTimer",
-  "\010\002\001ISA_Timer",
-  "\010\002\002EISA_Timer",
-  "\010\003\000GeneralRTC",
-  "\010\003\001ISA_RTC",
-  
-  "\010\004\001StoreThruOnly",
-  "\010\004\002StoreInEnabled",
-  "\010\004\003RS6KL2Cache",
-
-  "\010\005\000IndirectNVRAM",        /* Indirectly addressed               */
-  "\010\005\001DirectNVRAM",          /* Memory Mapped                      */
-  "\010\005\002IndirectNVRAM24",      /* Indirectly addressed - 24 bit      */
-
-  "\010\006\000GeneralPowerManagement",
-  "\010\006\001EPOWPowerManagement",
-  "\010\006\002PowerControl",         // d1378
-  
-  "\010\007\000GeneralCMOS",
-
-  "\010\010\000GeneralOPPanel",
-  "\010\010\001HarddiskLight",
-  "\010\010\002CDROMLight",
-  "\010\010\003PowerLight",
-  "\010\010\004KeyLock",
-  "\010\010\005ANDisplay",            /* AlphaNumeric Display               */
-  "\010\010\006SystemStatusLED",      /* 3 digit 7 segment LED              */
-  "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system           */
-
-  "\010\011\000GeneralServiceProcessor",
-  "\010\012\000GeneralServiceProcessor",
-  "\010\013\000GeneralServiceProcessor",
-  
-  "\010\014\001TransferData",
-  "\010\014\002IGMC32",
-  "\010\014\003IGMC64",
-  
-  "\010\017\000GeneralSystemPlanar",   /* 10/5/95                            */
-  NULL
-  };
-
-static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, 
-					     unsigned char SubType) {
-	unsigned char ** s=PnP_SUB_TYPES;
-	while (*s && !((*s)[0]==BaseType 
-		       && (*s)[1]==SubType)) s++;
-	if (*s) return *s+2;
-	else return("Unknown !");
-};
-
-static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, 
-					      unsigned char SubType,
-					      unsigned char Interface) {
-	unsigned char ** s=PnP_INTERFACES;
-	while (*s && !((*s)[0]==BaseType 
-		       && (*s)[1]==SubType 
-		       && (*s)[2]==Interface)) s++;
-	if (*s) return *s+3;
-	else return NULL;
-};
-
-static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) {
-	int i, c;
-	char decomp[4];
-#define p pkt->S14_Pack.S14_Data.S14_PPCPack
-	switch(p.Type) {
-	case 1:
-	  /* Decompress first 3 chars */
-	  c = *(unsigned short *)p.PPCData;
-	  decomp[0]='A'-1+((c>>10)&0x1F);
-	  decomp[1]='A'-1+((c>>5)&0x1F);
-	  decomp[2]='A'-1+(c&0x1F);
-	  decomp[3]=0;
-	  printk("    Chip identification: %s%4.4X\n",
-		 decomp, ld_le16((unsigned short *)(p.PPCData+2)));
-	  break;
-	default:
-	  printk("    Small vendor item type 0x%2.2x, data (hex): ",
-		 p.Type);
-	  for(i=0; i<size-2; i++) printk("%2.2x ", p.PPCData[i]);
-	  printk("\n");
-	  break;
-	}
-#undef p
-}
-
-static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) {
-	static const unsigned char * intlevel[] = {"high", "low"};
-	static const unsigned char * intsense[] = {"edge", "level"};
-
-	switch (tag_small_item_name(pkt->S1_Pack.Tag)) {
-	case PnPVersion:
-	  printk("    PnPversion 0x%x.%x\n", 
-		 pkt->S1_Pack.Version[0], /* How to interpret version ? */
-		 pkt->S1_Pack.Version[1]);
-	  break;
-//	case Logicaldevice:
-	  break;
-//	case CompatibleDevice:
-	  break;
-	case IRQFormat:
-#define p pkt->S4_Pack
-	  printk("    IRQ Mask 0x%4.4x, %s %s sensitive\n", 
-		 ld_le16((unsigned short *)p.IRQMask),
-		 intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0],
-		 intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]);
-#undef p
-	  break;
-	case DMAFormat:
-#define p pkt->S5_Pack
-	  printk("    DMA channel mask 0x%2.2x, info 0x%2.2x\n",
-		 p.DMAMask, p.DMAInfo);
-#undef p
-	  break;
-	case StartDepFunc:
-	  printk("Start dependent function:\n");
-	  break;
-	case EndDepFunc:
-	  printk("End dependent function\n");
-	  break;
-	case IOPort:
-#define p pkt->S8_Pack
-	  printk("    Variable (%d decoded bits) I/O port\n"
-		 "      from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n",
-		 p.IOInfo&ISAAddr16bit?16:10,
-		 ld_le16((unsigned short *)p.RangeMin),
- 		 ld_le16((unsigned short *)p.RangeMax),
-		 p.IOAlign, p.IONum); 
-#undef p
-	  break;
-	case FixedIOPort:
-#define p pkt->S9_Pack
-	  printk("    Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n",
-		 (p.Range[1]<<8)|p.Range[0],
-		 ((p.Range[1]<<8)|p.Range[0])+p.IONum-1);
-#undef p		 
-	  break;
-	case Res1:
-	case Res2:
-	case Res3:
-	  printk("    Undefined packet type %d!\n", 
-		 tag_small_item_name(pkt->S1_Pack.Tag));
-	  break;
-	case SmallVendorItem:
-	  printsmallvendor(pkt,size);
-	  break;
-	default:
-	  printk("    Type 0x2.2x%d, size=%d\n", 
-		 pkt->S1_Pack.Tag, size);    
-	  break;
-	}
-}
-
-static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) {
-	static const unsigned char * addrtype[] = {"I/O", "Memory", "System"};
-	static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"};
-	static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"};
-	static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"};
-	static const unsigned char * L2type[] = {"WriteThru", "CopyBack"};
-	static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"};
-
-	int i;
-	char tmpstr[30], *t;
-#define p pkt->L4_Pack.L4_Data.L4_PPCPack
-	switch(p.Type) {
-	case 2:
-	  printk("    %d K %s %s L2 cache, %d/%d bytes line/sector size\n",
-		 ld_le32((unsigned int *)p.PPCData),
-		 L2type[p.PPCData[10]-1],
-		 L2assoc[p.PPCData[4]-1],
-		 ld_le16((unsigned short *)p.PPCData+3),
-		 ld_le16((unsigned short *)p.PPCData+4));
-	  break;
-	case 3:
-	  printk("    PCI Bridge parameters\n"
-		 "      ConfigBaseAddress %0x\n"
-		 "      ConfigBaseData %0x\n"
-		 "      Bus number %d\n",
-		 ld_le32((unsigned int *)p.PPCData),
-		 ld_le32((unsigned int *)(p.PPCData+8)),
-		 p.PPCData[16]);
-	  for(i=20; i<size-4; i+=12) {
-	  	int j, first;
-	  	if(p.PPCData[i]) printk("      PCI Slot %d", p.PPCData[i]);
-		else printk ("      Integrated PCI device");
-		for(j=0, first=1, t=tmpstr; j<4; j++) {
-			int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
-			if(line!=0xffff){
-			        if(first) first=0; else *t++='/';
-				*t++='A'+j;
-			}
-		}
-		*t='\0';
-		printk(" DevFunc 0x%x interrupt line(s) %s routed to",
-		       p.PPCData[i+1],tmpstr);
-		sprintf(tmpstr,
-			inttype[p.PPCData[i+2]-1],
-			p.PPCData[i+3]);
-		printk(" %s line(s) ",
-		       tmpstr);
-		for(j=0, first=1, t=tmpstr; j<4; j++) {
-			int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
-			if(line!=0xffff){
-				if(first) first=0; else *t++='/';
-				t+=sprintf(t,"%d(%c)",
-					   line&0x7fff,
-					   line&0x8000?'E':'L');
-			}
-		}
-		printk("%s\n",tmpstr);
-	  }
-	  break;
-	case 5:
-	  printk("    Bridge address translation, %s decoding:\n"
-		 "      Processor  Bus        Size       Conversion Translation\n"
-		 "      0x%8.8x 0x%8.8x 0x%8.8x %s %s\n",
-		 p.PPCData[0]&1 ? "positive" : "subtractive",
-		 ld_le32((unsigned int *)p.PPCData+1),
-		 ld_le32((unsigned int *)p.PPCData+3),
-		 ld_le32((unsigned int *)p.PPCData+5),
-		 convtype[p.PPCData[2]-1],
-		 transtype[p.PPCData[1]-1]);
-	  break;
-	case 6:
-	  printk("    Bus speed %d Hz, %d slot(s)\n",
-		 ld_le32((unsigned int *)p.PPCData),
-		 p.PPCData[4]);
-	  break;
-	case 7:
-	  printk("    SCSI buses: %d, id(s):", p.PPCData[0]);
-	  for(i=1; i<=p.PPCData[0]; i++) 
-	    printk(" %d%c", p.PPCData[i], i==p.PPCData[0] ? '\n' : ',');
-	  break;
-	case 9:
-	  printk("    %s address (%d bits), at 0x%x size 0x%x bytes\n",
-		 addrtype[p.PPCData[0]-1],
-		 p.PPCData[1],
-		 ld_le32((unsigned int *)(p.PPCData+4)),
-		 ld_le32((unsigned int *)(p.PPCData+12)));
-	  break;
-	case 10:
-	  sprintf(tmpstr,
-		  inttype[p.PPCData[0]-1],
-		  p.PPCData[1]);
-
-	  printk("    ISA interrupts routed to %s\n"
-		 "      lines", 
-		 tmpstr);
-	  for(i=0; i<16; i++) {
-	  	int line=ld_le16((unsigned short *)p.PPCData+i+1);
-		if (line!=0xffff) printk(" %d(IRQ%d)", line, i); 
-	  }
-	  printk("\n");
-	  break;
-	default:
-	  printk("    Large vendor item type 0x%2.2x\n      Data (hex):",
-		 p.Type);
-	  for(i=0; i<size-4; i++) printk(" %2.2x", p.PPCData[i]);
-	  printk("\n");
-#undef p
-	}
-}
-
-static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) {
-	switch (tag_large_item_name(pkt->S1_Pack.Tag)) {
-	case LargeVendorItem:
-	  printlargevendor(pkt, size);
-	  break;
-	default:
-	  printk("    Type 0x2.2x%d, size=%d\n", 
-		 pkt->S1_Pack.Tag, size);    
-	  break;
-	}
-}
-static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) {
-	if (pkt->S1_Pack.Tag== END_TAG) {
-		printk("  No packets describing %s resources.\n", cat);
-		return;
-	}
-	printk(  "  Packets describing %s resources:\n",cat);
-	do {
-		int size;
-		if (tag_type(pkt->S1_Pack.Tag)) {
-		  	size= 3 +
-			  pkt->L1_Pack.Count0 + 
-			  pkt->L1_Pack.Count1*256;
-			printlargepacket(pkt, size);
-		} else {
-			size=tag_small_count(pkt->S1_Pack.Tag)+1;
-			printsmallpacket(pkt, size);
-		}
-		(unsigned char *) pkt+=size;
-	} while (pkt->S1_Pack.Tag != END_TAG);
-}
-
-void __init print_residual_device_info(void)
-{
-	int i;
-	PPC_DEVICE *dev;
-#define did dev->DeviceId
-	
-	/* make sure we have residual data first */
-	if ( res->ResidualLength == 0 )
-		return;
-	
-	printk("Residual: %ld devices\n", res->ActualNumDevices);
-	for ( i = 0;
-	      i < res->ActualNumDevices ;
-	      i++)
-	{
-	  	char decomp[4], sn[20];
-		const char * s;
-		dev = &res->Devices[i];
-		s = PnP_INTERFACE_STR(did.BaseType, did.SubType, 
-				      did.Interface);
-		if(!s) {
-			sprintf(sn, "interface %d", did.Interface);
-			s=sn;
-		}
-		if ( did.BusId & PCIDEVICE ) 
-		  printk("PCI Device, Bus %d, DevFunc 0x%x:",
-			 dev->BusAccess.PCIAccess.BusNumber,
-			 dev->BusAccess.PCIAccess.DevFuncNumber);
-	       	if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:");
-		if ( did.BusId & ISADEVICE ) 
-		  printk("ISA Device, Slot %d, LogicalDev %d:",
-			 dev->BusAccess.ISAAccess.SlotNumber,
-			 dev->BusAccess.ISAAccess.LogicalDevNumber);
-		if ( did.BusId & EISADEVICE ) printk("EISA Device:");
-		if ( did.BusId & PROCESSORDEVICE ) 
-		  printk("ProcBus Device, Bus %d, BUID %d: ",
-			 dev->BusAccess.ProcBusAccess.BusNumber,
-			 dev->BusAccess.ProcBusAccess.BUID);
-		if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA ");
-		if ( did.BusId & VMEDEVICE ) printk("VME ");
-		if ( did.BusId & MCADEVICE ) printk("MCA ");
-		if ( did.BusId & MXDEVICE ) printk("MX ");
-		/* Decompress first 3 chars */
-		decomp[0]='A'-1+((did.DevId>>26)&0x1F);
-		decomp[1]='A'-1+((did.DevId>>21)&0x1F);
-		decomp[2]='A'-1+((did.DevId>>16)&0x1F);
-		decomp[3]=0;
-		printk(" %s%4.4lX, %s, %s, %s\n", 
-		       decomp, did.DevId&0xffff,
-		       PnP_BASE_TYPES[did.BaseType],
-		       PnP_SUB_TYPE_STR(did.BaseType,did.SubType),
-		       s);
-		if ( dev->AllocatedOffset )
-			printpackets( (union _PnP_TAG_PACKET *)
-				      &res->DevicePnPHeap[dev->AllocatedOffset],
-				      "allocated");
-		if ( dev->PossibleOffset )
-			printpackets( (union _PnP_TAG_PACKET *)
-				      &res->DevicePnPHeap[dev->PossibleOffset],
-				      "possible");
-		if ( dev->CompatibleOffset )
-			printpackets( (union _PnP_TAG_PACKET *)
-				      &res->DevicePnPHeap[dev->CompatibleOffset],
-				      "compatible");
-	}
-}
-
-
-#if 0
-static void __init printVPD(void) {
-#define vpd res->VitalProductData
-	int ps=vpd.PageSize, i, j;
-	static const char* Usage[]={
-	  "FirmwareStack",  "FirmwareHeap",  "FirmwareCode", "BootImage",
-	  "Free", "Unpopulated", "ISAAddr", "PCIConfig",
-	  "IOMemory", "SystemIO", "SystemRegs", "PCIAddr", 
-	  "UnPopSystemRom", "SystemROM", "ResumeBlock", "Other" 
-	};
-	static const unsigned char *FWMan[]={
-	  "IBM", "Motorola", "FirmWorks", "Bull"
-	};
-	static const unsigned char *FWFlags[]={
-	  "Conventional", "OpenFirmware", "Diagnostics", "LowDebug",
-	  "MultiBoot", "LowClient", "Hex41", "FAT", 
-	  "ISO9660", "SCSI_ID_Override", "Tape_Boot", "FW_Boot_Path"
-	};
-	static const unsigned char *ESM[]={
-	  "Port92", "PCIConfigA8", "FF001030", "????????"
-	};
-	static const unsigned char *SIOM[]={
-	  "Port850", "????????", "PCIConfigA8", "????????"
-	};
-
-	printk("Model: %s\n",vpd.PrintableModel);
-	printk("Serial: %s\n", vpd.Serial);
-	printk("FirmwareSupplier: %s\n", FWMan[vpd.FirmwareSupplier]);
-	printk("FirmwareFlags:");
-	for(j=0; j<12; j++) {
-	  	if (vpd.FirmwareSupports & (1<<j)) {
-			printk(" %s%c", FWFlags[j], 
-			       vpd.FirmwareSupports&(-2<<j) ? ',' : '\n');
-		}
-	}
-	printk("NVRamSize: %ld\n", vpd.NvramSize);
-	printk("SIMMslots: %ld\n", vpd.NumSIMMSlots);
-	printk("EndianSwitchMethod: %s\n", 
-	       ESM[vpd.EndianSwitchMethod>2 ? 2 : vpd.EndianSwitchMethod]);
-	printk("SpreadIOMethod: %s\n", 
-	       SIOM[vpd.SpreadIOMethod>3 ? 3 : vpd.SpreadIOMethod]);
-	printk("Processor/Bus frequencies (Hz): %ld/%ld\n",
-	       vpd.ProcessorHz, vpd.ProcessorBusHz);
-	printk("Time Base Divisor: %ld\n", vpd.TimeBaseDivisor);
-	printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps);
-	printk("Cache sector size, Lock granularity: %ld, %ld\n",
-	       vpd.CoherenceBlockSize, vpd.GranuleSize);
-	for (i=0; i<res->ActualNumMemSegs; i++) {
-		int mask=res->Segs[i].Usage, first, j;
-		printk("%8.8lx-%8.8lx ", 
-		       res->Segs[i].BasePage*ps,
-		       (res->Segs[i].PageCount+res->Segs[i].BasePage)*ps-1);
-		for(j=15, first=1; j>=0; j--) {
-			if (mask&(1<<j)) {
-				if (first) first=0;
-				else printk(", ");
-				printk("%s", Usage[j]);
-			}
-		}
-		printk("\n");
-	}
-}
-
-/*
- * Spit out some info about residual data
- */
-void print_residual_device_info(void)
-{
-	int i;
-	union _PnP_TAG_PACKET *pkt;
-	PPC_DEVICE *dev;
-#define did dev->DeviceId
-	
-	/* make sure we have residual data first */
-	if ( res->ResidualLength == 0 )
-		return;
-	printk("Residual: %ld devices\n", res->ActualNumDevices);
-	for ( i = 0;
-	      i < res->ActualNumDevices ;
-	      i++)
-	{
-		dev = &res->Devices[i];
-		/*
-		 * pci devices
-		 */
-		if ( did.BusId & PCIDEVICE )
-		{
-			printk("PCI Device:");
-			/* unknown vendor */
-			if ( !strncmp( "Unknown", pci_strvendor(did.DevId>>16), 7) )
-				printk(" id %08lx types %d/%d", did.DevId,
-				       did.BaseType, did.SubType);
-			/* known vendor */
-			else
-				printk(" %s %s",
-				       pci_strvendor(did.DevId>>16),
-				       pci_strdev(did.DevId>>16,
-						  did.DevId&0xffff)
-					);
-			
-			if ( did.BusId & PNPISADEVICE )
-			{
-				printk(" pnp:");
-				/* get pnp info on the device */
-				pkt = (union _PnP_TAG_PACKET *)
-					&res->DevicePnPHeap[dev->AllocatedOffset];
-				for (; pkt->S1_Pack.Tag != DF_END_TAG;
-				     pkt++ )
-				{
-					if ( (pkt->S1_Pack.Tag == S4_Packet) ||
-					     (pkt->S1_Pack.Tag == S4_Packet_flags) )
-						printk(" irq %02x%02x",
-						       pkt->S4_Pack.IRQMask[0],
-						       pkt->S4_Pack.IRQMask[1]);
-				}
-			}
-			printk("\n");
-			continue;
-		}
-		/*
-		 * isa devices
-		 */
-		if ( did.BusId & ISADEVICE )
-		{
-			printk("ISA Device: basetype: %d subtype: %d",
-			       did.BaseType, did.SubType);
-			printk("\n");
-			continue;
-		}		
-		/*
-		 * eisa devices
-		 */
-		if ( did.BusId & EISADEVICE )
-		{
-			printk("EISA Device: basetype: %d subtype: %d",
-			       did.BaseType, did.SubType);
-			printk("\n");
-			continue;
-		}		
-		/*
-		 * proc bus devices
-		 */
-		if ( did.BusId & PROCESSORDEVICE )
-		{
-			printk("ProcBus Device: basetype: %d subtype: %d",
-			       did.BaseType, did.SubType);
-			printk("\n");
-			continue;
-		}
-		/*
-		 * pcmcia devices
-		 */
-		if ( did.BusId & PCMCIADEVICE )
-		{
-			printk("PCMCIA Device: basetype: %d subtype: %d",
-			       did.BaseType, did.SubType);
-			printk("\n");
-			continue;
-		}		
-		printk("Unknown bus access device: busid %lx\n",
-		       did.BusId);
-	}
-}
-#endif	
-
-/* Returns the device index in the residual data, 
-   any of the search items may be set as -1 for wildcard,
-   DevID number field (second halfword) is big endian ! 
-
-   Examples:
-   - search for the Interrupt controller (8259 type), 2 methods:
-     1) i8259 = residual_find_device(~0, 
-                                     NULL, 
-				     SystemPeripheral, 
-				     ProgrammableInterruptController, 
-				     ISA_PIC, 
-				     0);
-     2) i8259 = residual_find_device(~0, "PNP0000", -1, -1, -1, 0) 
-
-   - search for the first two serial devices, whatever their type)
-     iserial1 = residual_find_device(~0,NULL,
-                                     CommunicationsDevice,
-				     RS232Device,
-				     -1, 0)
-     iserial2 = residual_find_device(~0,NULL,
-                                     CommunicationsDevice,
-				     RS232Device,
-				     -1, 1)
-   - but search for typical COM1 and COM2 is not easy due to the
-     fact that the interface may be anything and the name "PNP0500" or 
-     "PNP0501". Quite bad. 
-
-*/
-
-/* devid are easier to uncompress than to compress, so to minimize bloat
-in this rarely used area we unencode and compare */
-
-/* in residual data number is big endian in the device table and
-little endian in the heap, so we use two parameters to avoid writing
-two very similar functions */
-
-static int __init same_DevID(unsigned short vendor,
-	       unsigned short Number,
-	       char * str) 
-{
-	static unsigned const char hexdigit[]="0123456789ABCDEF";
-	if (strlen(str)!=7) return 0;
-	if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&
-	     ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&
-	     ( (vendor&0x1f)+'A'-1 == str[2])        &&
-	     (hexdigit[(Number>>12)&0x0f] == str[3]) &&
-	     (hexdigit[(Number>>8)&0x0f] == str[4])  &&
-	     (hexdigit[(Number>>4)&0x0f] == str[5])  &&
-	     (hexdigit[Number&0x0f] == str[6]) ) return 1;
-	return 0;
-}
-
-PPC_DEVICE __init *residual_find_device(unsigned long BusMask,
-			 unsigned char * DevID,
-			 int BaseType,
-			 int SubType,
-			 int Interface,
-			 int n)
-{
-	int i;
-	if ( !res->ResidualLength ) return NULL;
-	for (i=0; i<res->ActualNumDevices; i++) {
-#define Dev res->Devices[i].DeviceId
-		if ( (Dev.BusId&BusMask)                                  &&
-		     (BaseType==-1 || Dev.BaseType==BaseType)             &&
-		     (SubType==-1 || Dev.SubType==SubType)                &&
-		     (Interface==-1 || Dev.Interface==Interface)          &&
-		     (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
-						Dev.DevId&0xffff, DevID)) &&
-		     !(n--) ) return res->Devices+i;
-#undef Dev
-	}
-	return 0;
-}
-
-PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask,
-			 unsigned short DevID,
-			 int BaseType,
-			 int SubType,
-			 int Interface,
-			 int n)
-{
-	int i;
-	if ( !res->ResidualLength ) return NULL;
-	for (i=0; i<res->ActualNumDevices; i++) {
-#define Dev res->Devices[i].DeviceId
-		if ( (Dev.BusId&BusMask)                                  &&
-		     (BaseType==-1 || Dev.BaseType==BaseType)             &&
-		     (SubType==-1 || Dev.SubType==SubType)                &&
-		     (Interface==-1 || Dev.Interface==Interface)          &&
-		     (DevID==0xffff || (Dev.DevId&0xffff) == DevID)	  &&
-		     !(n--) ) return res->Devices+i;
-#undef Dev
-	}
-	return 0;
-}
-
-PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
-				unsigned packet_tag,
-				int n)
-{
-	unsigned mask, masked_tag, size;
-	if(!p) return 0;
-	if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
-	masked_tag = packet_tag&mask;
-	for(; *p != END_TAG; p+=size) {
-		if ((*p & mask) == masked_tag && !(n--)) 
-			return (PnP_TAG_PACKET *) p;
-		if (tag_type(*p))
-			size=ld_le16((unsigned short *)(p+1))+3;
-		else 
-			size=tag_small_count(*p)+1;
-	}
-	return 0; /* not found */
-}
-
-PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p,
-					     unsigned packet_type,
-					     int n)
-{
-	int next=0;
-	while (p) {
-		p = (unsigned char *) PnP_find_packet(p, 0x70, next);
-		if (p && p[1]==packet_type && !(n--)) 
-			return (PnP_TAG_PACKET *) p;
-		next = 1;
-	};
-	return 0; /* not found */
-}
-
-PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p,
-					   unsigned packet_type,
-					   int n)
-{
-	int next=0;
-	while (p) {
-		p = (unsigned char *) PnP_find_packet(p, 0x84, next);
-		if (p && p[3]==packet_type && !(n--)) 
-			return (PnP_TAG_PACKET *) p;
-		next = 1;
-	};
-	return 0; /* not found */
-}
-
-#ifdef CONFIG_PROC_PREPRESIDUAL
-static int proc_prep_residual_read(char * buf, char ** start, off_t off,
-		int count, int *eof, void *data)
-{
-	int n;
-
-	n = res->ResidualLength - off;
-	if (n < 0) {
-		*eof = 1;
-		n = 0;
-	}
-	else {
-		if (n > count)
-			n = count;
-		else
-			*eof = 1;
-
-		memcpy(buf, (char *)res + off, n);
-		*start = buf;
-	}
-
-	return n;
-}
-
-void __init
-proc_prep_residual_init(void)
-{
-	if (res->ResidualLength)
-		create_proc_read_entry("residual", S_IRUGO, NULL,
-					proc_prep_residual_read, NULL);
-}
-
-__initcall(proc_prep_residual_init);
-#endif
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/setup.c linux-2.4.20-pre2/arch/ppc/kernel/setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/setup.c	Mon Aug 12 16:34:15 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.setup.c 1.75 04/16/02 20:08:22 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * Common prep/pmac/chrp boot and setup code.
@@ -29,17 +29,6 @@
 #include <asm/smp.h>
 #include <asm/elf.h>
 #include <asm/cputable.h>
-#ifdef CONFIG_8xx
-#include <asm/mpc8xx.h>
-#include <asm/8xx_immap.h>
-#endif
-#ifdef CONFIG_8260
-#include <asm/mpc8260.h>
-#include <asm/immap_8260.h>
-#endif
-#ifdef CONFIG_4xx
-#include <asm/ppc4xx.h>
-#endif
 #include <asm/bootx.h>
 #include <asm/btext.h>
 #include <asm/machdep.h>
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/sleep.S linux-2.4.20-pre2/arch/ppc/kernel/sleep.S
--- linux-2.4.20-pre1/arch/ppc/kernel/sleep.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/sleep.S	Wed Dec 31 16:00:00 1969
@@ -1,451 +0,0 @@
-/*
- * BK Id: SCCS/s.sleep.S 1.20 03/19/02 15:04:39 benh
- */
-/*
- * This file contains sleep low-level functions for PowerBook G3.
- *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
- *    and 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.
- *
- */
-
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/cputable.h>
-#include "ppc_asm.h"
-
-#define MAGIC	0x4c617273	/* 'Lars' */
-
-/*
- * Structure for storing CPU registers on the stack.
- */
-#define SL_SP		0
-#define SL_PC		4
-#define SL_MSR		8
-#define SL_SDR1		0xc
-#define SL_SPRG0	0x10	/* 4 sprg's */
-#define SL_DBAT0	0x20
-#define SL_IBAT0	0x28
-#define SL_DBAT1	0x30
-#define SL_IBAT1	0x38
-#define SL_DBAT2	0x40
-#define SL_IBAT2	0x48
-#define SL_DBAT3	0x50
-#define SL_IBAT3	0x58
-#define SL_TB		0x60
-#define SL_HID0		0x68
-#define SL_HID1		0x6c
-#define SL_MSSCR0	0x70
-#define SL_MSSSR0	0x74
-#define SL_ICTRL	0x78
-#define SL_LDSTCR	0x7c
-#define SL_LDSTDB	0x80
-#define SL_R2		0x84
-#define SL_CR		0x88
-#define SL_R12		0x8c	/* r12 to r31 */
-#define SL_SIZE		(SL_R12 + 80)
-
-	.text
-	.align	5
-
-/* This gets called by via-pmu.c late during the sleep process.
- * The PMU was already send the sleep command and will shut us down
- * soon. We need to save all that is needed and setup the wakeup
- * vector that will be called by the ROM on wakeup
- */
-_GLOBAL(low_sleep_handler)
-	mflr	r0
-	stw	r0,4(r1)
-	stwu	r1,-SL_SIZE(r1)
-	mfcr	r0
-	stw	r0,SL_CR(r1)
-	stw	r2,SL_R2(r1)
-	stmw	r12,SL_R12(r1)
-
-	/* Save MSR & SDR1 */
-	mfmsr	r4
-	stw	r4,SL_MSR(r1)
-	mfsdr1	r4
-	stw	r4,SL_SDR1(r1)
-
-	/* Get a stable timebase and save it */
-1:	mftbu	r4
-	stw	r4,SL_TB(r1)
-	mftb	r5
-	stw	r5,SL_TB+4(r1)
-	mftbu	r3
-	cmpw	r3,r4
-	bne	1b
-	
-	/* Save SPRGs */
-	mfsprg	r4,0
-	stw	r4,SL_SPRG0(r1)
-	mfsprg	r4,1
-	stw	r4,SL_SPRG0+4(r1)
-	mfsprg	r4,2
-	stw	r4,SL_SPRG0+8(r1)
-	mfsprg	r4,3
-	stw	r4,SL_SPRG0+12(r1)
-
-	/* Save BATs */
-	mfdbatu	r4,0
-	stw	r4,SL_DBAT0(r1)
-	mfdbatl	r4,0
-	stw	r4,SL_DBAT0+4(r1)
-	mfdbatu	r4,1
-	stw	r4,SL_DBAT1(r1)
-	mfdbatl	r4,1
-	stw	r4,SL_DBAT1+4(r1)
-	mfdbatu	r4,2
-	stw	r4,SL_DBAT2(r1)
-	mfdbatl	r4,2
-	stw	r4,SL_DBAT2+4(r1)
-	mfdbatu	r4,3
-	stw	r4,SL_DBAT3(r1)
-	mfdbatl	r4,3
-	stw	r4,SL_DBAT3+4(r1)
-	mfibatu	r4,0
-	stw	r4,SL_IBAT0(r1)
-	mfibatl	r4,0
-	stw	r4,SL_IBAT0+4(r1)
-	mfibatu	r4,1
-	stw	r4,SL_IBAT1(r1)
-	mfibatl	r4,1
-	stw	r4,SL_IBAT1+4(r1)
-	mfibatu	r4,2
-	stw	r4,SL_IBAT2(r1)
-	mfibatl	r4,2
-	stw	r4,SL_IBAT2+4(r1)
-	mfibatu	r4,3
-	stw	r4,SL_IBAT3(r1)
-	mfibatl	r4,3
-	stw	r4,SL_IBAT3+4(r1)
-
-	/* Save HID0 */
-	mfspr	r4,HID0
-	stw	r4,SL_HID0(r1)
-
-	/* Save 7400/7410/7450 specific registers */
-	mfspr	r3,PVR
-	srwi	r3,r3,16
-	cmpli	cr0,r3,0x8000
-	cmpli	cr1,r3,0x000c
-	cmpli	cr2,r3,0x800c
-	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
-	bne	1f
-	mfspr	r4,SPRN_MSSCR0
-	stw	r4,SL_MSSCR0(r1)
-	mfspr	r4,SPRN_MSSSR0
-	stw	r4,SL_MSSSR0(r1)
-	/* Save 7450 specific registers */
-	beq	cr1,1f
-	mfspr	r4,HID1
-	stw	r4,SL_HID1(r1)
-	mfspr	r4,SPRN_ICTRL
-	stw	r4,SL_ICTRL(r1)
-	mfspr	r4,SPRN_LDSTCR
-	stw	r4,SL_LDSTCR(r1)
-	mfspr	r4,SPRN_LDSTDB
-	stw	r4,SL_LDSTDB(r1)
-1:
-	/* The ROM can wake us up via 2 different vectors:
-	 *  - On wallstreet & lombard, we must write a magic
-	 *    value 'Lars' at address 4 and a pointer to a
-	 *    memory location containing the PC to resume from
-	 *    at address 0.
-	 *  - On Core99, we must store the wakeup vector at
-	 *    address 0x80 and eventually it's parameters
-	 *    at address 0x84. I've have some trouble with those
-	 *    parameters however and I no longer use them.
-	 */
-	lis	r5,grackle_wake_up@ha
-	addi	r5,r5,grackle_wake_up@l
-	tophys(r5,r5)
-	stw	r5,SL_PC(r1)
-	lis	r4,KERNELBASE@h
-	tophys(r5,r1)
-	addi	r5,r5,SL_PC
-	lis	r6,MAGIC@ha
-	addi	r6,r6,MAGIC@l
-	stw	r5,0(r4)
-	stw	r6,4(r4)
-	/* Setup stuffs at 0x80-0x84 for Core99 */
-	lis	r3,core99_wake_up@ha
-	addi	r3,r3,core99_wake_up@l
-	tophys(r3,r3)
-	stw	r3,0x80(r4)
-	stw	r5,0x84(r4)
-	/* Store a pointer to our backup storage into
-	 * a kernel global
-	 */
-	lis r3,sleep_storage@ha
-	addi r3,r3,sleep_storage@l
-	stw r5,0(r3)
-
-	BEGIN_FTR_SECTION
-	DSSALL
-	sync
-	END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-
-/*
- * Flush the L1 data cache by reading the first 128kB of RAM
- * and then flushing the same area with the dcbf instruction.
- * The L2 cache has already been disabled.
- */
-	li	r4,0x1000	/* 128kB / 32B */
-	mtctr	r4
-	lis	r4,KERNELBASE@h
-1:
-	lwz	r0,0(r4)
-	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	1b
-	sync
-	
-	li	r4,0x1000	/* 128kB / 32B */
-	mtctr	r4
-	lis	r4,KERNELBASE@h
-1:
-	dcbf	r0,r4
-	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	1b
-	sync
-
-/*
- * Set the HID0 and MSR for sleep.
- */
-	mfspr	r2,HID0
-	rlwinm	r2,r2,0,10,7	/* clear doze, nap */
-	oris	r2,r2,HID0_SLEEP@h
-	sync
-	mtspr	HID0,r2
-	sync
-
-/* This loop puts us back to sleep in case we have a spurrious
- * wakeup so that the host bridge properly stays asleep. The
- * CPU will be turned off, either after a known time (about 1
- * second) on wallstreet & lombard, or as soon as the CPU enters
- * SLEEP mode on core99
- */
-	mfmsr	r2
-	oris	r2,r2,MSR_POW@h
-1:	sync
-	mtmsr	r2
-	isync
-	b	1b
-
-/* 
- * Here is the resume code.
- */
-
-
-/*
- * Core99 machines resume here
- * r4 has the physical address of SL_PC(sp) (unused)
- */
-_GLOBAL(core99_wake_up)
-	/* Make sure HID0 no longer contains any sleep bit */
-	mfspr	r3,HID0
-	rlwinm	r3,r3,0,11,7		/* clear SLEEP, NAP, DOZE bits */
-	mtspr	HID0,r3
-	sync
-	isync
-
-	/* Won't that cause problems on CPU that doesn't support it ? */
-	lis	r3, 0
-	mtspr	SPRN_MMCR0, r3
-	
-	/* sanitize MSR */
-	mfmsr	r3
-	ori	r3,r3,MSR_EE|MSR_IP
-	xori	r3,r3,MSR_EE|MSR_IP
-	sync
-	isync
-	mtmsr	r3
-	sync
-	isync
-
-	/* Recover sleep storage */
-	lis	r3,sleep_storage@ha
-	addi	r3,r3,sleep_storage@l
-	tophys(r3,r3)
-	lwz	r1,0(r3)
-
-	/* Pass thru to older resume code ... */
-/* 
- * Here is the resume code for older machines.
- * r1 has the physical address of SL_PC(sp).
- */
-	
-grackle_wake_up:
-	/* Enable and then Flash inval the instruction & data cache */
-	mfspr	r3,HID0
-	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
-	sync
-	isync
-	mtspr	HID0,r3
-	xori	r3,r3, HID0_ICFI|HID0_DCI
-	mtspr	HID0,r3
-	sync
-	
-	/* Restore the kernel's segment registers before
-	 * we do any r1 memory access as we are not sure they
-	 * are in a sane state above the first 256Mb region
-	 */
-	li	r0,16		/* load up segment register values */
-	mtctr	r0		/* for context 0 */
-	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
-	li	r4,0
-3:	mtsrin	r3,r4
-	addi	r3,r3,0x111	/* increment VSID */
-	addis	r4,r4,0x1000	/* address of next segment */
-	bdnz	3b
-	
-	/* Restore the remaining bits of the HID0 register. */
-	subi	r1,r1,SL_PC
-	lwz	r3,SL_HID0(r1)
-	sync
-	isync
-	mtspr	HID0,r3
-	sync
-	isync
-
-	/* Restore 7400/7410/7450 specific registers */
-	mfspr	r3,PVR
-	srwi	r3,r3,16
-	cmpli	cr0,r3,0x8000
-	cmpli	cr1,r3,0x000c
-	cmpli	cr2,r3,0x800c
-	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
-	bne	1f
-	lwz	r4,SL_MSSCR0(r1)
-	sync
-	mtspr	SPRN_MSSCR0,r4
-	sync
-	isync
-	lwz	r4,SL_MSSSR0(r1)
-	sync
-	mtspr	SPRN_MSSSR0,r4
-	sync
-	isync
-	bne	cr2,1f
-	li	r4,0
-	mtspr	SPRN_L2CR2,r4
-	/* Restore 7450 specific registers */
-	beq	cr1,1f
-	lwz	r4,SL_HID1(r1)
-	sync
-	mtspr	HID1,r4
-	isync
-	sync
-	lwz	r4,SPRN_ICTRL(r1)
-	sync
-	mtspr	SPRN_ICTRL,r4
-	isync
-	sync
-	lwz	r4,SPRN_LDSTCR(r1)
-	sync
-	mtspr	SPRN_LDSTCR,r4
-	isync
-	sync
-	lwz	r4,SL_LDSTDB(r1)
-	sync
-	mtspr	SPRN_LDSTDB,r4
-	isync
-	sync
-1:
-	/* Restore the BATs, and SDR1.  Then we can turn on the MMU. */
-	lwz	r4,SL_SDR1(r1)
-	mtsdr1	r4
-	lwz	r4,SL_SPRG0(r1)
-	mtsprg	0,r4
-	lwz	r4,SL_SPRG0+4(r1)
-	mtsprg	1,r4
-	lwz	r4,SL_SPRG0+8(r1)
-	mtsprg	2,r4
-	lwz	r4,SL_SPRG0+12(r1)
-	mtsprg	3,r4
-
-	lwz	r4,SL_DBAT0(r1)
-	mtdbatu	0,r4
-	lwz	r4,SL_DBAT0+4(r1)
-	mtdbatl	0,r4
-	lwz	r4,SL_DBAT1(r1)
-	mtdbatu	1,r4
-	lwz	r4,SL_DBAT1+4(r1)
-	mtdbatl	1,r4
-	lwz	r4,SL_DBAT2(r1)
-	mtdbatu	2,r4
-	lwz	r4,SL_DBAT2+4(r1)
-	mtdbatl	2,r4
-	lwz	r4,SL_DBAT3(r1)
-	mtdbatu	3,r4
-	lwz	r4,SL_DBAT3+4(r1)
-	mtdbatl	3,r4
-	lwz	r4,SL_IBAT0(r1)
-	mtibatu	0,r4
-	lwz	r4,SL_IBAT0+4(r1)
-	mtibatl	0,r4
-	lwz	r4,SL_IBAT1(r1)
-	mtibatu	1,r4
-	lwz	r4,SL_IBAT1+4(r1)
-	mtibatl	1,r4
-	lwz	r4,SL_IBAT2(r1)
-	mtibatu	2,r4
-	lwz	r4,SL_IBAT2+4(r1)
-	mtibatl	2,r4
-	lwz	r4,SL_IBAT3(r1)
-	mtibatu	3,r4
-	lwz	r4,SL_IBAT3+4(r1)
-	mtibatl	3,r4
-
-	/* Flush all TLBs */
-	lis	r4,0x1000
-1:	addic.	r4,r4,-0x1000
-	tlbie	r4
-	blt	1b
-	sync
-
-	/* restore the MSR and turn on the MMU */
-	lwz	r3,SL_MSR(r1)
-	bl	turn_on_mmu	
-
-	/* get back the stack pointer */
-	tovirt(r1,r1)
-
-	/* Restore TB */
-	li	r3,0
-	mttbl	r3
-	lwz	r3,SL_TB(r1)
-	lwz	r4,SL_TB+4(r1)
-	mttbu	r3
-	mttbl	r4
-
-	/* Restore the callee-saved registers and return */
-	lwz	r0,SL_CR(r1)
-	mtcr	r0
-	lwz	r2,SL_R2(r1)
-	lmw	r12,SL_R12(r1)
-	addi	r1,r1,SL_SIZE
-	lwz	r0,4(r1)
-	mtlr	r0
-	blr
-
-turn_on_mmu:
-	mflr	r4
-	tovirt(r4,r4)
-	mtsrr0	r4
-	mtsrr1	r3
-	sync
-	isync
-	rfi
-
-	.data
-	.globl sleep_storage
-sleep_storage:
-	.long 0
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/walnut_setup.c linux-2.4.20-pre2/arch/ppc/kernel/walnut_setup.c
--- linux-2.4.20-pre1/arch/ppc/kernel/walnut_setup.c	Fri Nov 16 10:10:08 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/walnut_setup.c	Wed Dec 31 16:00:00 1969
@@ -1,292 +0,0 @@
-/*
- * BK Id: SCCS/s.walnut_setup.c 1.10 11/13/01 21:26:07 paulus
- */
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: walnut_setup.c
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 403GP "Walnut" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- *      <dan@net4x.com>.
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/interrupt.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/blk.h>
-#include <linux/seq_file.h>
-
-#include <asm/processor.h>
-#include <asm/board.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-
-#include "local_irq.h"
-#include "ppc4xx_pic.h"
-#include <asm/time.h>
-#include "walnut_setup.h"
-
-
-/* Function Prototypes */
-
-extern void abort(void);
-
-/* Global Variables */
-
-unsigned char __res[sizeof(bd_t)];
-
-
-/*
- * void __init walnut_init()
- *
- * Description:
- *   This routine...
- *
- * Input(s):
- *   r3 - Optional pointer to a board information structure.
- *   r4 - Optional pointer to the physical starting address of the init RAM
- *        disk.
- *   r5 - Optional pointer to the physical ending address of the init RAM
- *        disk.
- *   r6 - Optional pointer to the physical starting address of any kernel
- *        command-line parameters.
- *   r7 - Optional pointer to the physical ending address of any kernel
- *        command-line parameters.
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-walnut_init(unsigned long r3, unsigned long r4, unsigned long r5, 
-	    unsigned long r6, unsigned long r7)
-{
-	/*
-	 * If we were passed in a board information, copy it into the
-	 * residual data area.
-	 */
-	if (r3) {
-		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
-	}
-
-#if defined(CONFIG_BLK_DEV_INITRD)
-	/*
-	 * If the init RAM disk has been configured in, and there's a valid
-	 * starting address for it, set it up.
-	 */
-	if (r4) {
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	/* Copy the kernel command line arguments to a safe place. */
-
-	if (r6) {
- 		*(char *)(r7 + KERNELBASE) = 0;
-		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
-	}
-
-	/* Initialize machine-dependency vectors */
-
-	ppc_md.setup_arch	 	= walnut_setup_arch;
-	ppc_md.show_percpuinfo	 	= walnut_show_percpuinfo;
-	ppc_md.irq_cannonicalize 	= NULL;
-	ppc_md.init_IRQ		 	= walnut_init_IRQ;
-	ppc_md.get_irq		 	= walnut_get_irq;
-	ppc_md.init		 	= NULL;
-
-	ppc_md.restart		 	= walnut_restart;
-	ppc_md.power_off	 	= walnut_power_off;
-	ppc_md.halt		 	= walnut_halt;
-
-	ppc_md.time_init	 	= walnut_time_init;
-	ppc_md.set_rtc_time	 	= walnut_set_rtc_time;
-	ppc_md.get_rtc_time	 	= walnut_get_rtc_time;
-	ppc_md.calibrate_decr	 	= walnut_calibrate_decr;
-
-	ppc_md.kbd_setkeycode    	= NULL;
-	ppc_md.kbd_getkeycode    	= NULL;
-	ppc_md.kbd_translate     	= NULL;
-	ppc_md.kbd_unexpected_up 	= NULL;
-	ppc_md.kbd_leds          	= NULL;
-	ppc_md.kbd_init_hw       	= NULL;
-	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
-}
-
-/*
- * Document me.
- */
-void __init
-walnut_setup_arch(void)
-{
-	/* XXX - Implement me */
-}
-
-/*
- * int walnut_show_percpuinfo()
- *
- * Description:
- *   This routine pretty-prints the platform's internal CPU and bus clock
- *   frequencies into the buffer for usage in /proc/cpuinfo.
- *
- * Input(s):
- *  *buffer - Buffer into which CPU and bus clock frequencies are to be
- *            printed.
- *
- * Output(s):
- *  *buffer - Buffer with the CPU and bus clock frequencies.
- *
- * Returns:
- *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
- *   on error.
- */
-int
-walnut_show_percpuinfo(struct seq_file *m)
-{
-	bd_t *bp = (bd_t *)__res;
-
-	seq_printf(m, "clock\t\t: %dMHz\n"
-		   "bus clock\t\t: %dMHz\n",
-		   bp->bi_intfreq / 1000000,
-		   bp->bi_busfreq / 1000000);
-
-	return 0;
-}
-
-/*
- * Document me.
- */
-void __init
-walnut_init_IRQ(void)
-{
-	int i;
-
-	ppc4xx_pic_init();
-
-	for (i = 0; i < NR_IRQS; i++) {
-		irq_desc[i].handler = ppc4xx_pic;
-	}
-
-	return;
-}
-
-/*
- * Document me.
- */
-int
-walnut_get_irq(struct pt_regs *regs)
-{
-	return (ppc4xx_pic_get_irq(regs));
-}
-
-/*
- * Document me.
- */
-void
-walnut_restart(char *cmd)
-{
-	abort();
-}
-
-/*
- * Document me.
- */
-void
-walnut_power_off(void)
-{
-	walnut_restart(NULL);
-}
-
-/*
- * Document me.
- */
-void
-walnut_halt(void)
-{
-	walnut_restart(NULL);
-}
-
-/*
- * Document me.
- */
-long __init
-walnut_time_init(void)
-{
-	/* XXX - Implement me */
-	return 0;
-}
-
-/*
- * Document me.
- */
-int __init
-walnut_set_rtc_time(unsigned long time)
-{
-	/* XXX - Implement me */
-
-	return (0);
-}
-
-/*
- * Document me.
- */
-unsigned long __init
-walnut_get_rtc_time(void)
-{
-	/* XXX - Implement me */
-
-	return (0);
-}
-
-/*
- * void __init walnut_calibrate_decr()
- *
- * Description:
- *   This routine retrieves the internal processor frequency from the board
- *   information structure, sets up the kernel timer decrementer based on
- *   that value, enables the 403 programmable interval timer (PIT) and sets
- *   it up for auto-reload.
- *
- * Input(s):
- *   N/A
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-void __init
-walnut_calibrate_decr(void)
-{
-	unsigned int freq;
-	bd_t *bip = (bd_t *)__res;
-
-	freq = bip->bi_intfreq;
-
-	decrementer_count = freq / HZ;
-	count_period_num = 1;
-	count_period_den = freq;
-
-	/* Enable the PIT and set auto-reload of its value */
-
-	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
-
-	/* Clear any pending timer interrupts */
-
-	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/walnut_setup.h linux-2.4.20-pre2/arch/ppc/kernel/walnut_setup.h
--- linux-2.4.20-pre1/arch/ppc/kernel/walnut_setup.h	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/walnut_setup.h	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-/*
- * BK Id: SCCS/s.walnut_setup.h 1.5 05/17/01 18:14:22 cort
- */
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: walnut_setup.c
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM PowerPC 405GP "Walnut" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- *      <dan@netx4.com>.
- *
- */
-
-#ifndef	__WALNUT_SETUP_H__
-#define	__WALNUT_SETUP_H__
-
-#include <asm/ptrace.h>
-#include <asm/board.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern unsigned char	 __res[sizeof(bd_t)];
-
-extern void		 walnut_init(unsigned long r3,
-				  unsigned long ird_start,
-				  unsigned long ird_end,
-				  unsigned long cline_start,
-				  unsigned long cline_end);
-extern void		 walnut_setup_arch(void);
-extern int		 walnut_setup_residual(char *buffer);
-extern void		 walnut_init_IRQ(void);
-extern int		 walnut_get_irq(struct pt_regs *regs);
-extern void		 walnut_restart(char *cmd);
-extern void		 walnut_power_off(void);
-extern void		 walnut_halt(void);
-extern void		 walnut_time_init(void);
-extern int		 walnut_set_rtc_time(unsigned long now);
-extern unsigned long	 walnut_get_rtc_time(void);
-extern void		 walnut_calibrate_decr(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __WALNUT_SETUP_H__ */
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/xics.c linux-2.4.20-pre2/arch/ppc/kernel/xics.c
--- linux-2.4.20-pre1/arch/ppc/kernel/xics.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.20-pre2/arch/ppc/kernel/xics.c	Wed Dec 31 16:00:00 1969
@@ -1,217 +0,0 @@
-/*
- * BK Id: SCCS/s.xics.c 1.8 12/19/01 09:48:40 trini
- */
-/*
- * 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 "i8259.h"
-#include "xics.h"
-
-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);
-
-struct hw_interrupt_type xics_pic = {
-	" XICS     ",
-	NULL,
-	NULL,
-	xics_enable_irq,
-	xics_disable_irq,
-	xics_mask_and_ack_irq,
-	xics_end_irq
-};
-
-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_8259_CASCADE	0x2c
-#define XICS_IRQ_OFFSET		16
-#define XICS_IRQ_SPURIOUS	0
-
-#define DEFAULT_SERVER		0
-#define	DEFAULT_PRIORITY	0
-
-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;
-
-#define xirr_info(n_cpu)	(xics_info.per_cpu[n_cpu]->xirr.word)
-#define cppr_info(n_cpu)	(xics_info.per_cpu[n_cpu]->xirr.bytes[0])
-#define poll_info(n_cpu)	(xics_info.per_cpu[n_cpu]->xirr_poll.word)
-#define qirr_info(n_cpu)	(xics_info.per_cpu[n_cpu]->qirr.bytes[0])
-
-void
-xics_enable_irq(
-	u_int	irq
-	)
-{
-	int	status;
-	int	call_status;
-
-	irq -= XICS_IRQ_OFFSET;
-	if (irq == XICS_IPI)
-		return;
-	call_status = call_rtas("ibm,set-xive", 3, 1, (ulong*)&status,
-				irq, DEFAULT_SERVER, DEFAULT_PRIORITY);
-	if( call_status != 0 ) {
-		printk("xics_enable_irq: irq=%x: call_rtas failed; retn=%x, status=%x\n",
-		       irq, call_status, status);
-		return;
-	}
-}
-
-void
-xics_disable_irq(
-	u_int	irq
-	)
-{
-	int	status;
-	int	call_status;
-
-	irq -= XICS_IRQ_OFFSET;
-	call_status = call_rtas("ibm,int-off", 1, 1, (ulong*)&status, irq);
-	if( call_status != 0 ) {
-		printk("xics_disable_irq: irq=%x: call_rtas failed, retn=%x\n",
-		       irq, call_status);
-		return;
-	}
-}
-
-void
-xics_end_irq(
-	u_int	irq
-	)
-{
-	int cpu = smp_processor_id();
-
-	cppr_info(cpu) = 0; /* actually the value overwritten by ack */
-	xirr_info(cpu) = (0xff<<24) | (irq-XICS_IRQ_OFFSET);
-}
-
-void
-xics_mask_and_ack_irq(
-	u_int	irq
-	)
-{
-	int cpu = smp_processor_id();
-
-	if( irq < XICS_IRQ_OFFSET ) {
-		i8259_pic.ack(irq);
-		xirr_info(cpu) = (0xff<<24) | XICS_IRQ_8259_CASCADE;
-	}
-	else {
-		cppr_info(cpu) = 0xff;
-	}
-}
-
-int
-xics_get_irq(struct pt_regs *regs)
-{
-	u_int	cpu = smp_processor_id();
-	u_int	vec;
-	int irq;
-  
-	vec = xirr_info(cpu);
-	/*  (vec >> 24) == old priority */
-	vec &= 0x00ffffff;
-	/* for sanity, this had better be < NR_IRQS - 16 */
-	if( vec == XICS_IRQ_8259_CASCADE )
-		irq = i8259_poll();
-	else if( vec == XICS_IRQ_SPURIOUS )
-		irq = -1;
-	else
-		irq = vec + XICS_IRQ_OFFSET;
-	return irq;
-}
-
-#ifdef CONFIG_SMP
-void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
-{
-	qirr_info(smp_processor_id()) = 0xff;
-	smp_message_recv(MSG_RESCHEDULE, regs);
-}
-
-void xics_cause_IPI(int cpu)
-{
-	qirr_info(cpu) = 0;
-}
-
-void xics_setup_cpu(void)
-{
-	int cpu = smp_processor_id();
-
-	cppr_info(cpu) = 0xff;
-}
-#endif /* CONFIG_SMP */
-
-void
-xics_init_IRQ( void )
-{
-	int i;
-	extern unsigned long smp_chrp_cpu_nr;
-
-#ifdef CONFIG_SMP
-	for (i = 0; i < smp_chrp_cpu_nr; ++i)
-		xics_info.per_cpu[i] =
-			ioremap(0xfe000000 + smp_hw_index[i] * 0x1000, 0x20);
-#else
-	xics_info.per_cpu[0] = ioremap(0xfe000000, 0x20);
-#endif /* CONFIG_SMP */
-	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;
-
-	cppr_info(0) = 0xff;
-	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
-	request_irq(XICS_IPI + XICS_IRQ_OFFSET, xics_ipi_action, 0, "IPI", 0);
-#endif
-}
diff -urN linux-2.4.20-pre1/arch/ppc/kernel/xics.h linux-2.4.20-pre2/arch/ppc/kernel/xics.h
--- linux-2.4.20-pre1/arch/ppc/kernel/xics.h	Mon May 21 17:04:47 2001
+++ linux-2.4.20-pre2/arch/ppc/kernel/xics.h	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-/*
- * BK Id: SCCS/s.xics.h 1.5 05/17/01 18:14:22 cort
- */
-/*
- * 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 *);
-
-#endif /* _PPC_KERNEL_XICS_H */
diff -urN linux-2.4.20-pre1/arch/ppc/lib/checksum.S linux-2.4.20-pre2/arch/ppc/lib/checksum.S
--- linux-2.4.20-pre1/arch/ppc/lib/checksum.S	Tue Aug 28 06:58:33 2001
+++ linux-2.4.20-pre2/arch/ppc/lib/checksum.S	Mon Aug 12 16:34:15 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.checksum.S 1.8 08/20/01 22:09:34 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * This file contains assembly-language implementations
@@ -18,7 +18,7 @@
 #include <linux/sys.h>
 #include <asm/processor.h>
 #include <asm/errno.h>
-#include "../kernel/ppc_asm.tmpl"
+#include <asm/ppc_asm.h>
 
 	.text
 
diff -urN linux-2.4.20-pre1/arch/ppc/lib/string.S linux-2.4.20-pre2/arch/ppc/lib/string.S
--- linux-2.4.20-pre1/arch/ppc/lib/string.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc/lib/string.S	Mon Aug 12 16:34:15 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.string.S 1.11 05/21/02 21:44:32 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * String handling functions for PowerPC.
@@ -11,11 +11,11 @@
  * 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 <linux/config.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
 #include <asm/errno.h>
+#include <asm/ppc_asm.h>
 
 #define COPY_16_BYTES		\
 	lwz	r7,4(r4);	\
diff -urN linux-2.4.20-pre1/arch/ppc/mm/hashtable.S linux-2.4.20-pre2/arch/ppc/mm/hashtable.S
--- linux-2.4.20-pre1/arch/ppc/mm/hashtable.S	Tue Aug 28 06:58:33 2001
+++ linux-2.4.20-pre2/arch/ppc/mm/hashtable.S	Mon Aug 12 16:34:15 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.hashtable.S 1.18 08/15/01 22:43:07 paulus
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  arch/ppc/kernel/hashtable.S
@@ -27,11 +27,13 @@
  */
 
 #include <linux/config.h>
-#include "../kernel/ppc_asm.h"
+#include <asm/ppc_asm.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <kernel/ppc_defs.h>
 
 #ifdef CONFIG_SMP
 	.comm	hash_table_lock,4
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/Makefile linux-2.4.20-pre2/arch/ppc/platforms/Makefile
--- linux-2.4.20-pre1/arch/ppc/platforms/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/Makefile	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,53 @@
+# BK Id: SCCS/s.Makefile 1.57 09/24/01 07:45:31 trini
+#
+#
+# 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
+
+ifdef CONFIG_PPC64BRIDGE
+EXTRA_AFLAGS		:= -Wa,-mppc64bridge
+endif
+ifdef CONFIG_40x
+EXTRA_AFLAGS		:= -Wa,-m405
+endif
+
+# Extra CFLAGS so we don't have to do relative includes
+CFLAGS_pmac_setup.o	+= -I$(TOPDIR)/drivers/scsi -I$(TOPDIR)/fs/partitions \
+				-I$(TOPDIR)/arch/$(ARCH)/mm
+
+O_TARGET := platform.o
+
+export-objs			:= prep_setup.o
+
+obj-$(CONFIG_WALNUT)		+= walnut.o
+
+obj-$(CONFIG_APUS)		+= apus_setup.o
+ifeq ($(CONFIG_APUS),y)
+obj-$(CONFIG_PCI)		+= apus_pci.o
+endif
+
+obj-$(CONFIG_ALL_PPC)		+= pmac_pic.o pmac_setup.o pmac_time.o \
+					pmac_feature.o pmac_pci.o chrp_setup.o\
+					chrp_time.o chrp_pci.o prep_pci.o \
+					prep_time.o prep_setup.o
+ifeq ($(CONFIG_ALL_PPC),y)
+obj-$(CONFIG_NVRAM)		+= pmac_nvram.o
+endif
+obj-$(CONFIG_PMAC_BACKLIGHT)	+= pmac_backlight.o
+obj-$(CONFIG_PMAC_PBOOK)	+= sleep.o
+obj-$(CONFIG_PPC_RTAS)		+= error_log.o proc_rtas.o
+obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
+obj-$(CONFIG_GEMINI)		+= gemini_pci.o gemini_setup.o gemini_prom.o
+
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_ALL_PPC)		+= pmac_smp.o chrp_smp.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/apus_pci.c linux-2.4.20-pre2/arch/ppc/platforms/apus_pci.c
--- linux-2.4.20-pre1/arch/ppc/platforms/apus_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/apus_pci.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,187 @@
+/*
+ * BK Id: SCCS/s.apus_pci.c 1.5 09/08/01 15:47:42 paulus
+ */
+/*
+ * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch>
+ *
+ * APUS PCI routines.
+ *
+ * Currently, only B/CVisionPPC cards (Permedia2) are supported.
+ *
+ * Thanks to Geert Uytterhoeven for the idea:
+ * Read values from given config space(s) for the first devices, -1 otherwise
+ *
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_AMIGA
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "apus_pci.h"
+
+
+/* These definitions are mostly adapted from pm2fb.c */
+
+#undef APUS_PCI_MASTER_DEBUG
+#ifdef APUS_PCI_MASTER_DEBUG
+#define DPRINTK(a,b...)	printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif 
+
+/*
+ * The _DEFINITIVE_ memory mapping/unmapping functions.
+ * This is due to the fact that they're changing soooo often...
+ */
+#define DEFW()		wmb()
+#define DEFR()		rmb()
+#define DEFRW()		mb()
+
+#define DEVNO(d)	((d)>>3)
+#define FNNO(d)		((d)&7)
+
+
+extern unsigned long powerup_PCI_present;
+
+static struct pci_controller *apus_hose;
+
+
+void *pci_io_base(unsigned int bus)
+{
+	return 0;
+}
+
+
+#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op)	op((val), (type *)(addr)); DEFW()
+#define cfg_read_bad	*val = ~0;
+#define cfg_write_bad	;
+#define cfg_read_val(val)	*val
+#define cfg_write_val(val)	val
+
+#define APUS_PCI_OP(rw, size, type, op, mask)					\
+int									\
+apus_pcibios_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
+{										\
+	int fnno = FNNO(dev->devfn);						\
+	int devno = DEVNO(dev->devfn);						\
+										\
+	if (dev->bus->number > 0 || devno != 1) {				\
+		cfg_##rw##_bad;							\
+		return PCIBIOS_DEVICE_NOT_FOUND;				\
+	}									\
+	/* base address + function offset + offset ^ endianness conversion */	\
+	cfg_##rw(val, apus_hose->cfg_data + (fnno<<5) + (offset ^ mask),	\
+		 type, op);							\
+										\
+	DPRINTK(#op " b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, v: 0x%x\n",		\
+		dev->bus->number, dev->devfn>>3, dev->devfn&7,			\
+		offset, cfg_##rw##_val(val));					\
+	return PCIBIOS_SUCCESSFUL;						\
+}
+
+APUS_PCI_OP(read, byte, u8 *, readb, 3)
+APUS_PCI_OP(read, word, u16 *, readw, 2)
+APUS_PCI_OP(read, dword, u32 *, readl, 0)
+APUS_PCI_OP(write, byte, u8, writeb, 3)
+APUS_PCI_OP(write, word, u16, writew, 2)
+APUS_PCI_OP(write, dword, u32, writel, 0)
+
+
+static struct pci_ops apus_pci_ops = {
+	apus_pcibios_read_config_byte,
+	apus_pcibios_read_config_word,
+	apus_pcibios_read_config_dword,
+	apus_pcibios_write_config_byte,
+	apus_pcibios_write_config_word,
+	apus_pcibios_write_config_dword
+};
+
+static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM };
+
+void __init
+apus_pcibios_fixup(void)
+{
+/*	struct pci_dev *dev = pci_find_slot(0, 1<<3);
+	unsigned int reg, val, offset;*/
+
+	/* FIXME: interrupt? */
+	/*dev->interrupt = xxx;*/
+
+        request_resource(&iomem_resource, &pci_mem);
+    	printk("%s: PCI mem resource requested\n", __FUNCTION__);
+}
+
+static void __init apus_pcibios_fixup_bus(struct pci_bus *bus)
+{
+        bus->resource[1] = &pci_mem;
+}
+
+
+/* 
+ * This is from pm2fb.c again
+ * 
+ * Check if PCI (B/CVisionPPC) is available, initialize it and set up
+ * the pcibios_* pointers
+ */
+
+
+void __init
+apus_setup_pci_ptrs(void)
+{
+	if (!powerup_PCI_present) {
+		DPRINTK("no PCI bridge detected\n");
+		return;
+	}
+	DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n");
+
+	apus_hose = pcibios_alloc_controller();
+	if (!apus_hose) {
+		printk("apus_pci: Can't allocate PCI controller structure\n");
+		return;
+	}
+
+	if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) {
+		printk("apus_pci: unable to map PCI config region\n");
+		return;
+	}
+
+	if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) {
+		printk("apus_pci: unable to map PCI bridge\n");
+		return;
+	}
+
+	writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN);
+	DEFW();
+
+	writel(CVPPC_REGS_REGION,  apus_hose->cfg_data+ PCI_BASE_ADDRESS_0);
+	DEFW();
+	writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1);
+	DEFW();
+	writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2);
+	DEFW();
+	writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS);
+	DEFW();
+
+	writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+		PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND);
+	DEFW();
+
+	apus_hose->first_busno = 0;
+	apus_hose->last_busno = 0;
+	apus_hose->ops = &apus_pci_ops;
+	ppc_md.pcibios_fixup = apus_pcibios_fixup;
+	ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus;
+
+	return;
+}
+
+#endif /* CONFIG_AMIGA */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/apus_pci.h linux-2.4.20-pre2/arch/ppc/platforms/apus_pci.h
--- linux-2.4.20-pre1/arch/ppc/platforms/apus_pci.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/apus_pci.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,37 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer
+ * driver.
+ *
+ * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * --------------------------------------------------------------------------
+ * 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.
+ */
+
+#ifndef APUS_PCI_H
+#define APUS_PCI_H
+
+
+#define CSPPC_PCI_BRIDGE		0xfffe0000
+#define CSPPC_BRIDGE_ENDIAN		0x0000
+#define CSPPC_BRIDGE_INT		0x0010
+
+#define	CVPPC_PCI_CONFIG		0xfffc0000
+#define CVPPC_ROM_ADDRESS		0xe2000001
+#define CVPPC_REGS_REGION		0xef000000
+#define CVPPC_FB_APERTURE_ONE		0xe0000000
+#define CVPPC_FB_APERTURE_TWO		0xe1000000
+#define CVPPC_FB_SIZE			0x00800000
+
+/* CVPPC_BRIDGE_ENDIAN */
+#define CSPPCF_BRIDGE_BIG_ENDIAN	0x02
+
+/* CVPPC_BRIDGE_INT */
+#define CSPPCF_BRIDGE_ACTIVE_INT2	0x01
+
+
+#endif	/* APUS_PCI_H */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/apus_setup.c linux-2.4.20-pre2/arch/ppc/platforms/apus_setup.c
--- linux-2.4.20-pre1/arch/ppc/platforms/apus_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/apus_setup.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,1111 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/apus_setup.c
+ *
+ *  Copyright (C) 1998, 1999  Jesper Skov
+ *
+ *  Basically what is needed to replace functionality found in
+ *  arch/m68k allowing Amiga drivers to work under APUS.
+ *  Bits of code and/or ideas from arch/m68k and arch/ppc files.
+ *
+ * TODO:
+ *  This file needs a *really* good cleanup. Restructure and optimize.
+ *  Make sure it can be compiled for non-APUS configs. Begin to move
+ *  Amiga specific stuff into mach/amiga.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kd.h>
+#include <linux/init.h>
+#include <linux/hdreg.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/seq_file.h>
+
+#ifdef CONFIG_APUS
+#include <asm/logging.h>
+#endif
+
+/* Needs INITSERIAL call in head.S! */
+#undef APUS_DEBUG
+
+
+#include <linux/ide.h>
+#define T_CHAR          (0x0000)        /* char:  don't touch  */
+#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
+#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
+#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
+
+#define T_MASK_TYPE     (0xc000)
+#define T_MASK_COUNT    (0x3fff)
+
+#define D_CHAR(cnt)     (T_CHAR  | (cnt))
+#define D_SHORT(cnt)    (T_SHORT | (cnt))
+#define D_INT(cnt)      (T_INT   | (cnt))
+#define D_TEXT(cnt)     (T_TEXT  | (cnt))
+
+static u_short driveid_types[] = {
+        D_SHORT(10),    /* config - vendor2 */
+        D_TEXT(20),     /* serial_no */
+        D_SHORT(3),     /* buf_type, buf_size - ecc_bytes */
+        D_TEXT(48),     /* fw_rev - model */
+        D_CHAR(2),      /* max_multsect - vendor3 */
+        D_SHORT(1),     /* dword_io */
+        D_CHAR(2),      /* vendor4 - capability */
+        D_SHORT(1),     /* reserved50 */
+        D_CHAR(4),      /* vendor5 - tDMA */
+        D_SHORT(4),     /* field_valid - cur_sectors */
+        D_INT(1),       /* cur_capacity */
+        D_CHAR(2),      /* multsect - multsect_valid */
+        D_INT(1),       /* lba_capacity */
+        D_SHORT(194)    /* dma_1word - reservedyy */
+};
+
+#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
+
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigappc.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+
+unsigned long m68k_machtype;
+char debug_device[6] = "";
+
+extern void amiga_init_IRQ(void);
+
+void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
+/* machine dependent keyboard functions */
+int (*mach_keyb_init) (void) __initdata = NULL;
+int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
+void (*mach_kbd_leds) (unsigned int) = NULL;
+/* machine dependent irq functions */
+void (*mach_init_IRQ) (void) __initdata = NULL;
+void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
+void (*mach_get_model) (char *model) = NULL;
+int (*mach_get_hardware_list) (char *buffer) = NULL;
+int (*mach_get_irq_list) (char *) = NULL;
+void (*mach_process_int) (int, struct pt_regs *) = NULL;
+/* machine dependent timer functions */
+unsigned long (*mach_gettimeoffset) (void);
+void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
+int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
+int (*mach_set_clock_mmss) (unsigned long) = NULL;
+void (*mach_reset)( void );
+long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
+#if defined(CONFIG_AMIGA_FLOPPY)
+void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
+#endif
+#ifdef CONFIG_HEARTBEAT
+void (*mach_heartbeat) (int) = NULL;
+extern void apus_heartbeat (void);
+#endif
+
+extern unsigned long amiga_model;
+extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */
+extern unsigned count_period_num; /* 1 decrementer count equals */
+extern unsigned count_period_den; /* count_period_num / count_period_den us */
+
+int num_memory = 0;
+struct mem_info memory[NUM_MEMINFO];/* memory description */
+/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */
+int m68k_realnum_memory = 0;
+struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
+
+struct mem_info ramdisk;
+
+extern void amiga_floppy_setup(char *, int *);
+extern void config_amiga(void);
+
+static int __60nsram = 0;
+
+/* for cpuinfo */
+static int __bus_speed = 0;
+static int __speed_test_failed = 0;
+
+/********************************************** COMPILE PROTECTION */
+/* Provide some stubs that links to Amiga specific functions. 
+ * This allows CONFIG_APUS to be removed from generic PPC files while
+ * preventing link errors for other PPC targets.
+ */
+unsigned long apus_get_rtc_time(void)
+{
+#ifdef CONFIG_APUS
+	extern unsigned long m68k_get_rtc_time(void);
+	
+	return m68k_get_rtc_time ();
+#else
+	return 0;
+#endif
+}
+
+int apus_set_rtc_time(unsigned long nowtime)
+{
+#ifdef CONFIG_APUS
+	extern int m68k_set_rtc_time(unsigned long nowtime);
+
+	return m68k_set_rtc_time (nowtime);
+#else
+	return 0;
+#endif
+}
+
+
+
+/* Here some functions we don't support, but which the other ports reference */
+int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return 0; 
+}
+int pckbd_getkeycode(unsigned int scancode) 
+{ 
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return 0; 
+}
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+		    char raw_mode) 
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return 0; 
+}
+char pckbd_unexpected_up(unsigned char keycode)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return 0;
+}
+void pckbd_leds(unsigned char leds)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+}
+void pckbd_init_hw(void)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+}
+unsigned char pckbd_sysrq_xlate[128];
+
+struct pci_bus * __init pci_scan_peer_bridge(int bus)
+{
+	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");
+	return NULL;
+}
+
+/*********************************************************** SETUP */
+/* From arch/m68k/kernel/setup.c. */
+void __init apus_setup_arch(void)
+{
+#ifdef CONFIG_APUS
+	extern char cmd_line[];
+	int i;
+	char *p, *q;
+
+	/* Let m68k-shared code know it should do the Amiga thing. */
+	m68k_machtype = MACH_AMIGA;
+
+	/* Parse the command line for arch-specific options.
+	 * For the m68k, this is currently only "debug=xxx" to enable printing
+	 * certain kernel messages to some machine-specific device.  */
+	for( p = cmd_line; p && *p; ) {
+	    i = 0;
+	    if (!strncmp( p, "debug=", 6 )) {
+		    strncpy( debug_device, p+6, sizeof(debug_device)-1 );
+		    debug_device[sizeof(debug_device)-1] = 0;
+		    if ((q = strchr( debug_device, ' ' ))) *q = 0;
+		    i = 1;
+	    } else if (!strncmp( p, "60nsram", 7 )) {
+		    APUS_WRITE (APUS_REG_WAITSTATE, 
+				REGWAITSTATE_SETRESET
+				|REGWAITSTATE_PPCR
+				|REGWAITSTATE_PPCW);
+		    __60nsram = 1;
+		    i = 1;
+	    }
+
+	    if (i) {
+		/* option processed, delete it */
+		if ((q = strchr( p, ' ' )))
+		    strcpy( p, q+1 );
+		else
+		    *p = 0;
+	    } else {
+		if ((p = strchr( p, ' ' ))) ++p;
+	    }
+	}
+
+	config_amiga();
+
+#if 0 /* Enable for logging - also include logging.o in Makefile rule */
+	{
+#define LOG_SIZE 4096
+		void* base;
+
+		/* Throw away some memory - the P5 firmare stomps on top
+		 * of CHIP memory during bootup.
+		 */
+		amiga_chip_alloc(0x1000);
+
+		base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t));
+		LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE);
+	}
+#endif
+#endif
+}
+
+int
+apus_show_cpuinfo(struct seq_file *m)
+{
+	extern int __map_without_bats;
+	extern unsigned long powerup_PCI_present;
+
+	seq_printf(m, "machine\t\t: Amiga\n");
+	seq_printf(m, "bus speed\t: %d%s", __bus_speed,
+		   (__speed_test_failed) ? " [failed]\n" : "\n");
+	seq_printf(m, "using BATs\t: %s\n",
+		   (__map_without_bats) ? "No" : "Yes");
+	seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70);
+	seq_printf(m, "PCI bridge\t: %s\n",
+		   (powerup_PCI_present) ? "Yes" : "No");
+	return 0;
+}
+
+static void get_current_tb(unsigned long long *time)
+{
+	__asm __volatile ("1:mftbu 4      \n\t"
+			  "  mftb  5      \n\t"
+			  "  mftbu 6      \n\t"
+			  "  cmpw  4,6    \n\t"
+			  "  bne   1b     \n\t"
+			  "  stw   4,0(%0)\n\t"
+			  "  stw   5,4(%0)\n\t"
+			  : 
+			  : "r" (time)
+			  : "r4", "r5", "r6");
+}
+
+
+void apus_calibrate_decr(void)
+{
+#ifdef CONFIG_APUS
+	unsigned long freq;
+
+	/* This algorithm for determining the bus speed was
+           contributed by Ralph Schmidt. */
+	unsigned long long start, stop;
+	int bus_speed;
+	int speed_test_failed = 0;
+
+	{
+		unsigned long loop = amiga_eclock / 10;
+
+		get_current_tb (&start);
+		while (loop--) {
+			unsigned char tmp;
+
+			tmp = ciaa.pra;
+		}
+		get_current_tb (&stop);
+	}
+
+	bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000;
+	if (AMI_1200 == amiga_model)
+		bus_speed /= 2;
+
+	if ((bus_speed >= 47) && (bus_speed < 53)) {
+		bus_speed = 50;
+		freq = 12500000;
+	} else if ((bus_speed >= 57) && (bus_speed < 63)) {
+		bus_speed = 60;
+		freq = 15000000;
+	} else if ((bus_speed >= 63) && (bus_speed < 69)) {
+		bus_speed = 67;
+		freq = 16666667;
+	} else {
+		printk ("APUS: Unable to determine bus speed (%d). "
+			"Defaulting to 50MHz", bus_speed);
+		bus_speed = 50;
+		freq = 12500000;
+		speed_test_failed = 1;
+	}
+
+	/* Ease diagnostics... */
+	{
+		extern int __map_without_bats;
+		extern unsigned long powerup_PCI_present;
+
+		printk ("APUS: BATs=%d, BUS=%dMHz",
+			(__map_without_bats) ? 0 : 1,
+			bus_speed);
+		if (speed_test_failed)
+			printk ("[FAILED - please report]");
+
+		printk (", RAM=%dns, PCI bridge=%d\n",
+			(__60nsram) ? 60 : 70,
+			(powerup_PCI_present) ? 1 : 0);
+
+		/* print a bit more if asked politely... */
+		if (!(ciaa.pra & 0x40)){
+			extern unsigned int bat_addrs[4][3];
+			int b;
+			for (b = 0; b < 4; ++b) {
+				printk ("APUS: BAT%d ", b);
+				printk ("%08x-%08x -> %08x\n",
+					bat_addrs[b][0],
+					bat_addrs[b][1],
+					bat_addrs[b][2]);
+			}
+		}
+
+	}
+
+        printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+	       freq/1000000, freq%1000000);
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+	__bus_speed = bus_speed;
+	__speed_test_failed = speed_test_failed;
+#endif
+}
+
+void arch_gettod(int *year, int *mon, int *day, int *hour,
+		 int *min, int *sec)
+{
+#ifdef CONFIG_APUS
+	if (mach_gettod)
+		mach_gettod(year, mon, day, hour, min, sec);
+	else
+		*year = *mon = *day = *hour = *min = *sec = 0;
+#endif
+}
+
+/* for "kbd-reset" cmdline param */
+__init
+void kbd_reset_setup(char *str, int *ints)
+{
+}
+
+/*********************************************************** FLOPPY */
+#if defined(CONFIG_AMIGA_FLOPPY)
+__init 
+void floppy_setup(char *str, int *ints)
+{
+	if (mach_floppy_setup)
+		mach_floppy_setup (str, ints);
+}
+#endif
+
+/*********************************************************** MEMORY */
+#define KMAP_MAX 32
+unsigned long kmap_chunks[KMAP_MAX*3];
+int kmap_chunk_count = 0;
+
+/* From pgtable.h */
+static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va)
+{
+	pgd_t *dir = 0;
+	pmd_t *pmd = 0;
+	pte_t *pte = 0;
+
+	va &= PAGE_MASK;
+	
+	dir = pgd_offset( mm, va );
+	if (dir)
+	{
+		pmd = pmd_offset(dir, va & PAGE_MASK);
+		if (pmd && pmd_present(*pmd))
+		{
+			pte = pte_offset(pmd, va);
+		}
+	}
+	return pte;
+}
+
+
+/* Again simulating an m68k/mm/kmap.c function. */
+void kernel_set_cachemode( unsigned long address, unsigned long size,
+			   unsigned int cmode )
+{
+	unsigned long mask, flags;
+
+	switch (cmode)
+	{
+	case IOMAP_FULL_CACHING:
+		mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
+		flags = 0;
+		break;
+	case IOMAP_NOCACHE_SER:
+		mask = ~0;
+		flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
+		break;
+	default:
+		panic ("kernel_set_cachemode() doesn't support mode %d\n", 
+		       cmode);
+		break;
+	}
+	
+	size /= PAGE_SIZE;
+	address &= PAGE_MASK;
+	while (size--)
+	{
+		pte_t *pte;
+
+		pte = my_find_pte(&init_mm, address);
+		if ( !pte )
+		{
+			printk("pte NULL in kernel_set_cachemode()\n");
+			return;
+		}
+
+                pte_val (*pte) &= mask;
+                pte_val (*pte) |= flags;
+                flush_tlb_page(find_vma(&init_mm,address),address);
+
+		address += PAGE_SIZE;
+	}
+}
+
+unsigned long mm_ptov (unsigned long paddr)
+{
+	unsigned long ret;
+	if (paddr < 16*1024*1024)
+		ret = ZTWO_VADDR(paddr);
+	else {
+		int i;
+
+		for (i = 0; i < kmap_chunk_count;){
+			unsigned long phys = kmap_chunks[i++];
+			unsigned long size = kmap_chunks[i++];
+			unsigned long virt = kmap_chunks[i++];
+			if (paddr >= phys
+			    && paddr < (phys + size)){
+				ret = virt + paddr - phys;
+				goto exit;
+			}
+		}
+		
+		ret = (unsigned long) __va(paddr);
+	}
+exit:
+#ifdef DEBUGPV
+	printk ("PTOV(%lx)=%lx\n", paddr, ret);
+#endif
+	return ret;
+}
+
+int mm_end_of_chunk (unsigned long addr, int len)
+{
+	if (memory[0].addr + memory[0].size == addr + len)
+		return 1;
+	return 0;
+}
+
+/*********************************************************** CACHE */
+
+#define L1_CACHE_BYTES 32
+#define MAX_CACHE_SIZE 8192
+void cache_push(__u32 addr, int length)
+{
+	addr = mm_ptov(addr);
+
+	if (MAX_CACHE_SIZE < length)
+		length = MAX_CACHE_SIZE;
+
+	while(length > 0){
+		__asm ("dcbf 0,%0\n\t"
+		       : : "r" (addr));
+		addr += L1_CACHE_BYTES;
+		length -= L1_CACHE_BYTES;
+	}
+	/* Also flush trailing block */
+	__asm ("dcbf 0,%0\n\t"
+	       "sync \n\t"
+	       : : "r" (addr));
+}
+
+void cache_clear(__u32 addr, int length)
+{
+	if (MAX_CACHE_SIZE < length)
+		length = MAX_CACHE_SIZE;
+
+	addr = mm_ptov(addr);
+
+	__asm ("dcbf 0,%0\n\t"
+	       "sync \n\t"
+	       "icbi 0,%0 \n\t"
+	       "isync \n\t"
+	       : : "r" (addr));
+	
+	addr += L1_CACHE_BYTES;
+	length -= L1_CACHE_BYTES;
+
+	while(length > 0){
+		__asm ("dcbf 0,%0\n\t"
+		       "sync \n\t"
+		       "icbi 0,%0 \n\t"
+		       "isync \n\t"
+		       : : "r" (addr));
+		addr += L1_CACHE_BYTES;
+		length -= L1_CACHE_BYTES;
+	}
+
+	__asm ("dcbf 0,%0\n\t"
+	       "sync \n\t"
+	       "icbi 0,%0 \n\t"
+	       "isync \n\t"
+	       : : "r" (addr));
+}
+
+/****************************************************** from setup.c */
+void
+apus_restart(char *cmd)
+{
+	cli();
+
+	APUS_WRITE(APUS_REG_LOCK, 
+		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
+	APUS_WRITE(APUS_REG_LOCK, 
+		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
+	APUS_WRITE(APUS_REG_LOCK, 
+		   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
+	APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
+	APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
+	for(;;);
+}
+
+void
+apus_power_off(void)
+{
+	for (;;);
+}
+
+void
+apus_halt(void)
+{
+   apus_restart(NULL);
+}
+
+/****************************************************** from setup.c/IDE */
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+
+#if 0	/* no longer used  -- paulus */
+void
+apus_ide_fix_driveid(struct hd_driveid *id)
+{
+   u_char *p = (u_char *)id;
+   int i, j, cnt;
+   u_char t;
+
+   if (!MACH_IS_AMIGA && !MACH_IS_MAC)
+   	return;
+   for (i = 0; i < num_driveid_types; i++) {
+      cnt = driveid_types[i] & T_MASK_COUNT;
+      switch (driveid_types[i] & T_MASK_TYPE) {
+         case T_CHAR:
+            p += cnt;
+            break;
+         case T_SHORT:
+            for (j = 0; j < cnt; j++) {
+               t = p[0];
+               p[0] = p[1];
+               p[1] = t;
+               p += 2;
+            }
+            break;
+         case T_INT:
+            for (j = 0; j < cnt; j++) {
+               t = p[0];
+               p[0] = p[3];
+               p[3] = t;
+               t = p[1];
+               p[1] = p[2];
+               p[2] = t;
+               p += 4;
+            }
+            break;
+         case T_TEXT:
+            for (j = 0; j < cnt; j += 2) {
+               t = p[0];
+               p[0] = p[1];
+               p[1] = t;
+               p += 2;
+            }
+            break;
+      }
+   }
+}
+#endif /* 0 */
+
+__init
+void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, 
+			       ide_ioreg_t ctrl_port, int *irq)
+{
+        if (data_port || ctrl_port)
+                printk("apus_ide_init_hwif_ports: must not be called\n");
+}
+#endif
+/****************************************************** IRQ stuff */
+
+static unsigned int apus_irq_cannonicalize(unsigned int irq)
+{
+	return irq;
+}
+
+int apus_get_irq_list(char *buf)
+{
+#ifdef CONFIG_APUS
+	extern int amiga_get_irq_list(char *buf);
+	
+	return amiga_get_irq_list (buf);
+#else
+	return 0;
+#endif
+}
+
+/* IPL must be between 0 and 7 */
+static inline void apus_set_IPL(unsigned long ipl)
+{
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | ((~ipl) & IPLEMU_IPLMASK));
+	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+}
+
+static inline unsigned long apus_get_IPL(void)
+{
+	/* This returns the present IPL emulation level. */
+	unsigned long __f;
+	APUS_READ(APUS_IPL_EMU, __f);
+	return ((~__f) & IPLEMU_IPLMASK);
+}
+
+static inline unsigned long apus_get_prev_IPL(struct pt_regs* regs)
+{
+	/* The value saved in mq is the IPL_EMU value at the time of
+	   interrupt. The lower bits are the current interrupt level,
+	   the upper bits the requested level. Thus, to restore the
+	   IPL level to the post-interrupt state, we will need to use
+	   the lower bits. */
+	unsigned long __f = regs->mq;
+	return ((~__f) & IPLEMU_IPLMASK);
+}
+
+
+#ifdef CONFIG_APUS
+void free_irq(unsigned int irq, void *dev_id)
+{
+	extern void amiga_free_irq(unsigned int irq, void *dev_id);
+
+	amiga_free_irq (irq, dev_id);
+}
+
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+	unsigned long irqflags, const char * devname, void *dev_id)
+{
+	extern int  amiga_request_irq(unsigned int irq, 
+				      void (*handler)(int, void *, 
+						      struct pt_regs *),
+				      unsigned long flags, 
+				      const char *devname, 
+				      void *dev_id);
+
+	return amiga_request_irq (irq, handler, irqflags, devname, dev_id);
+}
+
+/* In Linux/m68k the sys_request_irq deals with vectors 0-7. That's what
+   callers expect - but on Linux/APUS we actually use the IRQ_AMIGA_AUTO
+   vectors (24-31), so we put this dummy function in between to adjust
+   the vector argument (rather have cruft here than in the generic irq.c). */
+int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+		    unsigned long irqflags, const char * devname, void *dev_id)
+{
+	extern int request_sysirq(unsigned int irq, 
+				  void (*handler)(int, void *, 
+						  struct pt_regs *),
+				  unsigned long irqflags,
+				  const char * devname, void *dev_id);
+	return request_sysirq(irq+IRQ_AMIGA_AUTO, handler, irqflags, 
+			      devname, dev_id);
+}
+#endif
+
+int apus_get_irq(struct pt_regs* regs)
+{
+#ifdef CONFIG_APUS
+	int level = apus_get_IPL();
+
+#ifdef __INTERRUPT_DEBUG
+	printk("<%d:%d>", level, apus_get_prev_IPL(regs));
+#endif
+
+	if (0 == level)
+		return -8;
+	if (7 == level)
+		return -9;
+
+	return level + IRQ_AMIGA_AUTO;
+#else
+	return 0;
+#endif
+}
+
+void apus_post_irq(struct pt_regs* regs, int level)
+{
+#ifdef __INTERRUPT_DEBUG
+	printk("{%d}", apus_get_prev_IPL(regs));
+#endif
+	/* Restore IPL to the previous value */
+	apus_set_IPL(apus_get_prev_IPL(regs));
+}
+
+/****************************************************** keyboard */
+static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	return -EOPNOTSUPP;
+}
+
+static int apus_kbd_getkeycode(unsigned int scancode)
+{
+	return scancode > 127 ? -EINVAL : scancode;
+}
+
+static int apus_kbd_translate(unsigned char keycode, unsigned char *keycodep,
+			      char raw_mode)
+{
+	*keycodep = keycode;
+	return 1;
+}
+
+static char apus_kbd_unexpected_up(unsigned char keycode)
+{
+	return 0200;
+}
+
+static void apus_kbd_leds(unsigned char leds)
+{
+}
+
+static void apus_kbd_init_hw(void)
+{
+#ifdef CONFIG_APUS
+	extern int amiga_keyb_init(void);
+
+	amiga_keyb_init();
+#endif
+}
+
+
+/****************************************************** debugging */
+
+/* some serial hardware definitions */
+#define SDR_OVRUN   (1<<15)
+#define SDR_RBF     (1<<14)
+#define SDR_TBE     (1<<13)
+#define SDR_TSRE    (1<<12)
+
+#define AC_SETCLR   (1<<15)
+#define AC_UARTBRK  (1<<11)
+
+#define SER_DTR     (1<<7)
+#define SER_RTS     (1<<6)
+#define SER_DCD     (1<<5)
+#define SER_CTS     (1<<4)
+#define SER_DSR     (1<<3)
+
+static __inline__ void ser_RTSon(void)
+{
+    ciab.pra &= ~SER_RTS; /* active low */
+}
+
+int __debug_ser_out( unsigned char c )
+{
+	custom.serdat = c | 0x100;
+	mb();
+	while (!(custom.serdatr & 0x2000))
+		barrier();
+	return 1;
+}
+
+unsigned char __debug_ser_in( void )
+{
+	unsigned char c;
+
+	/* XXX: is that ok?? derived from amiga_ser.c... */
+	while( !(custom.intreqr & IF_RBF) )
+		barrier();
+	c = custom.serdatr;
+	/* clear the interrupt, so that another character can be read */
+	custom.intreq = IF_RBF;
+	return c;
+}
+
+int __debug_serinit( void )
+{	
+	unsigned long flags;
+	
+	save_flags (flags);
+	cli();
+
+	/* turn off Rx and Tx interrupts */
+	custom.intena = IF_RBF | IF_TBE;
+
+	/* clear any pending interrupt */
+	custom.intreq = IF_RBF | IF_TBE;
+
+	restore_flags (flags);
+
+	/*
+	 * set the appropriate directions for the modem control flags,
+	 * and clear RTS and DTR
+	 */
+	ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
+	ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
+	
+#ifdef CONFIG_KGDB
+	/* turn Rx interrupts on for GDB */
+	custom.intena = IF_SETCLR | IF_RBF;
+	ser_RTSon();
+#endif
+
+	return 0;
+}
+
+void __debug_print_hex(unsigned long x)
+{
+	int i;
+	char hexchars[] = "0123456789ABCDEF";
+
+	for (i = 0; i < 8; i++) {
+		__debug_ser_out(hexchars[(x >> 28) & 15]);
+		x <<= 4;
+	}
+	__debug_ser_out('\n');
+	__debug_ser_out('\r');
+}
+
+void __debug_print_string(char* s)
+{
+	unsigned char c;
+	while((c = *s++))
+		__debug_ser_out(c);
+	__debug_ser_out('\n');
+	__debug_ser_out('\r');
+}
+
+static void apus_progress(char *s, unsigned short value)
+{
+	__debug_print_string(s);
+}
+
+/****************************************************** init */
+
+/* The number of spurious interrupts */
+volatile unsigned int num_spurious;
+
+#define NUM_IRQ_NODES 100
+static irq_node_t nodes[NUM_IRQ_NODES];
+
+extern void (*amiga_default_handler[AUTO_IRQS])(int, void *, struct pt_regs *);
+
+static const char *default_names[SYS_IRQS] = {
+	"spurious int", "int1 handler", "int2 handler", "int3 handler",
+	"int4 handler", "int5 handler", "int6 handler", "int7 handler"
+};
+
+irq_node_t *new_irq_node(void)
+{
+	irq_node_t *node;
+	short i;
+
+	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
+		if (!node->handler)
+			return node;
+
+	printk ("new_irq_node: out of nodes\n");
+	return NULL;
+}
+
+extern void amiga_enable_irq(unsigned int irq);
+extern void amiga_disable_irq(unsigned int irq);
+
+struct hw_interrupt_type amiga_irqctrl = {
+	" Amiga  ",
+	NULL,
+	NULL,
+	amiga_enable_irq,
+	amiga_disable_irq,
+	0,
+	0
+};
+
+#define HARDWARE_MAPPED_SIZE (512*1024)
+unsigned long __init apus_find_end_of_memory(void)
+{
+	int shadow = 0;
+	unsigned long total;
+
+	/* The memory size reported by ADOS excludes the 512KB
+	   reserved for PPC exception registers and possibly 512KB
+	   containing a shadow of the ADOS ROM. */
+	{
+		unsigned long size = memory[0].size;
+
+		/* If 2MB aligned, size was probably user
+                   specified. We can't tell anything about shadowing
+                   in this case so skip shadow assignment. */
+		if (0 != (size & 0x1fffff)){
+			/* Align to 512KB to ensure correct handling
+			   of both memfile and system specified
+			   sizes. */
+			size = ((size+0x0007ffff) & 0xfff80000);
+			/* If memory is 1MB aligned, assume
+                           shadowing. */
+			shadow = !(size & 0x80000);
+		}
+
+		/* Add the chunk that ADOS does not see. by aligning
+                   the size to the nearest 2MB limit upwards.  */
+		memory[0].size = ((size+0x001fffff) & 0xffe00000);
+	}
+
+	total = memory[0].size;
+
+	/* Remove the memory chunks that are controlled by special
+           Phase5 hardware. */
+
+	/* Remove the upper 512KB if it contains a shadow of
+	   the ADOS ROM. FIXME: It might be possible to
+	   disable this shadow HW. Check the booter
+	   (ppc_boot.c) */
+	if (shadow)
+		total -= HARDWARE_MAPPED_SIZE;
+
+	/* Remove the upper 512KB where the PPC exception
+	   vectors are mapped. */
+	total -= HARDWARE_MAPPED_SIZE;
+
+	/* Linux/APUS only handles one block of memory -- the one on
+	   the PowerUP board. Other system memory is horrible slow in
+	   comparison. The user can use other memory for swapping
+	   using the z2ram device. */
+	ram_phys_base = memory[0].addr;
+	return total;
+}
+
+static void __init
+apus_map_io(void)
+{
+	/* Map PPC exception vectors. */
+	io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL);
+	/* Map chip and ZorroII memory */
+	io_block_mapping(zTwoBase,   0x00000000, 0x01000000, _PAGE_IO);
+}
+
+__init
+void apus_init_IRQ(void)
+{
+	int i;
+
+	for ( i = 0 ; i < NR_IRQS ; i++ )
+		irq_desc[i].handler = &amiga_irqctrl;
+
+	for (i = 0; i < NUM_IRQ_NODES; i++)
+		nodes[i].handler = NULL;
+
+	for (i = 0; i < AUTO_IRQS; i++) {
+		if (amiga_default_handler[i] != NULL)
+			sys_request_irq(i, amiga_default_handler[i],
+					0, default_names[i], NULL);
+	}
+
+	amiga_init_IRQ();
+
+}
+
+__init
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7)
+{
+	extern int parse_bootinfo(const struct bi_record *);
+	extern char _end[];
+	
+	/* Parse bootinfo. The bootinfo is located right after
+           the kernel bss */
+	parse_bootinfo((const struct bi_record *)&_end);
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* Take care of initrd if we have one. Use data from
+	   bootinfo to avoid the need to initialize PPC
+	   registers when kernel is booted via a PPC reset. */
+	if ( ramdisk.addr ) {
+		initrd_start = (unsigned long) __va(ramdisk.addr);
+		initrd_end = (unsigned long) 
+			__va(ramdisk.size + ramdisk.addr);
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+
+	ppc_md.setup_arch     = apus_setup_arch;
+	ppc_md.show_cpuinfo   = apus_show_cpuinfo;
+	ppc_md.irq_cannonicalize = apus_irq_cannonicalize;
+	ppc_md.init_IRQ       = apus_init_IRQ;
+	ppc_md.get_irq        = apus_get_irq;
+	
+#error Should use the ->end() member of irq_desc[x]. -- Cort
+	/*ppc_md.post_irq       = apus_post_irq;*/
+	
+#ifdef CONFIG_HEARTBEAT
+	ppc_md.heartbeat      = apus_heartbeat;
+	ppc_md.heartbeat_count = 1;
+#endif
+#ifdef APUS_DEBUG
+	__debug_serinit();
+	ppc_md.progress       = apus_progress;
+#endif
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = apus_restart;
+	ppc_md.power_off      = apus_power_off;
+	ppc_md.halt           = apus_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = apus_set_rtc_time;
+	ppc_md.get_rtc_time   = apus_get_rtc_time;
+	ppc_md.calibrate_decr = apus_calibrate_decr;
+
+	ppc_md.find_end_of_memory = apus_find_end_of_memory;
+	ppc_md.setup_io_mappings = apus_map_io;
+
+	ppc_md.nvram_read_val = NULL;
+	ppc_md.nvram_write_val = NULL;
+
+	/* These should not be used for the APUS yet, since it uses
+	   the M68K keyboard now. */
+	ppc_md.kbd_setkeycode    = apus_kbd_setkeycode;
+	ppc_md.kbd_getkeycode    = apus_kbd_getkeycode;
+	ppc_md.kbd_translate     = apus_kbd_translate;
+	ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up;
+	ppc_md.kbd_leds          = apus_kbd_leds;
+	ppc_md.kbd_init_hw       = apus_kbd_init_hw;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports;
+#endif		
+}
+
+
+/*************************************************** coexistence */
+void __init adbdev_init(void)
+{
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/bseip.h linux-2.4.20-pre2/arch/ppc/platforms/bseip.h
--- linux-2.4.20-pre1/arch/ppc/platforms/bseip.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/bseip.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,42 @@
+/*
+ * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus
+ */
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_BSEIP_DEFS
+#define __MACH_BSEIP_DEFS
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * All we need to get started is the IMMR.
+ */
+#define IMAP_ADDR		((uint)0xff000000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0x04000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+#endif	/* !__ASSEMBLY__ */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/chrp_pci.c linux-2.4.20-pre2/arch/ppc/platforms/chrp_pci.c
--- linux-2.4.20-pre1/arch/ppc/platforms/chrp_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/chrp_pci.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,328 @@
+/*
+ * BK Id: SCCS/s.chrp_pci.c 1.22 09/08/01 15:47:42 paulus
+ */
+/*
+ * CHRP pci routines.
+ */
+
+#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/hydra.h>
+#include <asm/prom.h>
+#include <asm/gg2.h>
+#include <asm/machdep.h>
+#include <asm/sections.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+
+/* LongTrail */
+unsigned long gg2_pci_config_base;
+
+#define pci_config_addr(dev, offset) \
+(gg2_pci_config_base | ((dev->bus->number)<<16) | ((dev->devfn)<<8) | (offset))
+
+volatile struct Hydra *Hydra = NULL;
+
+/*
+ * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
+ * limit the bus number to 3 bits
+ */
+
+#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define cfg_read_bad(val, size)		*val = bad_##size;
+#define cfg_write_bad(val, size)
+
+#define bad_byte	0xff
+#define bad_word	0xffff
+#define bad_dword	0xffffffffU
+
+#define GG2_PCI_OP(rw, size, type, op)					    \
+int __chrp gg2_##rw##_config_##size(struct pci_dev *dev, int off, type val) \
+{									    \
+	if (dev->bus->number > 7) {					    \
+		cfg_##rw##_bad(val, size)				    \
+		return PCIBIOS_DEVICE_NOT_FOUND;			    \
+	}								    \
+	cfg_##rw(val, pci_config_addr(dev, off), type, op);		    \
+	return PCIBIOS_SUCCESSFUL;					    \
+}
+
+GG2_PCI_OP(read, byte, u8 *, in_8)
+GG2_PCI_OP(read, word, u16 *, in_le16)
+GG2_PCI_OP(read, dword, u32 *, in_le32)
+GG2_PCI_OP(write, byte, u8, out_8)
+GG2_PCI_OP(write, word, u16, out_le16)
+GG2_PCI_OP(write, dword, u32, out_le32)
+
+static struct pci_ops gg2_pci_ops =
+{
+	gg2_read_config_byte,
+	gg2_read_config_word,
+	gg2_read_config_dword,
+	gg2_write_config_byte,
+	gg2_write_config_word,
+	gg2_write_config_dword
+};
+
+/*
+ * Access functions for PCI config space on IBM "python" host bridges.
+ */
+#define PYTHON_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
+				 | (((o) & ~3) << 24))
+
+#define PYTHON_PCI_OP(rw, size, type, op, mask)			    	     \
+int __chrp								     \
+python_##rw##_config_##size(struct pci_dev *dev, int offset, type val) 	     \
+{									     \
+	struct pci_controller *hose = dev->sysdata;			     \
+									     \
+	out_be32(hose->cfg_addr,					     \
+		 PYTHON_CFA(dev->bus->number, dev->devfn, offset));	     \
+	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);   	     \
+	return PCIBIOS_SUCCESSFUL;					     \
+}
+
+PYTHON_PCI_OP(read, byte, u8 *, in_8, 3)
+PYTHON_PCI_OP(read, word, u16 *, in_le16, 2)
+PYTHON_PCI_OP(read, dword, u32 *, in_le32, 0)
+PYTHON_PCI_OP(write, byte, u8, out_8, 3)
+PYTHON_PCI_OP(write, word, u16, out_le16, 2)
+PYTHON_PCI_OP(write, dword, u32, out_le32, 0)
+
+static struct pci_ops python_pci_ops =
+{
+	python_read_config_byte,
+	python_read_config_word,
+	python_read_config_dword,
+	python_write_config_byte,
+	python_write_config_word,
+	python_write_config_dword
+};
+
+/*
+ * Access functions for PCI config space using RTAS calls.
+ */
+#define RTAS_PCI_READ_OP(size, type, nbytes)			    	  \
+int __chrp								  \
+rtas_read_config_##size(struct pci_dev *dev, int offset, type val) 	  \
+{									  \
+	unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
+		| ((dev->bus->number & 0xff) << 16);			  \
+	unsigned long ret = ~0UL;					  \
+	int rval;							  \
+									  \
+	rval = call_rtas("read-pci-config", 2, 2, &ret, addr, nbytes);	  \
+	*val = ret;							  \
+	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;    	  \
+}
+
+#define RTAS_PCI_WRITE_OP(size, type, nbytes)				  \
+int __chrp								  \
+rtas_write_config_##size(struct pci_dev *dev, int offset, type val)	  \
+{									  \
+	unsigned long addr = (offset & 0xff) | ((dev->devfn & 0xff) << 8) \
+		| ((dev->bus->number & 0xff) << 16);			  \
+	int rval;							  \
+									  \
+	rval = call_rtas("write-pci-config", 3, 1, NULL,		  \
+			 addr, nbytes, (ulong)val);			  \
+	return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;	  \
+}
+
+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)
+
+static struct pci_ops rtas_pci_ops =
+{
+	rtas_read_config_byte,
+	rtas_read_config_word,
+	rtas_read_config_dword,
+	rtas_write_config_byte,
+	rtas_write_config_word,
+	rtas_write_config_dword
+};
+
+    /*
+     *  Temporary fixes for PCI devices. These should be replaced by OF query
+     *  code -- Geert
+     */
+
+static u_char hydra_openpic_initsenses[] __initdata = {
+    1,	/* HYDRA_INT_SIO */
+    0,	/* HYDRA_INT_SCSI_DMA */
+    0,	/* HYDRA_INT_SCCA_TX_DMA */
+    0,	/* HYDRA_INT_SCCA_RX_DMA */
+    0,	/* HYDRA_INT_SCCB_TX_DMA */
+    0,	/* HYDRA_INT_SCCB_RX_DMA */
+    1,	/* HYDRA_INT_SCSI */
+    1,	/* HYDRA_INT_SCCA */
+    1,	/* HYDRA_INT_SCCB */
+    1,	/* HYDRA_INT_VIA */
+    1,	/* HYDRA_INT_ADB */
+    0,	/* HYDRA_INT_ADB_NMI */
+    	/* all others are 1 (= default) */
+};
+
+int __init
+hydra_init(void)
+{
+	struct device_node *np;
+
+	np = find_devices("mac-io");
+	if (np == NULL || np->n_addrs == 0) {
+		printk(KERN_WARNING "Warning: no mac-io found\n");
+		return 0;
+	}
+	Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
+	printk("Hydra Mac I/O at %x\n", np->addrs[0].address);
+	out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
+					   HYDRA_FC_SCSI_CELL_EN |
+					   HYDRA_FC_SCCA_ENABLE |
+					   HYDRA_FC_SCCB_ENABLE |
+					   HYDRA_FC_ARB_BYPASS |
+					   HYDRA_FC_MPIC_ENABLE |
+					   HYDRA_FC_SLOW_SCC_PCLK |
+					   HYDRA_FC_MPIC_IS_MASTER));
+	OpenPIC_Addr = &Hydra->OpenPIC;
+	OpenPIC_InitSenses = hydra_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(hydra_openpic_initsenses);
+	return 1;
+}
+
+void __init
+chrp_pcibios_fixup(void)
+{
+	struct pci_dev *dev;
+	struct device_node *np;
+
+	/* PCI interrupts are controlled by the OpenPIC */
+	pci_for_each_dev(dev) {
+		np = pci_device_to_OF_node(dev);
+		if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0))
+			dev->irq = np->intrs[0].line;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+}
+
+void __init
+chrp_find_bridges(void)
+{
+	struct device_node *dev;
+	int *bus_range;
+	int len, index = -1;
+	struct pci_controller *hose;
+	volatile unsigned char *cfg;
+	unsigned int *dma;
+	char *model, *machine;
+	int is_longtrail = 0, is_mot = 0;
+	struct device_node *root = find_path_device("/");
+#ifdef CONFIG_POWER3
+	unsigned int *opprop = (unsigned int *)
+		get_property(root, "platform-open-pic", NULL);
+	int i;
+#endif
+
+	/*
+	 * The PCI host bridge nodes on some machines don't have
+	 * properties to adequately identify them, so we have to
+	 * look at what sort of machine this is as well.
+	 */
+	machine = get_property(root, "model", NULL);
+	if (machine != NULL) {
+		is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
+		is_mot = strncmp(machine, "MOT", 3) == 0;
+	}
+	for (dev = root->child; dev != NULL; dev = dev->sibling) {
+		if (dev->type == NULL || strcmp(dev->type, "pci") != 0)
+			continue;
+		++index;
+		/* The GG2 bridge on the LongTrail doesn't have an address */
+		if (dev->n_addrs < 1 && !is_longtrail) {
+			printk(KERN_WARNING "Can't use %s: no address\n",
+			       dev->full_name);
+			continue;
+		}
+		bus_range = (int *) get_property(dev, "bus-range", &len);
+		if (bus_range == NULL || len < 2 * sizeof(int)) {
+			printk(KERN_WARNING "Can't get bus-range for %s\n",
+				dev->full_name);
+			continue;
+		}
+		if (bus_range[1] == bus_range[0])
+			printk(KERN_INFO "PCI bus %d", bus_range[0]);
+		else
+			printk(KERN_INFO "PCI buses %d..%d",
+			       bus_range[0], bus_range[1]);
+		printk(" controlled by %s", dev->type);
+		if (dev->n_addrs > 0)
+			printk(" at %x", dev->addrs[0].address);
+		printk("\n");
+
+		hose = pcibios_alloc_controller();
+		if (!hose) {
+			printk("Can't allocate PCI controller structure for %s\n",
+				dev->full_name);
+			continue;
+		}
+		hose->arch_data = dev;
+		hose->first_busno = bus_range[0];
+		hose->last_busno = bus_range[1];
+
+		model = get_property(dev, "model", NULL);
+		if (model == NULL)
+			model = "<none>";
+		if (device_is_compatible(dev, "IBM,python")) {
+			hose->ops = &python_pci_ops;
+			cfg = ioremap(dev->addrs[0].address + 0xf8000, 0x20);
+			hose->cfg_addr = (volatile unsigned int *) cfg;
+			hose->cfg_data = cfg + 0x10;
+		} else if (is_mot
+			   || strncmp(model, "Motorola, Grackle", 17) == 0) {
+			setup_grackle(hose);
+		} else if (is_longtrail) {
+			hose->ops = &gg2_pci_ops;
+			gg2_pci_config_base = (unsigned long)
+				ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
+		} else {
+			printk("No methods for %s (model %s), using RTAS\n",
+			       dev->full_name, model);
+			hose->ops = &rtas_pci_ops;
+		}
+
+		pci_process_bridge_OF_ranges(hose, dev, index == 0);
+
+#ifdef CONFIG_POWER3
+		if (opprop != NULL) {
+			i = prom_n_addr_cells(root) * (index + 2) - 1;
+			openpic_setup_ISU(index, opprop[i]);
+		}
+#endif /* CONFIG_POWER3 */
+
+		/* check the first bridge for a property that we can
+		   use to set pci_dram_offset */
+		dma = (unsigned int *)
+			get_property(dev, "ibm,dma-ranges", &len);
+		if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
+			pci_dram_offset = dma[2] - dma[3];
+			printk("pci_dram_offset = %lx\n", pci_dram_offset);
+		}
+	}
+
+	ppc_md.pcibios_fixup = chrp_pcibios_fixup;
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/chrp_setup.c linux-2.4.20-pre2/arch/ppc/platforms/chrp_setup.c
--- linux-2.4.20-pre1/arch/ppc/platforms/chrp_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/chrp_setup.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,632 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * 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/ide.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/gg2.h>
+#include <asm/pci-bridge.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/hydra.h>
+#include <asm/keyboard.h>
+#include <asm/sections.h>
+#include <asm/time.h>
+#include <asm/btext.h>
+#include <asm/i8259.h>
+#include <asm/open_pic.h>
+#include <asm/xics.h>
+
+unsigned long chrp_get_rtc_time(void);
+int chrp_set_rtc_time(unsigned long nowtime);
+void chrp_calibrate_decr(void);
+long chrp_time_init(void);
+
+void chrp_find_bridges(void);
+void chrp_event_scan(void);
+void rtas_display_progress(char *, unsigned short);
+void rtas_indicator_progress(char *, unsigned short);
+void btext_progress(char *, unsigned short);
+
+extern unsigned long pmac_find_end_of_memory(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 select_adb_keyboard(void);
+extern int of_show_percpuinfo(struct seq_file *, int);
+
+extern kdev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_jiffy;
+static int max_width;
+
+#ifdef CONFIG_SMP
+extern struct smp_ops_t chrp_smp_ops;
+extern struct smp_ops_t xics_smp_ops;
+#endif
+
+static const char *gg2_memtypes[4] = {
+	"FPM", "SDRAM", "EDO", "BEDO"
+};
+static const char *gg2_cachesizes[4] = {
+	"256 KB", "512 KB", "1 MB", "Reserved"
+};
+static const char *gg2_cachetypes[4] = {
+	"Asynchronous", "Reserved", "Flow-Through Synchronous",
+	"Pipelined Synchronous"
+};
+static const char *gg2_cachemodes[4] = {
+	"Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
+};
+
+int __chrp
+chrp_show_cpuinfo(struct seq_file *m)
+{
+	int i, sdramen;
+	unsigned int t;
+	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);
+
+	/* longtrail (goldengate) stuff */
+	if (!strncmp(model, "IBM,LongTrail", 13)) {
+		/* VLSI VAS96011/12 `Golden Gate 2' */
+		/* Memory banks */
+		sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
+						GG2_PCI_DRAM_CTRL))
+			   >>31) & 1;
+		for (i = 0; i < (sdramen ? 4 : 6); i++) {
+			t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
+						 GG2_PCI_DRAM_BANK0+
+						 i*4));
+			if (!(t & 1))
+				continue;
+			switch ((t>>8) & 0x1f) {
+			case 0x1f:
+				model = "4 MB";
+				break;
+			case 0x1e:
+				model = "8 MB";
+				break;
+			case 0x1c:
+				model = "16 MB";
+				break;
+			case 0x18:
+				model = "32 MB";
+				break;
+			case 0x10:
+				model = "64 MB";
+				break;
+			case 0x00:
+				model = "128 MB";
+				break;
+			default:
+				model = "Reserved";
+				break;
+			}
+			seq_printf(m, "memory bank %d\t: %s %s\n", i, model,
+				   gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
+		}
+		/* L2 cache */
+		t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
+		seq_printf(m, "board l2\t: %s %s (%s)\n",
+			   gg2_cachesizes[(t>>7) & 3],
+			   gg2_cachetypes[(t>>2) & 3],
+			   gg2_cachemodes[t & 3]);
+	}
+	return 0;
+}
+
+/*
+ *  Fixes for the National Semiconductor PC78308VUL SuperI/O
+ *
+ *  Some versions of Open Firmware incorrectly initialize the IRQ settings
+ *  for keyboard and mouse
+ */
+static inline void __init sio_write(u8 val, u8 index)
+{
+	outb(index, 0x15c);
+	outb(val, 0x15d);
+}
+
+static inline u8 __init sio_read(u8 index)
+{
+	outb(index, 0x15c);
+	return inb(0x15d);
+}
+
+static void __init sio_fixup_irq(const char *name, u8 device, u8 level,
+				     u8 type)
+{
+	u8 level0, type0, active;
+
+	/* select logical device */
+	sio_write(device, 0x07);
+	active = sio_read(0x30);
+	level0 = sio_read(0x70);
+	type0 = sio_read(0x71);
+	if (level0 != level || type0 != type || !active) {
+		printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: "
+		       "remapping to level %d, type %d, active\n",
+		       name, level0, type0, !active ? "in" : "", level, type);
+		sio_write(0x01, 0x30);
+		sio_write(level, 0x70);
+		sio_write(type, 0x71);
+	}
+}
+
+static void __init sio_init(void)
+{
+	struct device_node *root;
+
+	if ((root = find_path_device("/")) &&
+	    !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
+		/* logical device 0 (KBC/Keyboard) */
+		sio_fixup_irq("keyboard", 0, 1, 2);
+		/* select logical device 1 (KBC/Mouse) */
+		sio_fixup_irq("mouse", 1, 12, 2);
+	}
+}
+
+
+void __init
+chrp_setup_arch(void)
+{
+	struct device_node *device;
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000/HZ;
+
+#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) */
+
+	/* Lookup PCI host bridges */
+	chrp_find_bridges();
+
+#ifndef CONFIG_PPC64BRIDGE
+	/*
+	 *  Temporary fixes for PCI devices.
+	 *  -- Geert
+	 */
+	hydra_init();		/* Mac I/O */
+
+#endif /* CONFIG_PPC64BRIDGE */
+
+	/* Some IBM machines don't have the hydra -- Cort */
+	if (!OpenPIC_Addr) {
+		struct device_node *root;
+		unsigned long *opprop;
+		int n;
+
+		root = find_path_device("/");
+		opprop = (unsigned long *) get_property
+			(root, "platform-open-pic", NULL);
+		n = prom_n_addr_cells(root);
+		if (opprop != 0) {
+			printk("OpenPIC addrs: %lx %lx %lx\n",
+			       opprop[n-1], opprop[2*n-1], opprop[3*n-1]);
+			OpenPIC_Addr = ioremap(opprop[n-1], 0x40000);
+		}
+	}
+
+	/*
+	 *  Fix the Super I/O configuration
+	 */
+	sio_init();
+
+	/*
+	 *  Setup the console operations
+	 */
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+	/* Get the event scan rate for the rtas so we know how
+	 * often it expects a heartbeat. -- Cort
+	 */
+	if ( rtas_data ) {
+		struct property *p;
+		device = find_devices("rtas");
+		for ( p = device->properties;
+		      p && strncmp(p->name, "rtas-event-scan-rate", 20);
+		      p = p->next )
+			/* nothing */ ;
+		if ( p && *(unsigned long *)p->value ) {
+			ppc_md.heartbeat = chrp_event_scan;
+			ppc_md.heartbeat_reset = (HZ/(*(unsigned long *)p->value)*30)-1;
+			ppc_md.heartbeat_count = 1;
+			printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n",
+			       *(unsigned long *)p->value, ppc_md.heartbeat_reset );
+		}
+	}
+}
+
+void __chrp
+chrp_event_scan(void)
+{
+	unsigned char log[1024];
+	unsigned long ret = 0;
+	/* XXX: we should loop until the hardware says no more error logs -- Cort */
+	call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0,
+		   __pa(log), 1024 );
+	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+}
+	
+void __chrp
+chrp_restart(char *cmd)
+{
+	printk("RTAS system-reboot returned %d\n",
+	       call_rtas("system-reboot", 0, 1, NULL));
+	for (;;);
+}
+
+void __chrp
+chrp_power_off(void)
+{
+	/* allow power on only with power button press */
+	printk("RTAS power-off returned %d\n",
+	       call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff));
+	for (;;);
+}
+
+void __chrp
+chrp_halt(void)
+{
+	chrp_power_off();
+}
+
+u_int __chrp
+chrp_irq_cannonicalize(u_int irq)
+{
+	if (irq == 2)
+		return 9;
+	return irq;
+}
+
+void __init chrp_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("Cannot find pci to get ack address\n");
+	else
+		chrp_int_ack_special = (unsigned char *)
+			ioremap(addrp[prom_n_addr_cells(np)-1], 1);
+	/* 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(0);
+#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
+	/* see if there is a keyboard in the device tree
+	   with a parent of type "adb" */
+	for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
+		if (kbd->parent && kbd->parent->type
+		    && strcmp(kbd->parent->type, "adb") == 0)
+			break;
+	if (kbd)
+		request_irq( HYDRA_INT_ADB_NMI, xmon_irq, 0, "XMON break", 0);
+#endif
+}
+
+void __init
+chrp_init2(void)
+{
+#ifdef CONFIG_NVRAM  
+	pmac_nvram_init();
+#endif
+
+	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");
+
+	if (ppc_md.progress)
+		ppc_md.progress("  Have fun!    ", 0x7777);
+
+#if defined(CONFIG_VT) && (defined(CONFIG_ADB_KEYBOARD) || defined(CONFIG_INPUT))
+	/* see if there is a keyboard in the device tree
+	   with a parent of type "adb" */
+	{
+		struct device_node *kbd;
+
+		for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) {
+			if (kbd->parent && kbd->parent->type
+			    && strcmp(kbd->parent->type, "adb") == 0) {
+				select_adb_keyboard();
+				break;
+			}
+		}
+	}
+#endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+
+static int __chrp
+chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return check_region(from, extent);
+}
+
+static void __chrp
+chrp_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+        request_region(from, extent, name);
+}
+
+static void __chrp
+chrp_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+        release_region(from, extent);
+}
+
+static void __chrp
+chrp_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;
+	}
+	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+}
+#endif
+
+/*
+ * One of the main thing these mappings are needed for is so that
+ * xmon can get to the serial port early on.  We probably should
+ * handle the machines with the mpc106 as well as the python (F50)
+ * and the GG2 (longtrail).  Actually we should look in the device
+ * tree and do the right thing.
+ */
+static void __init
+chrp_map_io(void)
+{
+	char *name;
+
+	/*
+	 * The code below tends to get removed, please don't take it out.
+	 * The F50 needs this mapping and it you take it out I'll track you
+	 * down and slap your hands.  If it causes problems please email me.
+	 *  -- Cort <cort@fsmlabs.com>
+	 */
+	name = get_property(find_path_device("/"), "name", NULL);
+	if (name && strncmp(name, "IBM-70", 6) == 0
+	    && strstr(name, "-F50")) {
+		io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
+		io_block_mapping(0x90000000, 0x90000000, 0x10000000, _PAGE_IO);
+		return;
+	} else {
+		io_block_mapping(0xf8000000, 0xf8000000, 0x04000000, _PAGE_IO);
+	}
+}
+
+void __init
+chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r6 )
+	{
+		initrd_start = r6 + KERNELBASE;
+		initrd_end = r6 + r7 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+	isa_io_base = CHRP_ISA_IO_BASE;		/* default value */
+
+	ppc_md.setup_arch     = chrp_setup_arch;
+	ppc_md.show_percpuinfo = of_show_percpuinfo;
+	ppc_md.show_cpuinfo   = chrp_show_cpuinfo;
+	ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
+#ifndef CONFIG_POWER4
+	ppc_md.init_IRQ       = chrp_init_IRQ;
+	ppc_md.get_irq        = openpic_get_irq;
+#else
+	ppc_md.init_IRQ	      = xics_init_IRQ;
+	ppc_md.get_irq	      = xics_get_irq;
+#endif /* CONFIG_POWER4 */
+
+	ppc_md.init           = chrp_init2;
+
+	ppc_md.restart        = chrp_restart;
+	ppc_md.power_off      = chrp_power_off;
+	ppc_md.halt           = chrp_halt;
+
+	ppc_md.time_init      = chrp_time_init;
+	ppc_md.set_rtc_time   = chrp_set_rtc_time;
+	ppc_md.get_rtc_time   = chrp_get_rtc_time;
+	ppc_md.calibrate_decr = chrp_calibrate_decr;
+
+	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
+	ppc_md.setup_io_mappings = chrp_map_io;
+
+#ifdef CONFIG_VT
+	/* these are adjusted in chrp_init2 if we have an ADB keyboard */
+	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 = 0x54;
+#endif /* CONFIG_MAGIC_SYSRQ */
+#endif /* CONFIG_VT */
+
+	if (rtas_data) {
+		struct device_node *rtas;
+		unsigned int *p;
+
+		rtas = find_devices("rtas");
+		if (rtas != NULL) {
+			if (get_property(rtas, "display-character", NULL)) {
+				ppc_md.progress = rtas_display_progress;
+				p = (unsigned int *) get_property
+				       (rtas, "ibm,display-line-length", NULL);
+				if (p)
+					max_width = *p;
+			} else if (get_property(rtas, "set-indicator", NULL))
+				ppc_md.progress = rtas_indicator_progress;
+		}
+	}
+#ifdef CONFIG_BOOTX_TEXT
+	if (ppc_md.progress == NULL && boot_text_mapped)
+		ppc_md.progress = btext_progress;
+#endif
+
+#ifdef CONFIG_SMP
+#ifndef CONFIG_POWER4
+	ppc_md.smp_ops = &chrp_smp_ops;
+#else
+	ppc_md.smp_ops = &xics_smp_ops;
+#endif /* CONFIG_POWER4 */
+#endif /* CONFIG_SMP */
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.ide_check_region = chrp_ide_check_region;
+        ppc_ide_md.ide_request_region = chrp_ide_request_region;
+        ppc_ide_md.ide_release_region = chrp_ide_release_region;
+        ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
+#endif
+
+	/*
+	 * Print the banner, then scroll down so boot progress
+	 * can be printed.  -- Cort 
+	 */
+	if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
+}
+
+void __chrp
+rtas_display_progress(char *s, unsigned short hex)
+{
+	int width;
+	char *os = s;
+
+	if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) )
+		return;
+
+	width = max_width;
+	while ( *os )
+	{
+		if ( (*os == '\n') || (*os == '\r') )
+			width = max_width;
+		else
+			width--;
+		call_rtas( "display-character", 1, 1, NULL, *os++ );
+		/* if we overwrite the screen length */
+		if ( width == 0 )
+			while ( (*os != 0) && (*os != '\n') && (*os != '\r') )
+				os++;
+	}
+
+	/*while ( width-- > 0 )*/
+	call_rtas( "display-character", 1, 1, NULL, ' ' );
+}
+
+void __chrp
+rtas_indicator_progress(char *s, unsigned short hex)
+{
+	call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex);
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+void
+btext_progress(char *s, unsigned short hex)
+{
+	prom_print(s);
+	prom_print("\n");
+}
+#endif /* CONFIG_BOOTX_TEXT */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/chrp_smp.c linux-2.4.20-pre2/arch/ppc/platforms/chrp_smp.c
--- linux-2.4.20-pre1/arch/ppc/platforms/chrp_smp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/chrp_smp.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,147 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Smp support for CHRP machines.
+ *
+ * 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>
+ *
+ */
+
+#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/spinlock.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/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/residual.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+
+extern unsigned long smp_chrp_cpu_nr;
+
+static int __init
+smp_chrp_probe(void)
+{
+	if (smp_chrp_cpu_nr > 1)
+		openpic_request_IPIs();
+
+	return smp_chrp_cpu_nr;
+}
+
+static void __init
+smp_chrp_kick_cpu(int nr)
+{
+	*(unsigned long *)KERNELBASE = nr;
+	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+}
+
+static void __init
+smp_chrp_setup_cpu(int cpu_nr)
+{
+	static atomic_t ready = ATOMIC_INIT(1);
+	static volatile int frozen = 0;
+
+	if (cpu_nr == 0) {
+		/* wait for all the others */
+		while (atomic_read(&ready) < smp_num_cpus)
+			barrier();
+		atomic_set(&ready, 1);
+		/* freeze the timebase */
+		call_rtas("freeze-time-base", 0, 1, NULL);
+		mb();
+		frozen = 1;
+		/* XXX assumes this is not a 601 */
+		set_tb(0, 0);
+		last_jiffy_stamp(0) = 0;
+		while (atomic_read(&ready) < smp_num_cpus)
+			barrier();
+		/* thaw the timebase again */
+		call_rtas("thaw-time-base", 0, 1, NULL);
+		mb();
+		frozen = 0;
+		smp_tb_synchronized = 1;
+	} else {
+		atomic_inc(&ready);
+		while (!frozen)
+			barrier();
+		set_tb(0, 0);
+		last_jiffy_stamp(0) = 0;
+		mb();
+		atomic_inc(&ready);
+		while (frozen)
+			barrier();
+	}
+
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+}
+
+#ifdef CONFIG_POWER4
+static void __chrp
+smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	/* for now, only do reschedule messages
+	   since we only have one IPI */
+	if (msg != PPC_MSG_RESCHEDULE)
+		return;
+	for (i = 0; i < smp_num_cpus; ++i) {
+		if (target == MSG_ALL || target == i
+		    || (target == MSG_ALL_BUT_SELF
+			&& i != smp_processor_id()))
+			xics_cause_IPI(i);
+	}
+}
+
+static int __chrp
+smp_xics_probe(void)
+{
+	return smp_chrp_cpu_nr;
+}
+
+static void __chrp
+smp_xics_setup_cpu(int cpu_nr)
+{
+	if (cpu_nr > 0)
+		xics_setup_cpu();
+}
+#endif /* CONFIG_POWER4 */
+
+/* CHRP with openpic */
+struct smp_ops_t chrp_smp_ops __chrpdata = {
+	smp_openpic_message_pass,
+	smp_chrp_probe,
+	smp_chrp_kick_cpu,
+	smp_chrp_setup_cpu,
+};
+
+#ifdef CONFIG_POWER4
+/* CHRP with new XICS interrupt controller */
+struct smp_ops_t xics_smp_ops __chrpdata = {
+	smp_xics_message_pass,
+	smp_xics_probe,
+	smp_chrp_kick_cpu,
+	smp_xics_setup_cpu,
+};
+#endif /* CONFIG_POWER4 */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/chrp_time.c linux-2.4.20-pre2/arch/ppc/platforms/chrp_time.c
--- linux-2.4.20-pre1/arch/ppc/platforms/chrp_time.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/chrp_time.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,195 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/chrp_time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * Adapted for PowerPC (PReP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu).
+ * Copied and modified from arch/i386/kernel/time.c
+ *
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/init.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+#include <asm/prom.h>
+#include <asm/sections.h>
+#include <asm/time.h>
+
+extern spinlock_t rtc_lock;
+
+static int nvram_as1 = NVRAM_AS1;
+static int nvram_as0 = NVRAM_AS0;
+static int nvram_data = NVRAM_DATA;
+
+long __init chrp_time_init(void)
+{
+	struct device_node *rtcs;
+	int base;
+
+	rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+	if (rtcs == NULL || rtcs->addrs == NULL)
+		return 0;
+	base = rtcs->addrs[0].address;
+	nvram_as1 = 0;
+	nvram_as0 = base;
+	nvram_data = base + 1;
+
+	return 0;
+}
+
+int __chrp chrp_cmos_clock_read(int addr)
+{
+	if (nvram_as1 != 0)
+		outb(addr>>8, nvram_as1);
+	outb(addr, nvram_as0);
+	return (inb(nvram_data));
+}
+
+void __chrp chrp_cmos_clock_write(unsigned long val, int addr)
+{
+	if (nvram_as1 != 0)
+		outb(addr>>8, nvram_as1);
+	outb(addr, nvram_as0);
+	outb(val, nvram_data);
+	return;
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+int __chrp chrp_set_rtc_time(unsigned long nowtime)
+{
+	unsigned char save_control, save_freq_select;
+	struct rtc_time tm;
+
+	spin_lock(&rtc_lock);
+	to_tm(nowtime, &tm);
+
+	save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
+
+	chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+	save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+
+	chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+        tm.tm_year -= 1900;
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(tm.tm_sec);
+		BIN_TO_BCD(tm.tm_min);
+		BIN_TO_BCD(tm.tm_hour);
+		BIN_TO_BCD(tm.tm_mon);
+		BIN_TO_BCD(tm.tm_mday);
+		BIN_TO_BCD(tm.tm_year);
+	}
+	chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+	chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+	chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+	chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+	chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+	chrp_cmos_clock_write(tm.tm_year,RTC_YEAR);
+
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	chrp_cmos_clock_write(save_control, RTC_CONTROL);
+	chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+
+	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+		time_state = TIME_OK;
+	spin_unlock(&rtc_lock);
+	return 0;
+}
+
+unsigned long __chrp chrp_get_rtc_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	int uip, i;
+
+	/* The Linux interpretation of the CMOS clock register contents:
+	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+	 * RTC registers show the second which has precisely just started.
+	 * Let's hope other operating systems interpret the RTC the same way.
+	 */
+
+	/* Since the UIP flag is set for about 2.2 ms and the clock
+	 * is typically written with a precision of 1 jiffy, trying
+	 * to obtain a precision better than a few milliseconds is 
+	 * an illusion. Only consistency is interesting, this also
+	 * allows to use the routine for /dev/rtc without a potential
+	 * 1 second kernel busy loop triggered by any reader of /dev/rtc. 
+	 */
+
+	for ( i = 0; i<1000000; i++) {
+		uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
+		sec = chrp_cmos_clock_read(RTC_SECONDS);
+		min = chrp_cmos_clock_read(RTC_MINUTES);
+		hour = chrp_cmos_clock_read(RTC_HOURS);
+		day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
+		mon = chrp_cmos_clock_read(RTC_MONTH);
+		year = chrp_cmos_clock_read(RTC_YEAR);
+		uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
+		if ((uip & RTC_UIP)==0) break;
+	}
+
+	if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+	  {
+	    BCD_TO_BIN(sec);
+	    BCD_TO_BIN(min);
+	    BCD_TO_BIN(hour);
+	    BCD_TO_BIN(day);
+	    BCD_TO_BIN(mon);
+	    BCD_TO_BIN(year);
+	  }
+	if ((year += 1900) < 1970)
+		year += 100;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+
+void __init chrp_calibrate_decr(void)
+{
+	struct device_node *cpu;
+	unsigned int freq, *fp;
+
+	if (via_calibrate_decr())
+		return;
+
+	/*
+	 * 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 = (unsigned int *)
+			get_property(cpu, "timebase-frequency", NULL);
+		if (fp != 0)
+			freq = *fp;
+	}
+	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
+ 	       freq/1000000, freq%1000000);
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/error_log.c linux-2.4.20-pre2/arch/ppc/platforms/error_log.c
--- linux-2.4.20-pre1/arch/ppc/platforms/error_log.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/error_log.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,186 @@
+/*
+ * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort
+ */
+/*
+ *  arch/ppc/kernel/error_log.c
+ *  
+ *  Copyright (c) 2000 Tilmann Bitterberg
+ *  (tilmann@bitterberg.de)
+ *
+ *  Error processing of errors found by rtas even-scan routine
+ *  which is done with every heartbeat. (chrp_setup.c)
+ */
+
+#include <linux/sched.h>
+
+#include <asm/prom.h>
+
+#include "error_log.h"
+
+/* ****************************************************************** */
+/* 
+ * EVENT-SCAN
+ * The whole stuff below here doesn't take any action when it found
+ * an error, it just prints as much information as possible and 
+ * then its up to the user to decide what to do.
+ *
+ * Returns 0 if no errors were found
+ * Returns 1 if there may be more errors
+ */
+int ppc_rtas_errorlog_scan(void)
+{
+const char *_errlog_severity[] = {
+#ifdef VERBOSE_ERRORS
+	"No Error\n\t\
+Should require no further information",
+	"Event\n\t\
+This is not really an error, it is an event. I use events\n\t\
+to communicate with RTAS back and forth.",
+	"Warning\n\t\
+Indicates a non-state-losing error, either fully recovered\n\t\
+by RTAS or not needing recovery. Ignore it.",
+	"Error sync\n\t\
+May only be fatal to a certain program or thread. Recovery\n\t\
+and continuation is possible, if I only had a handler for\n\t\
+this. Less serious",
+	"Error\n\t\
+Less serious, but still causing a loss of data and state.\n\t\
+I can't tell you exactly what to do, You have to decide\n\t\
+with help from the target and initiator field, what kind\n\t\
+of further actions may take place.",
+	"Fatal\n\t\
+Represent a permanent hardware failure and I believe this\n\t\
+affects my overall performance and behaviour. I would not\n\t\
+attempt to continue normal operation."
+#else
+	"No Error",
+	"Event",
+	"Warning",
+	"Error sync",
+	"Error",
+	"Fatal"
+#endif /* VERBOSE_ERRORS */
+};
+
+#if 0 /* unused?? */
+const char *_errlog_disposition[] = {
+#ifdef VERBOSE_ERRORS
+	"Fully recovered\n\t\
+There was an error, but it is fully recovered by RTAS.",
+	"Limited recovery\n\t\
+RTAS was able to recover the state of the machine, but some\n\t\
+feature of the machine has been disabled or lost (for example\n\t\
+error checking) or performance may suffer.",
+	"Not recovered\n\t\
+Whether RTAS did not try to recover anything or recovery failed:\n\t\
+HOUSTON, WE HAVE A PROBLEM!"
+#else
+	"Fully recovered",
+	"Limited recovery",
+	"Not recovered"
+#endif /* VERBOSE_ERRORS */
+};
+#endif
+
+const char *_errlog_extended[] = {
+#ifdef VERBOSE_ERRORS
+	"Not present\n\t\
+Sad, the RTAS call didn't return an extended error log.",
+	"Present\n\t\
+The extended log is present and hopefully it contains a lot of\n\t\
+useful information, which leads to the solution of the problem."
+#else
+	"Not present",
+	"Present"
+#endif /* VERBOSE_ERRORS */
+};
+
+const char *_errlog_initiator[] = { 
+	"Unknown or not applicable",
+	"CPU",
+	"PCI",
+	"ISA",
+	"Memory",
+	"Power management"
+};
+
+const char *_errlog_target[] = { 
+	"Unknown or not applicable",
+	"CPU",
+	"PCI",
+	"ISA",
+	"Memory",
+	"Power management"
+};
+	rtas_error_log error_log;
+	char logdata[1024];
+	int error;
+#if 0 /* unused?? */
+	int retries = 0; /* if HW error, try 10 times */
+#endif
+
+	error = call_rtas ("event-scan", 4, 1, (unsigned long *)&error_log,
+			INTERNAL_ERROR | EPOW_WARNING,
+			0, __pa(logdata), 1024);
+
+	if (error == 1) /* no errors found */
+		return 0;
+
+	if (error == -1) {
+		printk(KERN_ERR "Unable to get errors. Do you a favor and throw this box away\n");
+		return 0;
+	}
+	if (error_log.version != 1)
+		printk(KERN_WARNING "Unknown version (%d), please implement me\n", 
+				error_log.version);
+
+	switch (error_log.disposition) {
+		case DISP_FULLY_RECOVERED:
+			/* there was an error, but everything is fine now */
+			return 0;
+		case DISP_NOT_RECOVERED:
+			printk("We have a really serious Problem!\n");
+		case DISP_LIMITED_RECOVERY:
+			printk("Error classification\n");
+			printk("Severity  : %s\n", 
+					ppc_rtas_errorlog_check_severity (error_log));
+			printk("Initiator : %s\n", 
+					ppc_rtas_errorlog_check_initiator (error_log));
+			printk("Target    : %s\n", 
+					ppc_rtas_errorlog_check_target (error_log));
+			printk("Type      : %s\n", 
+					ppc_rtas_errorlog_check_type (error_log));
+			printk("Ext. log  : %s\n", 
+					ppc_rtas_errorlog_check_extended (error_log));
+			if (error_log.extended)
+				ppc_rtas_errorlog_disect_extended (logdata);
+			return 1;	
+		default:
+			/* nothing */
+			break;
+	}
+	return 0;
+}
+/* ****************************************************************** */
+const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log)
+{
+	const char *_errlog_type[] = {
+		"unknown type",
+		"too many tries failed",
+		"TCE error",
+		"RTAS device failed",
+		"target timed out",
+		"parity error on data",			/* 5 */
+		"parity error on address",
+		"parity error on external cache",
+		"access to invalid address",
+		"uncorrectable ECC error",
+		"corrected ECC error"			/* 10 */
+	};
+	if (error_log.type == TYPE_EPOW) 
+		return "EPOW"; 
+	if (error_log.type >= TYPE_PMGM_POWER_SW_ON)
+		return "PowerMGM Event (not handled right now)";
+	return _errlog_type[error_log.type];
+}
+
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/error_log.h linux-2.4.20-pre2/arch/ppc/platforms/error_log.h
--- linux-2.4.20-pre1/arch/ppc/platforms/error_log.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/error_log.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,98 @@
+/*
+ * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort
+ */
+#ifndef __ERROR_LOG_H__
+#define __ERROR_LOG_H__
+
+#define VERBOSE_ERRORS		1 /* Maybe I enlarge the kernel too much */
+#undef VERBOSE_ERRORS
+
+/* Event classes */
+/* XXX: Endianess correct? NOW*/
+#define INTERNAL_ERROR		0x80000000 /* set bit 0 */
+#define EPOW_WARNING		0x40000000 /* set bit 1 */
+#define POWERMGM_EVENTS		0x20000000 /* set bit 2 */
+
+/* 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
+
+typedef 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 */
+} rtas_error_log;
+
+/* ****************************************************************** */
+#define ppc_rtas_errorlog_check_severity(x) \
+	(_errlog_severity[x.severity])
+#define ppc_rtas_errorlog_check_target(x) \
+	(_errlog_target[x.target])
+#define ppc_rtas_errorlog_check_initiator(x) \
+	(_errlog_initiator[x.initiator])
+#define ppc_rtas_errorlog_check_extended(x) \
+	(_errlog_extended[x.extended])
+#define ppc_rtas_errorlog_disect_extended(x) \
+	do { /* implement me */ } while(0)
+extern const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log);
+extern int ppc_rtas_errorlog_scan(void);
+
+
+#endif /* __ERROR_LOG_H__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/est8260.h linux-2.4.20-pre2/arch/ppc/platforms/est8260.h
--- linux-2.4.20-pre1/arch/ppc/platforms/est8260.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/est8260.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,31 @@
+/*
+ * BK Id: SCCS/s.est8260.h 1.5 05/17/01 18:14:24 cort
+ */
+
+/* Board information for the EST8260, which should be generic for
+ * all 8260 boards.  The IMMR is now given to us so the hard define
+ * will soon be removed.  All of the clock values are computed from
+ * the configuration SCMR and the Power-On-Reset word.
+ */
+
+#define IMAP_ADDR	((uint)0xf0000000)
+
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in MHz */
+	unsigned int	bi_cpmfreq;	/* CPM Freq, in MHz */
+	unsigned int	bi_brgfreq;	/* BRG Freq, in MHz */
+	unsigned int	bi_vco;		/* VCO Out from PLL */
+	unsigned int	bi_baudrate;	/* Default console baud rate */
+	unsigned int	bi_immr;	/* IMMR when called from boot rom */
+	unsigned char	bi_enetaddr[6];
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/fads.h linux-2.4.20-pre2/arch/ppc/platforms/fads.h
--- linux-2.4.20-pre1/arch/ppc/platforms/fads.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/fads.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,61 @@
+/*
+ * BK Id: SCCS/s.fads.h 1.14 10/26/01 10:14:09 trini
+ */
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Motorola 860T FADS board.  Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_FADS_H__
+#define __ASM_FADS_H__
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+/* Memory map is configured by the PROM startup.
+ * I tried to follow the FADS manual, although the startup PROM
+ * dictates this and we simply have to move some of the physical
+ * addresses for Linux.
+ */
+#define BCSR_ADDR		((uint)0xff010000)
+#define BCSR_SIZE		((uint)(64 * 1024))
+#define	BCSR0			((uint)0xff010000)
+#define	BCSR1			((uint)0xff010004)
+#define	BCSR2			((uint)0xff010008)
+#define	BCSR3			((uint)0xff01000c)
+#define	BCSR4			((uint)0xff010010)
+
+#define IMAP_ADDR		((uint)0xff000000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+
+#define PCMCIA_MEM_ADDR		((uint)0xff020000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+
+/* Bits of interest in the BCSRs.
+ */
+#define BCSR1_ETHEN		((uint)0x20000000)
+#define BCSR1_RS232EN_1		((uint)0x01000000)
+#define BCSR1_RS232EN_2		((uint)0x00040000)
+#define BCSR4_ETHLOOP		((uint)0x80000000)	/* EEST Loopback */
+#define BCSR4_EEFDX		((uint)0x40000000)	/* EEST FDX enable */
+#define BCSR4_FETH_EN		((uint)0x08000000)	/* PHY enable */
+#define BCSR4_FETHCFG0		((uint)0x04000000)	/* PHY autoneg mode */
+#define BCSR4_FETHCFG1		((uint)0x00400000)	/* PHY autoneg mode */
+#define BCSR4_FETHFDE		((uint)0x02000000)	/* PHY FDX advertise */
+#define BCSR4_FETHRST		((uint)0x00200000)	/* PHY Reset */
+
+/* Interrupt level assignments.
+ */
+#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
+#define PHY_INTERRUPT	SIU_IRQ2	/* PHY link change interrupt */
+
+/* We don't use the 8259.
+ */
+#define NR_8259_INTS	0
+
+#endif /* __ASM_FADS_H__ */
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/gemini.h linux-2.4.20-pre2/arch/ppc/platforms/gemini.h
--- linux-2.4.20-pre1/arch/ppc/platforms/gemini.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/gemini.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,171 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  include/asm-ppc/platforms/gemini.h
+ *
+ *
+ *  Onboard registers and descriptions for Synergy Microsystems' 
+ *  "Gemini" boards.
+ *
+ */
+#ifdef __KERNEL__
+#ifndef __PPC_GEMINI_H
+#define __PPC_GEMINI_H
+
+/*  Registers  */
+
+#define GEMINI_SERIAL_B     (0xffeffb00)
+#define GEMINI_SERIAL_A     (0xffeffb08)
+#define GEMINI_USWITCH      (0xffeffd00)
+#define GEMINI_BREV         (0xffeffe00)
+#define GEMINI_BECO         (0xffeffe08)
+#define GEMINI_FEAT         (0xffeffe10)
+#define GEMINI_BSTAT        (0xffeffe18)
+#define GEMINI_CPUSTAT      (0xffeffe20)
+#define GEMINI_L2CFG        (0xffeffe30)
+#define GEMINI_MEMCFG       (0xffeffe38)
+#define GEMINI_FLROM        (0xffeffe40)
+#define GEMINI_P0PCI        (0xffeffe48)
+#define GEMINI_FLWIN        (0xffeffe50)
+#define GEMINI_P0INTMASK    (0xffeffe60)
+#define GEMINI_P0INTAP      (0xffeffe68)
+#define GEMINI_PCIERR       (0xffeffe70)
+#define GEMINI_LEDBASE      (0xffeffe80)
+#define GEMINI_RTC          (0xffe9fff8)
+#define GEMINI_LEDS         8
+#define GEMINI_SWITCHES     8
+
+
+/* Flash ROM bit definitions */
+#define GEMINI_FLS_WEN      (1<<0)
+#define GEMINI_FLS_JMP      (1<<6)
+#define GEMINI_FLS_BOOT     (1<<7)
+
+/* Memory bit definitions */
+#define GEMINI_MEM_TYPE_MASK 0xc0
+#define GEMINI_MEM_SIZE_MASK 0x38
+#define GEMINI_MEM_BANK_MASK 0x07
+
+/* L2 cache bit definitions */
+#define GEMINI_L2_SIZE_MASK  0xc0
+#define GEMINI_L2_RATIO_MASK 0x03
+
+/* Timebase register bit definitons */
+#define GEMINI_TIMEB0_EN     (1<<0)
+#define GEMINI_TIMEB1_EN     (1<<1)
+#define GEMINI_TIMEB2_EN     (1<<2)
+#define GEMINI_TIMEB3_EN     (1<<3)
+
+/* CPU status bit definitions */
+#define GEMINI_CPU_ID_MASK   0x03
+#define GEMINI_CPU_COUNT_MASK 0x0c
+#define GEMINI_CPU0_HALTED   (1<<4)
+#define GEMINI_CPU1_HALTED   (1<<5)
+#define GEMINI_CPU2_HALTED   (1<<6)
+#define GEMINI_CPU3_HALTED   (1<<7)
+
+/* Board status bit definitions */
+#define GEMINI_BRD_FAIL      (1<<0)   /* FAIL led is lit */
+#define GEMINI_BRD_BUS_MASK  0x0c     /* PowerPC bus speed */
+
+/* Board family/feature bit descriptions */
+#define GEMINI_FEAT_HAS_FLASH (1<<0)
+#define GEMINI_FEAT_HAS_ETH   (1<<1)
+#define GEMINI_FEAT_HAS_SCSI  (1<<2)
+#define GEMINI_FEAT_HAS_P0    (1<<3)
+#define GEMINI_FEAT_FAM_MASK  0xf0
+
+/* Mod/ECO bit definitions */
+#define GEMINI_ECO_LEVEL_MASK 0x0f
+#define GEMINI_MOD_MASK       0xf0
+
+/* Type/revision bit definitions */
+#define GEMINI_REV_MASK       0x0f
+#define GEMINI_TYPE_MASK      0xf0
+
+/* User switch definitions */
+#define GEMINI_SWITCH_VERBOSE    1     /* adds "debug" to boot cmd line */
+#define GEMINI_SWITCH_SINGLE_USER 7    /* boots into "single-user" mode */
+
+#define SGS_RTC_CONTROL  0
+#define SGS_RTC_SECONDS  1
+#define SGS_RTC_MINUTES  2
+#define SGS_RTC_HOURS    3
+#define SGS_RTC_DAY      4
+#define SGS_RTC_DAY_OF_MONTH 5
+#define SGS_RTC_MONTH    6
+#define SGS_RTC_YEAR     7
+
+#define SGS_RTC_SET  0x80
+#define SGS_RTC_IS_STOPPED 0x80
+
+#define GRACKLE_CONFIG_ADDR_ADDR  (0xfec00000)
+#define GRACKLE_CONFIG_DATA_ADDR  (0xfee00000)
+
+#define GEMINI_BOOT_INIT  (0xfff00100)
+
+#ifndef __ASSEMBLY__
+
+static inline void grackle_write( unsigned long addr, unsigned long data )
+{
+  __asm__ __volatile__(
+  " stwbrx %1, 0, %0\n \
+    sync\n \
+    stwbrx %3, 0, %2\n \
+    sync "
+  : /* no output */
+  : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr),
+    "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data));
+}
+
+static inline unsigned long grackle_read( unsigned long addr )
+{
+  unsigned long val;
+
+  __asm__ __volatile__(
+  " stwbrx %1, 0, %2\n \
+    sync\n \
+    lwbrx %0, 0, %3\n \
+    sync "
+  : "=r" (val)
+  : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR),
+    "r" (GRACKLE_CONFIG_DATA_ADDR));
+
+  return val;
+}
+
+static inline void gemini_led_on( int led )
+{
+  if (led >= 0 && led < GEMINI_LEDS)
+    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1;
+}
+
+static inline void gemini_led_off(int led)
+{
+  if (led >= 0 && led < GEMINI_LEDS)
+    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0;
+}
+
+static inline int gemini_led_val(int led)
+{
+  int val = 0;
+  if (led >= 0 && led < GEMINI_LEDS)
+    val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3));
+  return (val & 0x1);
+}
+
+/* returns processor id from the board */
+static inline int gemini_processor(void)
+{
+  unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT);
+  return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK));
+}
+
+
+extern void _gemini_reboot(void);
+extern void gemini_prom_init(void);
+extern void gemini_init_l2(void);
+#endif /* __ASSEMBLY__ */
+#endif
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/gemini_pci.c linux-2.4.20-pre2/arch/ppc/platforms/gemini_pci.c
--- linux-2.4.20-pre1/arch/ppc/platforms/gemini_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/gemini_pci.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,122 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/machdep.h>
+#include <platforms/gemini.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pci-bridge.h>
+
+#define pci_config_addr(bus,dev,offset) \
+        (0x80000000 | (bus<<16) | (dev<<8) | offset)
+
+
+int
+gemini_pcibios_read_config_byte(struct pci_dev *dev, int offset, u8 *val)
+{
+	unsigned long reg;
+	reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
+					   (offset & ~(0x3))));
+	*val = ((reg >> ((offset & 0x3) << 3)) & 0xff);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_read_config_word(struct pci_dev *dev, int offset, u16 *val)
+{
+	unsigned long reg;
+	reg = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
+					   (offset & ~(0x3))));
+	*val = ((reg >> ((offset & 0x3) << 3)) & 0xffff);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_read_config_dword(struct pci_dev *dev, int offset, u32 *val)
+{
+	*val = grackle_read(pci_config_addr(dev->bus->number, dev->devfn,
+					    (offset & ~(0x3))));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_byte(struct pci_dev *dev, int offset, u8 val)
+{
+	unsigned long reg;
+	int shifts = offset & 0x3;
+	unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn,
+					    (offset & ~(0x3)));
+
+	reg = grackle_read(addr);
+	reg = (reg & ~(0xff << (shifts << 3))) | (val << (shifts << 3));
+	grackle_write(addr, reg );
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_word(struct pci_dev *dev, int offset, u16 val)
+{
+	unsigned long reg;
+	int shifts = offset & 0x3;
+	unsigned int addr = pci_config_addr(dev->bus->number, dev->devfn,
+					    (offset & ~(0x3)));
+
+	reg = grackle_read(addr);
+	reg = (reg & ~(0xffff << (shifts << 3))) | (val << (shifts << 3));
+	grackle_write(addr, reg );
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int
+gemini_pcibios_write_config_dword(struct pci_dev *dev, int offset, u32 val)
+{
+	grackle_write(pci_config_addr(dev->bus->number, dev->devfn,
+				      (offset & ~(0x3))), val);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops gemini_pci_ops =
+{
+	gemini_pcibios_read_config_byte,
+	gemini_pcibios_read_config_word,
+	gemini_pcibios_read_config_dword,
+	gemini_pcibios_write_config_byte,
+	gemini_pcibios_write_config_word,
+	gemini_pcibios_write_config_dword
+};
+
+void __init gemini_pcibios_fixup(void)
+{
+	int i;
+	struct pci_dev *dev;
+	
+	pci_for_each_dev(dev) {
+		for(i = 0; i < 6; i++) {
+			if (dev->resource[i].flags & IORESOURCE_IO) {
+				dev->resource[i].start |= (0xfe << 24);
+				dev->resource[i].end |= (0xfe << 24);
+			}
+		}
+	}
+}
+
+
+/* The "bootloader" for Synergy boards does none of this for us, so we need to
+   lay it all out ourselves... --Dan */
+void __init gemini_find_bridges(void)
+{
+	struct pci_controller* hose;
+	
+	ppc_md.pcibios_fixup = gemini_pcibios_fixup;
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+	hose->ops = &gemini_pci_ops;
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/gemini_prom.S linux-2.4.20-pre2/arch/ppc/platforms/gemini_prom.S
--- linux-2.4.20-pre1/arch/ppc/platforms/gemini_prom.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/gemini_prom.S	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,98 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/kernel/gemini_prom.S
+ *
+ *  Not really prom support code (yet), but sort of anti-prom code.  The current
+ *  bootloader does a number of things it shouldn't and doesn't do things that it
+ *  should.  The stuff in here is mainly a hodge-podge collection of setup code
+ *  to get the board up and running.
+ *    ---Dan
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <platforms/gemini.h>
+#include <asm/ppc_asm.h>
+
+#define HID0_ABE (1<<3)
+
+/*
+ *  On 750's the MMU is on when Linux is booted, so we need to clear out the
+ *  bootloader's BAT settings, make sure we're in supervisor state (gotcha!),
+ *  and turn off the MMU.
+ *
+ */
+
+_GLOBAL(gemini_prom_init)
+#ifdef CONFIG_SMP
+	/* Since the MMU's on, get stuff in rom space that we'll need */
+	lis	r4,GEMINI_CPUSTAT@h
+	ori	r4,r4,GEMINI_CPUSTAT@l
+	lbz	r5,0(r4)
+	andi.	r5,r5,3
+	mr	r24,r5		/* cpu # used later on */
+#endif
+	mfmsr	r4
+	li	r3,MSR_PR	/* ensure supervisor! */
+	ori	r3,r3,MSR_IR|MSR_DR
+	andc	r4,r4,r3
+	mtmsr	r4
+	isync
+#if 0
+	/* zero out the bats now that the MMU is off */
+prom_no_mmu:	
+	li	r3,0
+        mtspr   IBAT0U,r3
+        mtspr   IBAT0L,r3
+        mtspr   IBAT1U,r3
+        mtspr   IBAT1L,r3
+        mtspr   IBAT2U,r3
+        mtspr   IBAT2L,r3
+        mtspr   IBAT3U,r3
+        mtspr   IBAT3L,r3
+
+        mtspr   DBAT0U,r3
+        mtspr   DBAT0L,r3
+        mtspr   DBAT1U,r3
+        mtspr   DBAT1L,r3
+        mtspr   DBAT2U,r3
+	mtspr   DBAT2L,r3
+        mtspr   DBAT3U,r3
+        mtspr   DBAT3L,r3
+#endif
+
+	/* the bootloader (as far as I'm currently aware) doesn't mess with page
+	   tables, but since we're already here, might as well zap these, too */
+	li	r4,0
+	mtspr	SDR1,r4
+
+	li	r4,16
+	mtctr	r4
+	li	r3,0
+	li	r4,0
+3:	mtsrin	r3,r4
+	addi	r3,r3,1
+	bdnz	3b
+
+#ifdef CONFIG_SMP
+	/* The 750 book (and Mot/IBM support) says that this will "assist" snooping
+	   when in SMP.  Not sure yet whether this should stay or leave... */
+	mfspr	r4,HID0
+	ori	r4,r4,HID0_ABE
+	mtspr	HID0,r4
+	sync
+#endif /* CONFIG_SMP */
+	blr
+
+/*  apparently, SMon doesn't pay attention to HID0[SRST].  Disable the MMU and
+    branch to 0xfff00100 */
+_GLOBAL(_gemini_reboot)
+	lis	r5,GEMINI_BOOT_INIT@h
+	ori	r5,r5,GEMINI_BOOT_INIT@l
+	li	r6,MSR_IP
+	mtspr	SRR0,r5
+	mtspr	SRR1,r6
+	rfi
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/gemini_serial.h linux-2.4.20-pre2/arch/ppc/platforms/gemini_serial.h
--- linux-2.4.20-pre1/arch/ppc/platforms/gemini_serial.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/gemini_serial.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,44 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+#ifdef __KERNEL__
+#ifndef __ASMPPC_GEMINI_SERIAL_H
+#define __ASMPPC_GEMINI_SERIAL_H
+
+#include <linux/config.h>
+#include <platforms/gemini.h>
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  4
+#endif
+
+/* Rate for the 24.576 Mhz clock for the onboard serial chip */
+#define BASE_BAUD  (24576000 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define STD_SERIAL_PORT_DEFNS \
+        { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \
+        { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \
+
+#ifdef CONFIG_GEMINI_PU32
+#define PU32_SERIAL_PORT_DEFNS \
+        { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS },
+#else
+#define PU32_SERIAL_PORT_DEFNS
+#endif
+
+#define SERIAL_PORT_DFNS \
+        STD_SERIAL_PORT_DEFNS \
+        PU32_SERIAL_PORT_DEFNS
+
+#endif
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/gemini_setup.c linux-2.4.20-pre2/arch/ppc/platforms/gemini_setup.c
--- linux-2.4.20-pre1/arch/ppc/platforms/gemini_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/gemini_setup.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,584 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/setup.c
+ *
+ *  Copyright (C) 1995 Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Synergy Microsystems board support by Dan Cox (dan@synergymicro.com)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/m48t35.h>
+#include <platforms/gemini.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+
+void gemini_find_bridges(void);
+static int gemini_get_clock_speed(void);
+extern void gemini_pcibios_fixup(void);
+
+static char *gemini_board_families[] = {
+  "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR"
+};
+static int gemini_board_count = sizeof(gemini_board_families) /
+                                 sizeof(gemini_board_families[0]);
+
+static unsigned int cpu_7xx[16] = {
+	0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
+};
+static unsigned int cpu_6xx[16] = {
+	0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
+};
+
+/*
+ * prom_init is the Gemini version of prom.c:prom_init.  We only need
+ * the BSS clearing code, so I copied that out of prom.c.  This is a
+ * lot simpler than hacking prom.c so it will build with Gemini. -VAL
+ */
+
+#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
+
+unsigned long
+prom_init(void)
+{
+	unsigned long offset = reloc_offset();
+	unsigned long phys;
+	extern char __bss_start, _end;
+
+	/* First zero the BSS -- use memset, some arches don't have
+	 * caches on yet */
+	memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start);
+
+ 	/* Default */
+ 	phys = offset + KERNELBASE;
+
+	gemini_prom_init();
+
+	return phys;
+}
+
+int
+gemini_show_cpuinfo(struct seq_file *m)
+{
+	unsigned char reg, rev;
+	char *family;
+	unsigned int type;
+
+	reg = readb(GEMINI_FEAT);
+	family = gemini_board_families[((reg>>4) & 0xf)];
+	if (((reg>>4) & 0xf) > gemini_board_count)
+		printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
+
+	reg = readb(GEMINI_BREV);
+	type = (reg>>4) & 0xf;
+	rev = reg & 0xf;
+
+	reg = readb(GEMINI_BECO);
+
+	seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n", 
+		   family, type, (rev + 'A'), (reg & 0xf));
+
+	seq_printf(m, "board\t\t: Gemini %s", family);
+	if (type > 9)
+		seq_printf(m, "%c", (type - 10) + 'A');
+	else
+		seq_printf(m, "%d", type);
+
+	seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf));
+
+	seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed());
+
+	return 0;
+}
+
+static u_char gemini_openpic_initsenses[] = {
+	1,
+	1,
+	1,
+	1,
+	0,
+	0,
+	1, /* remainder are level-triggered */
+};
+
+#define GEMINI_MPIC_ADDR (0xfcfc0000)
+#define GEMINI_MPIC_PCI_CFG (0x80005800)
+
+void __init gemini_openpic_init(void)
+{
+
+	OpenPIC_Addr = (volatile struct OpenPIC *)
+		grackle_read(GEMINI_MPIC_PCI_CFG + 0x10);
+	OpenPIC_InitSenses = gemini_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
+
+	ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE);
+}
+
+
+extern unsigned long loops_per_jiffy;
+extern int root_mountflags;
+extern char cmd_line[];
+
+void
+gemini_heartbeat(void)
+{
+	static unsigned long led = GEMINI_LEDBASE+(4*8);
+	static char direction = 8;
+
+	/* We only want to do this on 1 CPU */
+	if (smp_processor_id())
+		return;
+	*(char *)led = 0;
+	if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) ||
+	     (led + direction) < (GEMINI_LEDBASE+(4*8)) )
+		direction *= -1;
+	led += direction;
+	*(char *)led = 0xff;
+	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+}
+
+void __init gemini_setup_arch(void)
+{
+	extern char cmd_line[];
+
+
+	loops_per_jiffy = 50000000/HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* bootable off CDROM */
+	if (initrd_start)
+		ROOT_DEV = MKDEV(SCSI_CDROM_MAJOR, 0);
+	else
+#endif
+		ROOT_DEV = to_kdev_t(0x0801);
+
+	/* nothing but serial consoles... */
+	sprintf(cmd_line, "%s console=ttyS0", cmd_line);
+
+	printk("Boot arguments: %s\n", cmd_line);
+
+	ppc_md.heartbeat = gemini_heartbeat;
+	ppc_md.heartbeat_reset = HZ/8;
+	ppc_md.heartbeat_count = 1;
+
+	/* Lookup PCI hosts */
+	gemini_find_bridges();
+	/* take special pains to map the MPIC, since it isn't mapped yet */
+	gemini_openpic_init();
+	/* start the L2 */
+	gemini_init_l2();
+}
+
+
+int
+gemini_get_clock_speed(void)
+{
+	unsigned long hid1, pvr;
+	int clock;
+
+	pvr = mfspr(PVR);
+	hid1 = (mfspr(HID1) >> 28) & 0xf;
+	if (PVR_VER(pvr) == 8 ||
+	    PVR_VER(pvr) == 12)
+		hid1 = cpu_7xx[hid1];
+	else
+		hid1 = cpu_6xx[hid1];
+
+	switch((readb(GEMINI_BSTAT) & 0xc) >> 2) {
+
+	case 0:
+	default:
+		clock = (hid1*100)/3;
+		break;
+
+	case 1:
+		clock = (hid1*125)/3;
+		break;
+
+	case 2:
+		clock = (hid1*50);
+		break;
+	}
+
+	return clock;
+}
+
+void __init gemini_init_l2(void)
+{
+        unsigned char reg, brev, fam, creg;
+        unsigned long cache;
+        unsigned long pvr;
+
+        reg = readb(GEMINI_L2CFG);
+        brev = readb(GEMINI_BREV);
+        fam = readb(GEMINI_FEAT);
+        pvr = mfspr(PVR);
+
+        switch(PVR_VER(pvr)) {
+
+        case 8:
+                if (reg & 0xc0)
+                        cache = (((reg >> 6) & 0x3) << 28);
+                else
+                        cache = 0x3 << 28;
+
+#ifdef CONFIG_SMP
+                /* Pre-3.0 processor revs had snooping errata.  Leave
+                   their L2's disabled with SMP. -- Dan */
+                if (PVR_CFG(pvr) < 3) {
+                        printk("Pre-3.0 750; L2 left disabled!\n");
+                        return;
+                }
+#endif /* CONFIG_SMP */
+
+                /* Special case: VGM5-B's came before L2 ratios were set on
+                   the board.  Processor speed shouldn't be too high, so
+                   set L2 ratio to 1:1.5.  */
+                if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0)
+                        reg |= 1;
+
+                /* determine best cache ratio based upon what the board
+                   tells us (which sometimes _may_ not be true) and
+                   the processor speed. */
+                else {
+                        if (gemini_get_clock_speed() > 250)
+                                reg = 2;
+                }
+                break;
+        case 12:
+	{
+		static unsigned long l2_size_val = 0;
+
+		if (!l2_size_val)
+			l2_size_val = _get_L2CR();
+		cache = l2_size_val;
+                break;
+	}
+        case 4:
+        case 9:
+                creg = readb(GEMINI_CPUSTAT);
+                if (((creg & 0xc) >> 2) != 1)
+                        printk("Dual-604 boards don't support the use of L2\n");
+                else
+                        writeb(1, GEMINI_L2CFG);
+                return;
+        default:
+                printk("Unknown processor; L2 left disabled\n");
+                return;
+        }
+
+        cache |= ((1<<reg) << 25);
+        cache |= (L2CR_L2RAM_MASK|L2CR_L2CTL|L2CR_L2DO);
+        _set_L2CR(0);
+        _set_L2CR(cache | L2CR_L2E);
+
+}
+
+void
+gemini_restart(char *cmd)
+{
+	__cli();
+	/* make a clean restart, not via the MPIC */
+	_gemini_reboot();
+	for(;;);
+}
+
+void
+gemini_power_off(void)
+{
+	for(;;);
+}
+
+void
+gemini_halt(void)
+{
+	gemini_restart(NULL);
+}
+
+void __init gemini_init_IRQ(void)
+{
+	/* gemini has no 8259 */
+	openpic_init(1, 0, 0, -1);
+}
+
+#define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
+#define gemini_rtc_write(val,x)  (writeb((val),(GEMINI_RTC+(x))))
+
+/* ensure that the RTC is up and running */
+long __init gemini_time_init(void)
+{
+	unsigned char reg;
+
+	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+
+	if ( reg & M48T35_RTC_STOPPED ) {
+		printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n");
+		gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
+		gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
+	}
+	return 0;
+}
+
+#undef DEBUG_RTC
+
+unsigned long
+gemini_get_rtc_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	unsigned char reg;
+
+	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+	gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL);
+#ifdef DEBUG_RTC
+	printk("get rtc: reg = %x\n", reg);
+#endif
+
+	do {
+		sec = gemini_rtc_read(M48T35_RTC_SECONDS);
+		min = gemini_rtc_read(M48T35_RTC_MINUTES);
+		hour = gemini_rtc_read(M48T35_RTC_HOURS);
+		day = gemini_rtc_read(M48T35_RTC_DOM);
+		mon = gemini_rtc_read(M48T35_RTC_MONTH);
+		year = gemini_rtc_read(M48T35_RTC_YEAR);
+	} while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
+#ifdef DEBUG_RTC
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	       sec, min, hour, day, mon, year);
+#endif
+
+	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+
+	if ((year += 1900) < 1970)
+		year += 100;
+#ifdef DEBUG_RTC
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	       sec, min, hour, day, mon, year);
+#endif
+
+	return mktime( year, mon, day, hour, min, sec );
+}
+
+
+int
+gemini_set_rtc_time( unsigned long now )
+{
+	unsigned char reg;
+	struct rtc_time tm;
+
+	to_tm( now, &tm );
+
+	reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+#if DEBUG_RTC
+	printk("set rtc: reg = %x\n", reg);
+#endif
+
+	gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL);
+#if DEBUG_RTC
+	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+
+	tm.tm_year -= 1900;
+	BIN_TO_BCD(tm.tm_sec);
+	BIN_TO_BCD(tm.tm_min);
+	BIN_TO_BCD(tm.tm_hour);
+	BIN_TO_BCD(tm.tm_mon);
+	BIN_TO_BCD(tm.tm_mday);
+	BIN_TO_BCD(tm.tm_year);
+#ifdef DEBUG_RTC
+	printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+	       tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+
+	gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS);
+	gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES);
+	gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS);
+	gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM);
+	gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH);
+	gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR);
+
+	/* done writing */
+	gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+	if ((time_state == TIME_ERROR) || (time_state == TIME_BAD))
+		time_state = TIME_OK;
+
+	return 0;
+}
+
+/*  use the RTC to determine the decrementer count */
+void __init gemini_calibrate_decr(void)
+{
+	int freq, divisor;
+	unsigned char reg;
+
+	/* determine processor bus speed */
+	reg = readb(GEMINI_BSTAT);
+
+	switch(((reg & 0x0c)>>2)&0x3) {
+	case 0:
+	default:
+		freq = 66667;
+		break;
+	case 1:
+		freq = 83000;
+		break;
+	case 2:
+		freq = 100000;
+		break;
+	}
+
+	freq *= 1000;
+	divisor = 4;
+	tb_ticks_per_jiffy = freq / HZ / divisor;
+	tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+}
+
+unsigned long __init gemini_find_end_of_memory(void)
+{
+	unsigned long total;
+	unsigned char reg;
+
+	reg = readb(GEMINI_MEMCFG);
+	total = ((1<<((reg & 0x7) - 1)) *
+		 (8<<((reg >> 3) & 0x7)));
+	total *= (1024*1024);
+	return total;
+}
+
+static void __init
+gemini_map_io(void)
+{
+	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+	io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
+}
+
+#ifdef CONFIG_SMP
+static int
+smp_gemini_probe(void)
+{
+	int i, nr;
+
+        nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
+	if (nr == 0)
+		nr = 4;
+
+	if (nr > 1) {
+		openpic_request_IPIs();
+		for (i = 1; i < nr; ++i)
+			smp_hw_index[i] = i;
+	}
+
+	return nr;
+}
+
+static void
+smp_gemini_kick_cpu(int nr)
+{
+	openpic_reset_processor_phys(1 << nr);
+	openpic_reset_processor_phys(0);
+}
+
+static void
+smp_gemini_setup_cpu(int cpu_nr)
+{
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+	if (cpu_nr > 0)
+		gemini_init_l2();
+}
+
+static struct smp_ops_t gemini_smp_ops = {
+	smp_openpic_message_pass,
+	smp_gemini_probe,
+	smp_gemini_kick_cpu,
+	smp_gemini_setup_cpu,
+};
+#endif /* CONFIG_SMP */
+
+void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+			  unsigned long r6, unsigned long r7)
+{
+	int i;
+
+	for(i = 0; i < GEMINI_LEDS; i++)
+		gemini_led_off(i);
+
+	ISA_DMA_THRESHOLD = 0;
+	DMA_MODE_READ = 0;
+	DMA_MODE_WRITE = 0;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif
+
+	ppc_md.setup_arch = gemini_setup_arch;
+	ppc_md.show_cpuinfo = gemini_show_cpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ = gemini_init_IRQ;
+	ppc_md.get_irq = openpic_get_irq;
+	ppc_md.init = NULL;
+
+	ppc_md.restart = gemini_restart;
+	ppc_md.power_off = gemini_power_off;
+	ppc_md.halt = gemini_halt;
+
+	ppc_md.time_init = gemini_time_init;
+	ppc_md.set_rtc_time = gemini_set_rtc_time;
+	ppc_md.get_rtc_time = gemini_get_rtc_time;
+	ppc_md.calibrate_decr = gemini_calibrate_decr;
+
+	ppc_md.find_end_of_memory = gemini_find_end_of_memory;
+	ppc_md.setup_io_mappings = gemini_map_io;
+
+	/* no keyboard/mouse/video stuff yet.. */
+	ppc_md.kbd_setkeycode = NULL;
+	ppc_md.kbd_getkeycode = NULL;
+	ppc_md.kbd_translate = NULL;
+	ppc_md.kbd_unexpected_up = NULL;
+	ppc_md.kbd_leds = NULL;
+	ppc_md.kbd_init_hw = NULL;
+	ppc_md.ppc_kbd_sysrq_xlate = NULL;
+	ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
+
+#ifdef CONFIG_SMP
+	ppc_md.smp_ops = &gemini_smp_ops;
+#endif /* CONFIG_SMP */
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/ivms8.h linux-2.4.20-pre2/arch/ppc/platforms/ivms8.h
--- linux-2.4.20-pre1/arch/ppc/platforms/ivms8.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/ivms8.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,59 @@
+/*
+ * BK Id: SCCS/s.ivms8.h 1.8 10/26/01 10:14:09 trini
+ */
+/*
+ * Speech Design Integrated Voicemail board specific definitions
+ * - IVMS8  (small,  8 channels)
+ * - IVML24 (large, 24 channels)
+ *
+ * In 2.5 when we force a new bootloader, we can merge these two, and add
+ * in _MACH_'s for them. -- Tom
+ *
+ * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IVMS8_H__
+#define __ASM_IVMS8_H__
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define IVMS_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
+#define IVMS_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
+
+#define IMAP_ADDR	IVMS_IMMR_BASE	/* phys. base address of IMMR area */
+#define IMAP_SIZE	IVMS_IMAP_SIZE	/* mapped size of IMMR area */
+
+#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
+#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
+
+#define FEC_INTERRUPT	 9		/* = SIU_LEVEL4 */
+#define IDE0_INTERRUPT	10		/* = IRQ5 */
+#define CPM_INTERRUPT	11		/* = SIU_LEVEL5 (was: SIU_LEVEL2) */
+#define PHY_INTERRUPT	12		/* = IRQ6 */
+
+/* override the default number of IDE hardware interfaces */
+#define MAX_HWIFS	1
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory */
+#define IDE0_DATA_REG_OFFSET		0x0000
+#define IDE0_ERROR_REG_OFFSET		0x0081
+#define IDE0_NSECTOR_REG_OFFSET		0x0082
+#define IDE0_SECTOR_REG_OFFSET		0x0083
+#define IDE0_LCYL_REG_OFFSET		0x0084
+#define IDE0_HCYL_REG_OFFSET		0x0085
+#define IDE0_SELECT_REG_OFFSET		0x0086
+#define IDE0_STATUS_REG_OFFSET		0x0087
+#define IDE0_CONTROL_REG_OFFSET		0x0106
+#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
+
+/* We don't use the 8259. */
+#define NR_8259_INTS	0
+
+#endif /* __ASM_IVMS8_H__ */
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/mbx.h linux-2.4.20-pre2/arch/ppc/platforms/mbx.h
--- linux-2.4.20-pre1/arch/ppc/platforms/mbx.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/mbx.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,98 @@
+/*
+ * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus
+ */
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Motorola MBX boards.  This was originally created for the
+ * MBX860, and probably needs revisions for other boards (like the 821).
+ * When this file gets out of control, we can split it up into more
+ * meaningful pieces.
+ *
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_MBX_DEFS
+#define __MACH_MBX_DEFS
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * EPPC-Bug starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_tag;		/* Should be 0x42444944 "BDID" */
+	unsigned int	bi_size;	/* Size of this structure */
+	unsigned int	bi_revision;	/* revision of this structure */
+	unsigned int	bi_bdate;	/* EPPCbug date, i.e. 0x11061997 */
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned int	bi_clun;	/* Boot device controller */
+	unsigned int	bi_dlun;	/* Boot device logical dev */
+
+	/* These fields are not part of the board information structure
+	 * provided by the boot rom.  They are filled in by embed_config.c
+	 * so we have the information consistent with other platforms.
+	 */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+/* Memory map for the MBX as configured by EPPC-Bug.  We could reprogram
+ * The SIU and PCI bridge, and try to use larger MMU pages, but the
+ * performance gain is not measureable and it certainly complicates the
+ * generic MMU model.
+ *
+ * In a effort to minimize memory usage for embedded applications, any
+ * PCI driver or ISA driver must request or map the region required by
+ * the device.  For convenience (and since we can map up to 4 Mbytes with
+ * a single page table page), the MMU initialization will map the
+ * NVRAM, Status/Control registers, CPM Dual Port RAM, and the PCI
+ * Bridge CSRs 1:1 into the kernel address space.
+ */
+#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
+#define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
+#define PCI_IDE_ADDR		((unsigned)0x81000000)
+#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
+#define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0xe0000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024 * 1024))
+#define PCMCIA_DMA_ADDR		((uint)0xe4000000)
+#define PCMCIA_DMA_SIZE		((uint)(64 * 1024 * 1024))
+#define PCMCIA_ATTRB_ADDR	((uint)0xe8000000)
+#define PCMCIA_ATTRB_SIZE	((uint)(64 * 1024 * 1024))
+#define PCMCIA_IO_ADDR		((uint)0xec000000)
+#define PCMCIA_IO_SIZE		((uint)(64 * 1024 * 1024))
+#define NVRAM_ADDR		((uint)0xfa000000)
+#define NVRAM_SIZE		((uint)(1 * 1024 * 1024))
+#define MBX_CSR_ADDR		((uint)0xfa100000)
+#define MBX_CSR_SIZE		((uint)(1 * 1024 * 1024))
+#define IMAP_ADDR		((uint)0xfa200000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCI_CSR_ADDR		((uint)0xfa210000)
+#define PCI_CSR_SIZE		((uint)(64 * 1024))
+
+/* Map additional physical space into well known virtual addresses.  Due
+ * to virtual address mapping, these physical addresses are not accessible
+ * in a 1:1 virtual to physical mapping.
+ */
+#define ISA_IO_VIRT_ADDR	((uint)0xfa220000)
+#define ISA_IO_VIRT_SIZE	((uint)64 * 1024)
+
+/* Interrupt assignments.
+ * These are defined (and fixed) by the MBX hardware implementation.
+ */
+#define POWER_FAIL_INT	SIU_IRQ0	/* Power fail */
+#define TEMP_HILO_INT	SIU_IRQ1	/* Temperature sensor */
+#define QSPAN_INT	SIU_IRQ2	/* PCI Bridge (DMA CTLR?) */
+#define ISA_BRIDGE_INT	SIU_IRQ3	/* All those PC things */
+#define COMM_L_INT	SIU_IRQ6	/* MBX Comm expansion connector pin */
+#define STOP_ABRT_INT	SIU_IRQ7	/* Stop/Abort header pin */
+#endif /* !__ASSEMBLY__ */
+
+/* The MBX uses the 8259.
+*/
+#define NR_8259_INTS	16
+
+#endif
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/oak.h linux-2.4.20-pre2/arch/ppc/platforms/oak.h
--- linux-2.4.20-pre1/arch/ppc/platforms/oak.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/oak.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,65 @@
+/*
+ * BK Id: SCCS/s.oak.h 1.12 10/11/01 13:05:07 trini
+ */
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: oak.h
+ *
+ *    Description:
+ *	Macros, definitions, and data structures specific to the IBM PowerPC
+ *      403G{A,B,C,CX} "Oak" evaluation board. Anything specific to the pro-
+ *      cessor itself is defined elsewhere.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef	__OAK_H__
+#define	__OAK_H__
+
+#define _IO_BASE	0
+#define _ISA_MEM_BASE	0
+#define PCI_DRAM_OFFSET	0
+
+/* Memory map for the "Oak" evaluation board */
+
+#define	PPC403SPU_IO_BASE      	0x40000000	/* 403 On-chip serial port */
+#define	PPC403SPU_IO_SIZE      	0x00000008
+#define	OAKSERIAL_IO_BASE	0x7E000000	/* NS16550DV serial port */
+#define	OAKSERIAL_IO_SIZE	0x00000008
+#define	OAKNET_IO_BASE		0xF4000000	/* NS83902AV Ethernet */
+#define	OAKNET_IO_SIZE		0x00000040
+#define	OAKPROM_IO_BASE		0xFFFE0000	/* AMD 29F010 Flash ROM */
+#define	OAKPROM_IO_SIZE		0x00020000
+
+
+/* Interrupt assignments fixed by the hardware implementation */
+
+/* This is annoying kbuild-2.4 problem. -- Tom */
+
+#define	PPC403SPU_RX_INT	4	/* AIC_INT4 */
+#define	PPC403SPU_TX_INT	5	/* AIC_INT5 */
+#define	OAKNET_INT		27	/* AIC_INT27 */
+#define	OAKSERIAL_INT		28	/* AIC_INT28 */
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Oak" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+	unsigned char	 bi_s_version[4];	/* Version of this structure */
+	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[6];	/* Ethernet MAC address */
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* Bus speed, in Hz */
+} bd_t;
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __OAK_H__ */
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/oak_setup.c linux-2.4.20-pre2/arch/ppc/platforms/oak_setup.c
--- linux-2.4.20-pre1/arch/ppc/platforms/oak_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/oak_setup.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,291 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: oak_setup.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+
+#include <asm/processor.h>
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/bootinfo.h>
+#include <asm/ppc4xx_pic.h>
+#include <asm/time.h>
+
+#include "oak_setup.h"
+
+/* Function Prototypes */
+
+extern void abort(void);
+
+/* Global Variables */
+
+unsigned char __res[sizeof(bd_t)];
+
+
+/*
+ * void __init oak_init()
+ *
+ * Description:
+ *   This routine...
+ *
+ * Input(s):
+ *   r3 - Optional pointer to a board information structure.
+ *   r4 - Optional pointer to the physical starting address of the init RAM
+ *        disk.
+ *   r5 - Optional pointer to the physical ending address of the init RAM
+ *        disk.
+ *   r6 - Optional pointer to the physical starting address of any kernel
+ *        command-line parameters.
+ *   r7 - Optional pointer to the physical ending address of any kernel
+ *        command-line parameters.
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	/*
+	 * If we were passed in a board information, copy it into the
+	 * residual data area.
+	 */
+	if (r3) {
+		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+	}
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+	/*
+	 * If the init RAM disk has been configured in, and there's a valid
+	 * starting address for it, set it up.
+	 */
+	if (r4) {
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* Copy the kernel command line arguments to a safe place. */
+
+	if (r6) {
+ 		*(char *)(r7 + KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
+	}
+
+	/* Initialize machine-dependency vectors */
+
+	ppc_md.setup_arch	 	= oak_setup_arch;
+	ppc_md.show_percpuinfo	 	= oak_show_percpuinfo;
+	ppc_md.irq_cannonicalize 	= NULL;
+	ppc_md.init_IRQ		 	= oak_init_IRQ;
+	ppc_md.get_irq		 	= oak_get_irq;
+	ppc_md.init		 	= NULL;
+
+	ppc_md.restart		 	= oak_restart;
+	ppc_md.power_off	 	= oak_power_off;
+	ppc_md.halt		 	= oak_halt;
+
+	ppc_md.time_init	 	= oak_time_init;
+	ppc_md.set_rtc_time	 	= oak_set_rtc_time;
+	ppc_md.get_rtc_time	 	= oak_get_rtc_time;
+	ppc_md.calibrate_decr	 	= oak_calibrate_decr;
+
+	ppc_md.kbd_setkeycode    	= NULL;
+	ppc_md.kbd_getkeycode    	= NULL;
+	ppc_md.kbd_translate     	= NULL;
+	ppc_md.kbd_unexpected_up 	= NULL;
+	ppc_md.kbd_leds          	= NULL;
+	ppc_md.kbd_init_hw       	= NULL;
+	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
+}
+
+/*
+ * Document me.
+ */
+void __init
+oak_setup_arch(void)
+{
+	/* XXX - Implement me */
+}
+
+/*
+ * int oak_show_percpuinfo()
+ *
+ * Description:
+ *   This routine pretty-prints the platform's internal CPU and bus clock
+ *   frequencies into the buffer for usage in /proc/cpuinfo.
+ *
+ * Input(s):
+ *  *buffer - Buffer into which CPU and bus clock frequencies are to be
+ *            printed.
+ *
+ * Output(s):
+ *  *buffer - Buffer with the CPU and bus clock frequencies.
+ *
+ * Returns:
+ *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
+ *   on error.
+ */
+int
+oak_show_percpuinfo(struct seq_file *m, int i)
+{
+	bd_t *bp = (bd_t *)__res;
+
+	seq_printf(m, "clock\t\t: %dMHz\n"
+		   "bus clock\t\t: %dMHz\n",
+		   bp->bi_intfreq / 1000000,
+		   bp->bi_busfreq / 1000000);
+
+	return 0;
+}
+
+/*
+ * Document me.
+ */
+void __init
+oak_init_IRQ(void)
+{
+	int i;
+
+	ppc4xx_pic_init();
+
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].handler = ppc4xx_pic;
+	}
+
+	return;
+}
+
+/*
+ * Document me.
+ */
+int
+oak_get_irq(struct pt_regs *regs)
+{
+	return (ppc4xx_pic_get_irq(regs));
+}
+
+/*
+ * Document me.
+ */
+void
+oak_restart(char *cmd)
+{
+	abort();
+}
+
+/*
+ * Document me.
+ */
+void
+oak_power_off(void)
+{
+	oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void
+oak_halt(void)
+{
+	oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+long __init
+oak_time_init(void)
+{
+	/* XXX - Implement me */
+	return 0;
+}
+
+/*
+ * Document me.
+ */
+int __init
+oak_set_rtc_time(unsigned long time)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * Document me.
+ */
+unsigned long __init
+oak_get_rtc_time(void)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * void __init oak_calibrate_decr()
+ *
+ * Description:
+ *   This routine retrieves the internal processor frequency from the board
+ *   information structure, sets up the kernel timer decrementer based on
+ *   that value, enables the 403 programmable interval timer (PIT) and sets
+ *   it up for auto-reload.
+ *
+ * Input(s):
+ *   N/A
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+void __init
+oak_calibrate_decr(void)
+{
+	unsigned int freq;
+	bd_t *bip = (bd_t *)__res;
+
+	freq = bip->bi_intfreq;
+
+	decrementer_count = freq / HZ;
+	count_period_num = 1;
+	count_period_den = freq;
+
+	/* Enable the PIT and set auto-reload of its value */
+
+	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
+
+	/* Clear any pending timer interrupts */
+
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/oak_setup.h linux-2.4.20-pre2/arch/ppc/platforms/oak_setup.h
--- linux-2.4.20-pre1/arch/ppc/platforms/oak_setup.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/oak_setup.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,53 @@
+/*
+ * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort
+ */
+/*
+ *
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: oak_setup.h
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
+ *      <dan@netx4.com>.
+ *
+ */
+
+#ifndef	__OAK_SETUP_H__
+#define	__OAK_SETUP_H__
+
+#include <asm/ptrace.h>
+#include <asm/board.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned char	 __res[sizeof(bd_t)];
+
+extern void		 oak_init(unsigned long r3,
+				  unsigned long ird_start,
+				  unsigned long ird_end,
+				  unsigned long cline_start,
+				  unsigned long cline_end);
+extern void		 oak_setup_arch(void);
+extern int		 oak_setup_residual(char *buffer);
+extern void		 oak_init_IRQ(void);
+extern int		 oak_get_irq(struct pt_regs *regs);
+extern void		 oak_restart(char *cmd);
+extern void		 oak_power_off(void);
+extern void		 oak_halt(void);
+extern void		 oak_time_init(void);
+extern int		 oak_set_rtc_time(unsigned long now);
+extern unsigned long	 oak_get_rtc_time(void);
+extern void		 oak_calibrate_decr(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OAK_SETUP_H__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/pmac_backlight.c linux-2.4.20-pre2/arch/ppc/platforms/pmac_backlight.c
--- linux-2.4.20-pre1/arch/ppc/platforms/pmac_backlight.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/pmac_backlight.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,150 @@
+/*
+ * BK Id: SCCS/s.pmac_backlight.c 1.10 12/01/01 20:09:06 benh
+ */
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ * Contains support for the backlight.
+ * 
+ *   Copyright (C) 2000 Benjamin Herrenschmidt
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
+#include <asm/sections.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+#include <asm/backlight.h>
+
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+static struct backlight_controller *backlighter = NULL;
+static void* backlighter_data = NULL;
+static int backlight_autosave = 0;
+static int backlight_level = BACKLIGHT_MAX;
+static int backlight_enabled = 1;
+
+void __pmac
+register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type)
+{
+	struct device_node* bk_node;
+	char *prop;
+	int valid = 0;
+
+	bk_node = find_devices("backlight");
+	
+#ifdef CONFIG_ADB_PMU
+	/* Special case for the old PowerBook since I can't test on it */
+	backlight_autosave = machine_is_compatible("AAPL,3400/2400")
+		|| machine_is_compatible("AAPL,3500");
+	if ((backlight_autosave
+	     || machine_is_compatible("AAPL,PowerBook1998")
+	     || machine_is_compatible("PowerBook1,1"))
+	    && !strcmp(type, "pmu"))
+		valid = 1;
+#endif
+	if (bk_node) {
+		prop = get_property(bk_node, "backlight-control", NULL);
+		if (prop && !strncmp(prop, type, strlen(type)))
+			valid = 1;
+	}
+	if (!valid)
+		return;
+	backlighter = ctrler;
+	backlighter_data = data;
+	
+	if (bk_node && !backlight_autosave)
+		prop = get_property(bk_node, "bklt", NULL);
+	else
+		prop = NULL;
+	if (prop) {
+		backlight_level = ((*prop)+1) >> 1;
+		if (backlight_level > BACKLIGHT_MAX)
+			backlight_level = BACKLIGHT_MAX;
+	}
+	
+#ifdef CONFIG_ADB_PMU
+	if (backlight_autosave) {
+		struct adb_request req;
+		pmu_request(&req, NULL, 2, 0xd9, 0);
+		while (!req.complete)
+			pmu_poll();
+		backlight_level = req.reply[0] >> 4;
+	}
+#endif
+	if (!backlighter->set_enable(1, backlight_level, data))
+		backlight_enabled = 1;
+
+	printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
+		type, backlight_level);
+}
+
+void __pmac
+unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
+{
+	/* We keep the current backlight level (for now) */
+	if (ctrler == backlighter && data == backlighter_data)
+		backlighter = NULL;
+}
+
+int __pmac
+set_backlight_enable(int enable)
+{
+	int rc;
+	
+	if (!backlighter)
+		return -ENODEV;
+	rc = backlighter->set_enable(enable, backlight_level, backlighter_data);
+	if (!rc)
+		backlight_enabled = enable;
+	return rc;
+}
+
+int __pmac
+get_backlight_enable(void)
+{
+	if (!backlighter)
+		return -ENODEV;
+	return backlight_enabled;
+}
+
+int __pmac
+set_backlight_level(int level)
+{
+	int rc = 0;
+	
+	if (!backlighter)
+		return -ENODEV;
+	if (level < BACKLIGHT_MIN)
+		level = BACKLIGHT_OFF;
+	if (level > BACKLIGHT_MAX)
+		level = BACKLIGHT_MAX;
+	if (backlight_enabled)
+		rc = backlighter->set_level(level, backlighter_data);
+	if (!rc)
+		backlight_level = level;
+	if (!rc && !backlight_autosave) {
+		level <<=1;
+		if (level & 0x10)
+			level |= 0x01;
+		// -- todo: save to property "bklt"
+	}
+	return rc;
+}
+
+int __pmac
+get_backlight_level(void)
+{
+	if (!backlighter)
+		return -ENODEV;
+	return backlight_level;
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/pmac_feature.c linux-2.4.20-pre2/arch/ppc/platforms/pmac_feature.c
--- linux-2.4.20-pre1/arch/ppc/platforms/pmac_feature.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/pmac_feature.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,2139 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platform/pmac_feature.c
+ *
+ *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
+ *                          Ben. Herrenschmidt (benh@kernel.crashing.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.
+ *  
+ *  TODO: 
+ *  
+ *   - Replace mdelay with some schedule loop if possible
+ *   - Shorten some obfuscated delays on some routines (like modem
+ *     power)
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/sections.h>
+#include <asm/errno.h>
+#include <asm/ohare.h>
+#include <asm/heathrow.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/dbdma.h>
+
+#undef DEBUG_FEATURE
+
+#ifdef DEBUG_FEATURE
+#define DBG(fmt,...) printk(KERN_DEBUG fmt)
+#else
+#define DBG(fmt,...)
+#endif
+
+/* Exported from arch/ppc/kernel/idle.c */
+extern unsigned long powersave_nap;
+
+/*
+ * We use a single global lock to protect accesses. Each driver has
+ * to take care of it's own locking
+ */
+static spinlock_t feature_lock  __pmacdata = SPIN_LOCK_UNLOCKED;
+
+#define LOCK(flags)	spin_lock_irqsave(&feature_lock, flags);
+#define UNLOCK(flags)	spin_unlock_irqrestore(&feature_lock, flags);
+
+/*
+ * Helper functions regarding the various flavors of mac-io
+ */
+ 
+#define MAX_MACIO_CHIPS		2
+
+enum {
+	macio_unknown = 0,
+	macio_grand_central,
+	macio_ohare,
+	macio_ohareII,
+	macio_heathrow,
+	macio_gatwick,
+	macio_paddington,
+	macio_keylargo,
+	macio_pangea
+};
+
+static const char* macio_names[] __pmacdata = 
+{
+	"Unknown",
+	"Grand Central",
+	"OHare",
+	"OHareII",
+	"Heathrow",
+	"Gatwick",
+	"Paddington",
+	"Keylargo",
+	"Pangea"
+};
+
+static struct macio_chip
+{
+	struct device_node*	of_node;
+	int			type;
+	int			rev;
+	volatile u32*		base;
+	unsigned long		flags;
+} macio_chips[MAX_MACIO_CHIPS]  __pmacdata;
+
+#define MACIO_FLAG_SCCA_ON	0x00000001
+#define MACIO_FLAG_SCCB_ON	0x00000002
+#define MACIO_FLAG_SCC_LOCKED	0x00000004
+#define MACIO_FLAG_AIRPORT_ON	0x00000010
+#define MACIO_FLAG_FW_SUPPORTED	0x00000020
+
+static struct macio_chip* __pmac
+macio_find(struct device_node* child, int type)
+{
+	while(child) {
+		int	i;
+	
+		for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
+			if (child == macio_chips[i].of_node &&
+			    (!type || macio_chips[i].type == type))
+				return &macio_chips[i];
+		child = child->parent;
+	}
+	return NULL;
+}
+
+#define MACIO_FCR32(macio, r)	((macio)->base + ((r) >> 2))
+#define MACIO_FCR8(macio, r)	(((volatile u8*)((macio)->base)) + (r))
+
+#define MACIO_IN32(r)		(in_le32(MACIO_FCR32(macio,r)))
+#define MACIO_OUT32(r,v)	(out_le32(MACIO_FCR32(macio,r), (v)))
+#define MACIO_BIS(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) | (v)))
+#define MACIO_BIC(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) & ~(v)))
+#define MACIO_IN8(r)		(in_8(MACIO_FCR8(macio,r)))
+#define MACIO_OUT8(r,v)		(out_8(MACIO_FCR8(macio,r), (v)))
+
+/*
+ * Uninorth reg. access. Note that Uni-N regs are big endian
+ */
+ 
+#define UN_REG(r)	(uninorth_base + ((r) >> 2))
+#define UN_IN(r)	(in_be32(UN_REG(r)))
+#define UN_OUT(r,v)	(out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v)	(UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v)	(UN_OUT((r), UN_IN(r) & ~(v)))
+
+static struct device_node* uninorth_node __pmacdata;
+static u32* uninorth_base __pmacdata;
+static u32 uninorth_rev __pmacdata;
+
+
+/*
+ * For each motherboard family, we have a table of functions pointers
+ * that handle the various features.
+ */
+
+typedef int (*feature_call)(struct device_node* node, int param, int value);
+
+struct feature_table_entry {
+	unsigned int	selector;	
+	feature_call	function;
+};
+
+struct pmac_mb_def
+{
+	const char*			model_string;
+	const char*			model_name;
+	int				model_id;
+	struct feature_table_entry* 	features;
+	unsigned long			board_flags;
+};
+static struct pmac_mb_def pmac_mb __pmacdata;
+
+/*
+ * Here are the chip specific feature functions
+ */
+
+static inline int __pmac
+simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, type);
+	if (!macio)
+		return -ENODEV;
+	LOCK(flags);
+	if (value)
+		MACIO_BIS(reg, mask);
+	else
+		MACIO_BIC(reg, mask);
+	(void)MACIO_IN32(reg);
+	UNLOCK(flags);
+
+	return 0;
+}
+
+static int __pmac
+ohare_htw_scc_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		chan_mask;
+	unsigned long		fcr;
+	unsigned long		flags;
+	int			htw, trans;
+	unsigned long		rmask;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	if (!strcmp(node->name, "ch-a"))
+		chan_mask = MACIO_FLAG_SCCA_ON;
+	else if (!strcmp(node->name, "ch-b"))
+		chan_mask = MACIO_FLAG_SCCB_ON;
+	else
+		return -ENODEV;
+
+	htw = (macio->type == macio_heathrow || macio->type == macio_paddington
+		|| macio->type == macio_gatwick);
+	/* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
+	trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
+	    	 pmac_mb.model_id != PMAC_TYPE_YIKES);
+	if (value) {
+#ifdef CONFIG_ADB_PMU
+		if ((param & 0xfff) == PMAC_SCC_IRDA)
+			pmu_enable_irled(1);
+#endif /* CONFIG_ADB_PMU */		
+		LOCK(flags);
+		fcr = MACIO_IN32(OHARE_FCR);
+		/* Check if scc cell need enabling */
+		if (!(fcr & OH_SCC_ENABLE)) {
+			fcr |= OH_SCC_ENABLE;
+			if (htw) {
+				/* Side effect: this will also power up the
+				 * modem, but it's too messy to figure out on which
+				 * ports this controls the tranceiver and on which
+				 * it controls the modem
+				 */
+				if (trans)
+					fcr &= ~HRW_SCC_TRANS_EN_N;
+				MACIO_OUT32(OHARE_FCR, fcr);
+				fcr |= (rmask = HRW_RESET_SCC);
+				MACIO_OUT32(OHARE_FCR, fcr);
+			} else {
+				fcr |= (rmask = OH_SCC_RESET);
+				MACIO_OUT32(OHARE_FCR, fcr);
+			}
+			UNLOCK(flags);
+			(void)MACIO_IN32(OHARE_FCR);
+			mdelay(15);
+			LOCK(flags);
+			fcr &= ~rmask;
+			MACIO_OUT32(OHARE_FCR, fcr);
+		}
+		if (chan_mask & MACIO_FLAG_SCCA_ON)
+			fcr |= OH_SCCA_IO;
+		if (chan_mask & MACIO_FLAG_SCCB_ON)
+			fcr |= OH_SCCB_IO;
+		MACIO_OUT32(OHARE_FCR, fcr);
+		macio->flags |= chan_mask;
+		UNLOCK(flags);
+		if (param & PMAC_SCC_FLAG_XMON)
+			macio->flags |= MACIO_FLAG_SCC_LOCKED;
+	} else {
+		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
+			return -EPERM;
+		LOCK(flags);
+		fcr = MACIO_IN32(OHARE_FCR);
+		if (chan_mask & MACIO_FLAG_SCCA_ON)
+			fcr &= ~OH_SCCA_IO;
+		if (chan_mask & MACIO_FLAG_SCCB_ON)
+			fcr &= ~OH_SCCB_IO;
+		MACIO_OUT32(OHARE_FCR, fcr);
+		if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
+			fcr &= ~OH_SCC_ENABLE;
+			if (htw && trans)
+				fcr |= HRW_SCC_TRANS_EN_N;
+			MACIO_OUT32(OHARE_FCR, fcr);
+		}
+		macio->flags &= ~(chan_mask);
+		UNLOCK(flags);
+		mdelay(10);
+#ifdef CONFIG_ADB_PMU
+		if ((param & 0xfff) == PMAC_SCC_IRDA)
+			pmu_enable_irled(0);
+#endif /* CONFIG_ADB_PMU */		
+	}
+	return 0;
+}
+
+static int __pmac
+ohare_floppy_enable(struct device_node* node, int param, int value)
+{
+	return simple_feature_tweak(node, macio_ohare,
+		OHARE_FCR, OH_FLOPPY_ENABLE, value);
+}
+
+static int __pmac
+ohare_mesh_enable(struct device_node* node, int param, int value)
+{
+	return simple_feature_tweak(node, macio_ohare,
+		OHARE_FCR, OH_MESH_ENABLE, value);
+}
+
+static int __pmac
+ohare_ide_enable(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+	    	/* For some reason, setting the bit in set_initial_features()
+	    	 * doesn't stick. I'm still investigating... --BenH.
+	    	 */
+	    	if (value)
+	    		simple_feature_tweak(node, macio_ohare,
+				OHARE_FCR, OH_IOBUS_ENABLE, 1);
+		return simple_feature_tweak(node, macio_ohare,
+			OHARE_FCR, OH_IDE0_ENABLE, value);
+	    case 1:
+		return simple_feature_tweak(node, macio_ohare,
+			OHARE_FCR, OH_BAY_IDE_ENABLE, value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+ohare_ide_reset(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_ohare,
+			OHARE_FCR, OH_IDE0_RESET_N, !value);
+	    case 1:
+		return simple_feature_tweak(node, macio_ohare,
+			OHARE_FCR, OH_IDE1_RESET_N, !value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+ohare_sleep_state(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio = &macio_chips[0];
+
+	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+		return -EPERM;
+	if (value == 1) {
+		MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
+	} else if (value == 0) {
+		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+	}
+	
+	return 0;
+}
+
+static int __pmac
+heathrow_modem_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	u8			gpio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, macio_unknown);
+	if (!macio)
+		return -ENODEV;
+	gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
+	if (!value) {
+		LOCK(flags);
+		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
+		UNLOCK(flags);
+		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+		mdelay(250);
+	}
+	if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
+	    pmac_mb.model_id != PMAC_TYPE_YIKES) {
+	    	LOCK(flags);
+	    	if (value)
+	    		MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+	    	else
+	    		MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+	    	UNLOCK(flags);
+	    	(void)MACIO_IN32(HEATHROW_FCR);
+		mdelay(250);
+	}
+	if (value) {
+		LOCK(flags);
+		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
+		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
+		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
+		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250);
+	}
+	return 0;
+}
+
+static int __pmac
+heathrow_floppy_enable(struct device_node* node, int param, int value)
+{
+	return simple_feature_tweak(node, macio_unknown,
+		HEATHROW_FCR,
+		HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
+		value);
+}
+
+static int __pmac
+heathrow_mesh_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, macio_unknown);
+	if (!macio)
+		return -ENODEV;
+	LOCK(flags);
+	/* Set clear mesh cell enable */
+	if (value)
+		MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
+	else
+		MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
+	(void)MACIO_IN32(HEATHROW_FCR);
+	udelay(10);
+	/* Set/Clear termination power (todo: test ! the bit value
+	 * used by Darwin doesn't seem to match what we used so
+	 * far. If you experience problems, turn #if 1 into #if 0
+	 * and tell me about it --BenH.
+	 */
+#if 1
+	if (value)
+		MACIO_BIC(HEATHROW_MBCR, 0x00000004);
+	else
+		MACIO_BIS(HEATHROW_MBCR, 0x00000004);
+#else
+	if (value)
+		MACIO_BIC(HEATHROW_MBCR, 0x00040000);
+	else
+		MACIO_BIS(HEATHROW_MBCR, 0x00040000);
+#endif		
+	(void)MACIO_IN32(HEATHROW_MBCR);
+	udelay(10);
+	UNLOCK(flags);
+
+	return 0;
+}
+
+static int __pmac
+heathrow_ide_enable(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_unknown,
+			HEATHROW_FCR, HRW_IDE0_ENABLE, value);
+	    case 1:
+		return simple_feature_tweak(node, macio_unknown,
+			HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+heathrow_ide_reset(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_unknown,
+			HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
+	    case 1:
+		return simple_feature_tweak(node, macio_unknown,
+			HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+heathrow_bmac_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	if (value) {
+		LOCK(flags);
+		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
+		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
+		UNLOCK(flags);
+		(void)MACIO_IN32(HEATHROW_FCR);
+		mdelay(10);
+		LOCK(flags);
+		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
+		UNLOCK(flags);
+		(void)MACIO_IN32(HEATHROW_FCR);
+		mdelay(10);
+	} else {
+		LOCK(flags);
+		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
+		UNLOCK(flags);
+	}
+	return 0;
+}
+
+static int __pmac
+heathrow_sound_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+
+	/* B&W G3 and Yikes don't support that properly (the
+	 * sound appear to never come back after beeing shut down).
+	 */
+	if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
+	    pmac_mb.model_id == PMAC_TYPE_YIKES)
+		return 0;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	if (value) {
+		LOCK(flags);
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+		UNLOCK(flags);
+		(void)MACIO_IN32(HEATHROW_FCR);
+	} else {
+		LOCK(flags);
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		UNLOCK(flags);
+	}
+	return 0;
+}
+
+static u32 save_fcr[5] __pmacdata;
+static u32 save_mbcr __pmacdata;
+static u32 save_gpio_levels[2] __pmacdata;
+static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata;
+static u8 save_gpio_normal[KEYLARGO_GPIO_CNT] __pmacdata;
+static u32 save_unin_clock_ctl __pmacdata;
+static struct dbdma_regs save_dbdma[13] __pmacdata;
+static struct dbdma_regs save_alt_dbdma[13] __pmacdata;
+
+static void __pmac
+dbdma_save(struct macio_chip* macio, struct dbdma_regs* save)
+{
+	int i;
+	
+	/* Save state & config of DBDMA channels */
+	for (i=0; i<13; i++) {
+		volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*)
+			(macio->base + ((0x8000+i*0x100)>>2));
+		save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
+		save[i].cmdptr = in_le32(&chan->cmdptr);
+		save[i].intr_sel = in_le32(&chan->intr_sel);
+		save[i].br_sel = in_le32(&chan->br_sel);
+		save[i].wait_sel = in_le32(&chan->wait_sel);
+	}
+}
+
+static void __pmac
+dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save)
+{
+	int i;
+	
+	/* Save state & config of DBDMA channels */
+	for (i=0; i<13; i++) {
+		volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*)
+			(macio->base + ((0x8000+i*0x100)>>2));
+		out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
+		while (in_le32(&chan->status) & ACTIVE)
+			mb();
+		out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
+		out_le32(&chan->cmdptr, save[i].cmdptr);
+		out_le32(&chan->intr_sel, save[i].intr_sel);
+		out_le32(&chan->br_sel, save[i].br_sel);
+		out_le32(&chan->wait_sel, save[i].wait_sel);
+	}
+}
+
+static void __pmac
+heathrow_sleep(struct macio_chip* macio, int secondary)
+{
+	if (secondary) {
+		dbdma_save(macio, save_alt_dbdma);
+		save_fcr[2] = MACIO_IN32(0x38);
+		save_fcr[3] = MACIO_IN32(0x3c);
+	} else {
+		dbdma_save(macio, save_dbdma);
+		save_fcr[0] = MACIO_IN32(0x38);
+		save_fcr[1] = MACIO_IN32(0x3c);
+		save_mbcr = MACIO_IN32(0x34);
+		/* Make sure sound is shut down */
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		/* This seems to be necessary as well or the fan
+		 * keeps coming up and battery drains fast */
+		MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
+		/* Make sure eth is down even if module or sleep
+		 * won't work properly */
+		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
+	}
+	/* Make sure modem is shut down */
+	MACIO_OUT8(HRW_GPIO_MODEM_RESET,
+		MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
+	MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+	MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
+
+	/* Let things settle */
+	(void)MACIO_IN32(HEATHROW_FCR);
+	mdelay(1);
+}
+
+static void __pmac
+heathrow_wakeup(struct macio_chip* macio, int secondary)
+{
+	if (secondary) {
+		MACIO_OUT32(0x38, save_fcr[2]);
+		(void)MACIO_IN32(0x38);
+		mdelay(1);
+		MACIO_OUT32(0x3c, save_fcr[3]);
+		(void)MACIO_IN32(0x38);
+		mdelay(10);
+		dbdma_restore(macio, save_alt_dbdma);
+	} else {
+		MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
+		(void)MACIO_IN32(0x38);
+		mdelay(1);
+		MACIO_OUT32(0x3c, save_fcr[1]);
+		(void)MACIO_IN32(0x38);
+		mdelay(1);
+		MACIO_OUT32(0x34, save_mbcr);
+		(void)MACIO_IN32(0x38);
+		mdelay(10);
+		dbdma_restore(macio, save_dbdma);
+	}
+}
+
+static int __pmac
+heathrow_sleep_state(struct device_node* node, int param, int value)
+{
+	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+		return -EPERM;
+	if (value == 1) {
+		if (macio_chips[1].type == macio_gatwick)
+			heathrow_sleep(&macio_chips[0], 1);
+		heathrow_sleep(&macio_chips[0], 0);
+	} else if (value == 0) {
+		heathrow_wakeup(&macio_chips[0], 0);
+		if (macio_chips[1].type == macio_gatwick)
+			heathrow_wakeup(&macio_chips[0], 1);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_scc_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	unsigned long		chan_mask;
+	u32			fcr;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	if (!strcmp(node->name, "ch-a"))
+		chan_mask = MACIO_FLAG_SCCA_ON;
+	else if (!strcmp(node->name, "ch-b"))
+		chan_mask = MACIO_FLAG_SCCB_ON;
+	else
+		return -ENODEV;
+
+	if (value) {
+		int need_reset_scc = 0;
+		int need_reset_irda = 0;
+		
+		LOCK(flags);
+		fcr = MACIO_IN32(KEYLARGO_FCR0);
+		/* Check if scc cell need enabling */
+		if (!(fcr & KL0_SCC_CELL_ENABLE)) {
+			fcr |= KL0_SCC_CELL_ENABLE;
+			need_reset_scc = 1;
+		}
+		if (chan_mask & MACIO_FLAG_SCCA_ON) {
+			fcr |= KL0_SCCA_ENABLE;
+			/* Don't enable line drivers for I2S modem */
+			if ((param & 0xfff) == PMAC_SCC_I2S1)
+				fcr &= ~KL0_SCC_A_INTF_ENABLE;
+			else
+				fcr |= KL0_SCC_A_INTF_ENABLE;
+		}
+		if (chan_mask & MACIO_FLAG_SCCB_ON) {
+			fcr |= KL0_SCCB_ENABLE;
+			/* Perform irda specific inits */
+			if ((param & 0xfff) == PMAC_SCC_IRDA) {
+				fcr &= ~KL0_SCC_B_INTF_ENABLE;
+				fcr |= KL0_IRDA_ENABLE;
+				fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
+				fcr |= KL0_IRDA_SOURCE1_SEL;
+				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
+				fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
+				need_reset_irda = 1;
+			} else
+				fcr |= KL0_SCC_B_INTF_ENABLE;
+		}
+		MACIO_OUT32(KEYLARGO_FCR0, fcr);
+		macio->flags |= chan_mask;
+		if (need_reset_scc)  {
+			MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			UNLOCK(flags);
+			mdelay(15);
+			LOCK(flags);
+			MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
+		}
+		if (need_reset_irda)  {
+			MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			UNLOCK(flags);
+			mdelay(15);
+			LOCK(flags);
+			MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
+		}
+		UNLOCK(flags);
+		if (param & PMAC_SCC_FLAG_XMON)
+			macio->flags |= MACIO_FLAG_SCC_LOCKED;
+	} else {
+		if (macio->flags & MACIO_FLAG_SCC_LOCKED)
+			return -EPERM;
+		LOCK(flags);
+		fcr = MACIO_IN32(KEYLARGO_FCR0);
+		if (chan_mask & MACIO_FLAG_SCCA_ON)
+			fcr &= ~KL0_SCCA_ENABLE;
+		if (chan_mask & MACIO_FLAG_SCCB_ON) {
+			fcr &= ~KL0_SCCB_ENABLE;
+			/* Perform irda specific clears */
+			if ((param & 0xfff) == PMAC_SCC_IRDA) {
+				fcr &= ~KL0_IRDA_ENABLE;
+				fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
+				fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
+				fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
+			}
+		}
+		MACIO_OUT32(KEYLARGO_FCR0, fcr);
+		if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
+			fcr &= ~KL0_SCC_CELL_ENABLE;
+			MACIO_OUT32(KEYLARGO_FCR0, fcr);
+		}
+		macio->flags &= ~(chan_mask);
+		UNLOCK(flags);
+		mdelay(10);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_modem_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	u8			gpio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+	
+	if (!value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		UNLOCK(flags);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+		mdelay(250);
+	}
+    	LOCK(flags);
+    	if (value) {
+    		MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+	    	UNLOCK(flags);
+	    	(void)MACIO_IN32(KEYLARGO_FCR2);
+		mdelay(250);
+    	} else {
+    		MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+	    	UNLOCK(flags);
+    	}
+	if (value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_ide_enable(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
+	    case 1:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
+	    case 2:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+core99_ide_reset(struct device_node* node, int param, int value)
+{
+	switch(param) {
+	    case 0:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
+	    case 1:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
+	    case 2:
+		return simple_feature_tweak(node, macio_unknown,
+			KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
+	    default:
+	    	return -ENODEV;
+	}
+}
+
+static int __pmac
+core99_gmac_enable(struct device_node* node, int param, int value)
+{
+	unsigned long flags;
+
+	LOCK(flags);
+	if (value)
+		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+	else
+		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+	(void)UN_IN(UNI_N_CLOCK_CNTL);
+	UNLOCK(flags);
+	udelay(20);
+
+	return 0;
+}
+
+static int __pmac
+core99_gmac_phy_reset(struct device_node* node, int param, int value)
+{
+	unsigned long flags;
+	struct macio_chip* macio;
+	
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+
+	LOCK(flags);
+	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
+	(void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
+	UNLOCK(flags);
+	mdelay(10);
+	LOCK(flags);
+	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE
+		| KEYLARGO_GPIO_OUTOUT_DATA);
+	UNLOCK(flags);
+	mdelay(10);
+
+	return 0;
+}
+
+static int __pmac
+core99_sound_chip_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+
+	/* Do a better probe code, screamer G4 desktops &
+	 * iMacs can do that too, add a recalibrate  in
+	 * the driver as well
+	 */
+	if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
+	    pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
+		LOCK(flags);
+		if (value)
+	    		MACIO_OUT8(KL_GPIO_SOUND_POWER,
+	    			KEYLARGO_GPIO_OUTPUT_ENABLE |
+	    			KEYLARGO_GPIO_OUTOUT_DATA);
+	    	else
+	    		MACIO_OUT8(KL_GPIO_SOUND_POWER,
+	    			KEYLARGO_GPIO_OUTPUT_ENABLE);
+	    	(void)MACIO_IN8(KL_GPIO_SOUND_POWER);
+	    	UNLOCK(flags);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_airport_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	unsigned long		flags;
+	int			state;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	
+	/* Hint: we allow passing of macio itself for the sake of the
+	 * sleep code
+	 */
+	if (node != macio->of_node &&
+	    (!node->parent || node->parent != macio->of_node))
+		return -ENODEV;
+	state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
+	if (value == state)
+		return 0;
+	if (value) {
+		/* This code is a reproduction of OF enable-cardslot
+		 * and init-wireless methods, slightly hacked until
+		 * I got it working.
+		 */
+		LOCK(flags);
+		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
+		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
+		UNLOCK(flags);
+		mdelay(10);
+		LOCK(flags);
+		MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
+		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
+		UNLOCK(flags);
+
+		mdelay(10);
+
+		LOCK(flags);
+		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
+		(void)MACIO_IN32(KEYLARGO_FCR2);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
+		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
+		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
+		(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
+		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
+		udelay(10);
+		MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
+		(void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
+		UNLOCK(flags);
+		udelay(10);
+		MACIO_OUT32(0x1c000, 0);
+		mdelay(1);
+		MACIO_OUT8(0x1a3e0, 0x41);
+		(void)MACIO_IN8(0x1a3e0);
+		udelay(10);
+		LOCK(flags);
+		MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
+		(void)MACIO_IN32(KEYLARGO_FCR2);
+		UNLOCK(flags);
+		mdelay(100);
+
+		macio->flags |= MACIO_FLAG_AIRPORT_ON;
+	} else {
+		LOCK(flags);
+		MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
+		(void)MACIO_IN32(KEYLARGO_FCR2);
+		MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
+		MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
+		MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
+		MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
+		MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
+		(void)MACIO_IN8(KL_GPIO_AIRPORT_4);
+		UNLOCK(flags);
+
+		macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int __pmac
+core99_reset_cpu(struct device_node* node, int param, int value)
+{
+	const int reset_lines[] = {	KL_GPIO_RESET_CPU0,
+					KL_GPIO_RESET_CPU1,
+					KL_GPIO_RESET_CPU2,
+					KL_GPIO_RESET_CPU3 };
+	int reset_io;
+	unsigned long flags;
+	struct macio_chip* macio;
+	
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	if (param > 3 || param < 0)
+		return -ENODEV;
+
+	reset_io = reset_lines[param];
+	
+	LOCK(flags);
+	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
+	(void)MACIO_IN8(reset_io);
+	udelay(1);
+	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+	(void)MACIO_IN8(reset_io);
+	UNLOCK(flags);
+
+	return 0;
+}
+#endif /* CONFIG_SMP */
+
+static int __pmac
+core99_usb_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip* macio;
+	unsigned long flags;
+	char* prop;
+	int number;
+	u32 reg;
+	
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	
+	prop = (char *)get_property(node, "AAPL,clock-id", NULL);
+	if (!prop)
+		return -ENODEV;
+	if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0)
+		number = 0;
+	else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0)
+		number = 2;
+	else
+		return -ENODEV;
+
+	/* Sorry for the brute-force locking, but this is only used during
+	 * sleep and the timing seem to be critical
+	 */
+	LOCK(flags);
+	if (value) {
+		/* Turn ON */
+		if (number == 0) {
+			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			UNLOCK(flags);
+			mdelay(1);
+			LOCK(flags);
+			MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+		} else {
+			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+			UNLOCK(flags);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			mdelay(1);
+			LOCK(flags);
+			MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+		}
+		reg = MACIO_IN32(KEYLARGO_FCR4);
+		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
+		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
+		MACIO_OUT32(KEYLARGO_FCR4, reg);
+		(void)MACIO_IN32(KEYLARGO_FCR4);
+		udelay(10);
+	} else {
+		/* Turn OFF */
+		reg = MACIO_IN32(KEYLARGO_FCR4);
+		reg |=	KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
+		reg |=	KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
+		MACIO_OUT32(KEYLARGO_FCR4, reg);
+		(void)MACIO_IN32(KEYLARGO_FCR4);
+		udelay(1);
+		if (number == 0) {
+			MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			udelay(1);
+			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+		} else {
+			MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+			udelay(1);
+			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+			(void)MACIO_IN32(KEYLARGO_FCR0);
+		}
+		udelay(1);
+	}
+	UNLOCK(flags);
+
+	return 0;
+}
+
+static int __pmac
+core99_firewire_enable(struct device_node* node, int param, int value)
+{
+	unsigned long flags;
+	struct macio_chip* macio;
+
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
+		return -ENODEV;
+	
+	LOCK(flags);
+	if (value) {
+		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
+		(void)UN_IN(UNI_N_CLOCK_CNTL);
+	} else {
+		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
+		(void)UN_IN(UNI_N_CLOCK_CNTL);
+	}
+	UNLOCK(flags);
+	mdelay(1);
+
+	return 0;
+}
+
+static int __pmac
+core99_firewire_cable_power(struct device_node* node, int param, int value)
+{
+	unsigned long flags;
+	struct macio_chip* macio;
+
+	/* Trick: we allow NULL node */
+	if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
+	    	return -ENODEV;
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
+		return -ENODEV;
+	
+	LOCK(flags);
+	if (value) {
+		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
+		MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
+		udelay(10);
+	} else {
+		MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
+		MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
+	}
+	UNLOCK(flags);
+	mdelay(1);
+
+	return 0;
+}
+
+static int __pmac
+core99_read_gpio(struct device_node* node, int param, int value)
+{
+	struct macio_chip* macio = &macio_chips[0];
+	
+	return MACIO_IN8(param);
+}
+
+
+static int __pmac
+core99_write_gpio(struct device_node* node, int param, int value)
+{
+	struct macio_chip* macio = &macio_chips[0];
+
+	MACIO_OUT8(param, (u8)(value & 0xff));
+	return 0;
+}
+
+static void __pmac
+keylargo_shutdown(struct macio_chip* macio, int restart)
+{
+	u32 temp;
+
+	mdelay(1);
+	MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
+	(void)MACIO_IN32(KEYLARGO_FCR0);
+	mdelay(100);
+
+	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+				KL0_SCC_CELL_ENABLE |
+		      		KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
+		      		KL0_IRDA_CLK19_ENABLE);
+
+	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
+	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+
+	MACIO_BIC(KEYLARGO_FCR1,
+		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
+		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
+		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+		KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
+		KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
+		KL1_UIDE_ENABLE);
+	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+
+	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+ 	udelay(10);
+ 	MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
+ 	udelay(10);
+	temp = MACIO_IN32(KEYLARGO_FCR3);
+	if (macio->rev >= 2)
+		temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL);
+		
+	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+		KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12;
+	temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
+		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
+		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+	MACIO_OUT32(KEYLARGO_FCR3, temp);
+	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+}
+
+static void __pmac
+pangea_shutdown(struct macio_chip* macio, int restart)
+{
+	u32 temp;
+
+	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+				KL0_SCC_CELL_ENABLE |
+				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
+
+	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
+	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+
+	MACIO_BIC(KEYLARGO_FCR1,
+		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
+		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
+		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+		KL1_UIDE_ENABLE);
+	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+
+	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+ 	udelay(10);
+	temp = MACIO_IN32(KEYLARGO_FCR3);
+	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+		KL3_SHUTDOWN_PLLKW35;
+	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
+		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
+		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+	MACIO_OUT32(KEYLARGO_FCR3, temp);
+	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+}
+
+static int __pmac
+core99_sleep(void)
+{
+	struct macio_chip* macio;
+	int i;
+
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+	
+	/* We power off the wireless slot in case it was not done
+	 * by the driver. We don't power it on automatically however
+	 */
+	if (macio->flags & MACIO_FLAG_AIRPORT_ON)
+		core99_airport_enable(macio->of_node, 0, 0);
+
+	/* We power off the FW cable. Should be done by the driver... */
+	if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
+		core99_firewire_enable(NULL, 0, 0);
+		core99_firewire_cable_power(NULL, 0, 0);
+	}
+
+	/* We make sure int. modem is off (in case driver lost it) */
+	core99_modem_enable(macio->of_node, 0, 0);
+	/* We make sure the sound is off as well */
+	core99_sound_chip_enable(macio->of_node, 0, 0);
+	 
+	/*
+	 * Save various bits of KeyLargo
+	 */
+
+	/* Save the state of the various GPIOs */
+	save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
+	save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
+	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+		save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
+	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+		save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
+
+	/* Save the FCRs */
+	save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
+	save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
+	save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
+	save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
+	save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
+	save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
+
+	/* Save state & config of DBDMA channels */
+	dbdma_save(macio, save_dbdma);
+	
+	/*
+	 * Turn off as much as we can
+	 */
+	if (macio->type == macio_pangea)
+		pangea_shutdown(macio, 0);
+	else if (macio->type == macio_keylargo)
+		keylargo_shutdown(macio, 0);
+	
+	/* 
+	 * Put the host bridge to sleep
+	 */
+
+	save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
+	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
+		~(UNI_N_CLOCK_CNTL_GMAC|UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
+	udelay(100);
+	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
+
+	/*
+	 * FIXME: A bit of black magic with OpenPIC (don't ask me why)
+	 */
+	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
+		MACIO_BIS(0x506e0, 0x00400000);
+		MACIO_BIS(0x506e0, 0x80000000);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_wake_up(void)
+{
+	struct macio_chip* macio;
+	int i;
+
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+		return -ENODEV;
+
+	/*
+	 * Wakeup the host bridge
+	 */
+	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+	udelay(10);
+	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+	udelay(10);
+	
+	/*
+	 * Restore KeyLargo
+	 */
+	 
+	MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
+	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
+	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
+	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
+	(void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
+	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+	MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
+	(void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
+
+	dbdma_restore(macio, save_dbdma);
+
+	MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
+	MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
+	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+		MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
+	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+		MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
+
+	/* FIXME more black magic with OpenPIC ... */
+	if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
+		MACIO_BIC(0x506e0, 0x00400000);
+		MACIO_BIC(0x506e0, 0x80000000);
+	}
+
+	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
+	udelay(100);
+
+	return 0;
+}
+
+static int __pmac
+core99_sleep_state(struct device_node* node, int param, int value)
+{
+	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+		return -EPERM;
+	if (value == 1)
+		return core99_sleep();
+	else if (value == 0)
+		return core99_wake_up();
+	return 0;
+}
+
+static int __pmac
+pangea_modem_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	u8			gpio;
+	unsigned long		flags;
+	
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+	
+	if (!value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		UNLOCK(flags);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+		mdelay(250);
+	}
+    	LOCK(flags);
+	if (value) {
+		MACIO_OUT8(KL_GPIO_MODEM_POWER,
+			KEYLARGO_GPIO_OUTPUT_ENABLE);
+    		UNLOCK(flags);
+	    	(void)MACIO_IN32(KEYLARGO_FCR2);
+		mdelay(250);
+	} else {
+		MACIO_OUT8(KL_GPIO_MODEM_POWER,
+			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+    		UNLOCK(flags);
+	}
+	if (value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250);
+	}
+	return 0;
+}
+
+
+static int __pmac
+generic_get_mb_info(struct device_node* node, int param, int value)
+{
+	switch(param) {
+		case PMAC_MB_INFO_MODEL:
+			return pmac_mb.model_id;
+		case PMAC_MB_INFO_FLAGS:
+			return pmac_mb.board_flags;
+		case PMAC_MB_INFO_NAME:	
+			/* hack hack hack... but should work */
+			*((const char **)value) = pmac_mb.model_name;
+			break;
+	}
+	return 0;
+}
+
+
+/* 
+ * Table definitions
+ */
+ 
+/* Used on any machine
+ */
+static struct feature_table_entry any_features[]  __pmacdata = {
+	{ PMAC_FTR_GET_MB_INFO,		generic_get_mb_info },
+	{ 0, NULL }
+};
+
+/* OHare based motherboards. Currently, we only use these on the
+ * 2400,3400 and 3500 series powerbooks. Some older desktops seem
+ * to have issues with turning on/off those asic cells
+ */
+static struct feature_table_entry ohare_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
+	{ PMAC_FTR_SWIM3_ENABLE,	ohare_floppy_enable },
+	{ PMAC_FTR_MESH_ENABLE,		ohare_mesh_enable },
+	{ PMAC_FTR_IDE_ENABLE,		ohare_ide_enable},
+	{ PMAC_FTR_IDE_RESET,		ohare_ide_reset},
+	{ PMAC_FTR_SLEEP_STATE,		ohare_sleep_state },
+	{ 0, NULL }
+};
+
+/* Heathrow desktop machines (Beige G3).
+ * Separated as some features couldn't be properly tested
+ * and the serial port control bits appear to confuse it.
+ */
+static struct feature_table_entry heathrow_desktop_features[]  __pmacdata = {
+	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
+	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
+	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
+	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
+	{ 0, NULL }
+};
+
+/* Heathrow based laptop, that is the Wallstreet and mainstreet
+ * powerbooks.
+ */
+static struct feature_table_entry heathrow_laptop_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
+	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
+	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
+	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
+	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
+	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
+	{ 0, NULL }
+};
+
+/* Paddington based machines
+ * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
+ */
+static struct feature_table_entry paddington_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
+	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
+	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
+	{ PMAC_FTR_IDE_ENABLE,		heathrow_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		heathrow_ide_reset },
+	{ PMAC_FTR_BMAC_ENABLE,		heathrow_bmac_enable },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	heathrow_sound_enable },
+	{ PMAC_FTR_SLEEP_STATE,		heathrow_sleep_state },
+	{ 0, NULL }
+};
+
+/* Core99 & MacRISC 2 machines (all machines released since the
+ * iBook (included), that is all AGP machines, except pangea
+ * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
+ * used on iBook2 & iMac "flow power".
+ */
+static struct feature_table_entry core99_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	core99_modem_enable },
+	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
+	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
+	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
+	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
+	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
+	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
+	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
+	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
+#ifdef CONFIG_SMP
+	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
+#endif /* CONFIG_SMP */
+	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
+	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
+	{ 0, NULL }
+};
+
+/* Pangea features
+ */
+static struct feature_table_entry pangea_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
+	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
+	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
+	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
+	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
+	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
+	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
+	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
+	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
+	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
+	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
+	{ 0, NULL }
+};
+	
+static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
+	/* Warning: ordering is important as some models may claim
+	 * beeing compatible with several types
+	 */
+	{	"AAPL,8500",			"PowerMac 8500/8600",
+		PMAC_TYPE_PSURGE,		NULL,
+		0
+	},
+	{	"AAPL,9500",			"PowerMac 9500/9600",
+		PMAC_TYPE_PSURGE,		NULL,
+		0
+	},
+	{	"AAPL,7500",			"PowerMac 7500",
+		PMAC_TYPE_PSURGE,		NULL,
+		0
+	},
+	{	"AAPL,ShinerESB",		"Apple Network Server",
+		PMAC_TYPE_ANS,			NULL,
+		0
+	},
+	{	"AAPL,e407",			"Alchemy",
+		PMAC_TYPE_ALCHEMY,		NULL,
+		0
+	},
+	{	"AAPL,e411",			"Gazelle",
+		PMAC_TYPE_GAZELLE,		NULL,
+		0
+	},
+	{	"AAPL,3400/2400",		"PowerBook 3400",
+		PMAC_TYPE_HOOPER,		ohare_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"AAPL,3500",			"PowerBook 3500",
+		PMAC_TYPE_KANGA,		ohare_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"AAPL,Gossamer",		"PowerMac G3 (Gossamer)",
+		PMAC_TYPE_GOSSAMER,		heathrow_desktop_features,
+		0
+	},
+	{	"AAPL,PowerMac G3",		"PowerMac G3 (Silk)",
+		PMAC_TYPE_SILK,			heathrow_desktop_features,
+		0
+	},
+	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
+		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"AAPL,PowerBook1,1",		"PowerBook 101 (Lombard)",
+		PMAC_TYPE_101_PBOOK,		paddington_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"iMac,1",			"iMac (first generation)",
+		PMAC_TYPE_ORIG_IMAC,		paddington_features,
+		0
+	},
+	{	"PowerMac4,1",			"iMac \"Flower Power\"",
+		PMAC_TYPE_PANGEA_IMAC,		pangea_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerBook4,3",			"iBook 2 with 14\" LCD",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerBook4,2",			"iBook 2 with 14\" LCD",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerBook4,1",			"iBook 2",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerMac4,2",			"Flat panel iMac",
+		PMAC_TYPE_FLAT_PANEL_IMAC,	pangea_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerMac1,1",			"Blue&White G3",
+		PMAC_TYPE_YOSEMITE,		paddington_features,
+		0
+	},
+	{	"PowerMac1,2",			"PowerMac G4 PCI Graphics",
+		PMAC_TYPE_YIKES,		paddington_features,
+		0
+	},
+	{	"PowerBook2,1",			"iBook (first generation)",
+		PMAC_TYPE_ORIG_IBOOK,		core99_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerMac3,1",			"PowerMac G4 AGP Graphics",
+		PMAC_TYPE_SAWTOOTH,		core99_features,
+		0
+	},
+	{	"PowerMac3,2",			"PowerMac G4 AGP Graphics",
+		PMAC_TYPE_SAWTOOTH,		core99_features,
+		0
+	},
+	{	"PowerMac3,3",			"PowerMac G4 AGP Graphics",
+		PMAC_TYPE_SAWTOOTH,		core99_features,
+		0
+	},
+	{	"PowerMac2,1",			"iMac FireWire",
+		PMAC_TYPE_FW_IMAC,		core99_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerMac2,2",			"iMac FireWire",
+		PMAC_TYPE_FW_IMAC,		core99_features,
+		PMAC_MB_CAN_SLEEP
+	},
+	{	"PowerBook2,2",			"iBook FireWire",
+		PMAC_TYPE_FW_IBOOK,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerMac5,1",			"PowerMac G4 Cube",
+		PMAC_TYPE_CUBE,			core99_features,
+	},
+	{	"PowerMac3,4",			"PowerMac G4 Silver",
+		PMAC_TYPE_QUICKSILVER,		core99_features,
+		0
+	},
+	{	"PowerMac3,5",			"PowerMac G4 Silver",
+		PMAC_TYPE_QUICKSILVER,		core99_features,
+		0
+	},
+	{	"PowerBook3,1",			"PowerBook Pismo",
+		PMAC_TYPE_PISMO,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerBook3,2",			"PowerBook Titanium",
+		PMAC_TYPE_TITANIUM,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerBook3,3",			"PowerBook Titanium II",
+		PMAC_TYPE_TITANIUM2,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+	{	"PowerBook3,4",			"PowerBook Titanium III",
+		PMAC_TYPE_TITANIUM3,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
+};
+
+/*
+ * The toplevel feature_call callback
+ */
+int __pmac
+pmac_do_feature_call(unsigned int selector, ...)
+{
+	struct device_node* node;
+	int param, value, i;
+	feature_call func = NULL;
+	va_list args;
+	
+	if (pmac_mb.features)
+		for (i=0; pmac_mb.features[i].function; i++)
+			if (pmac_mb.features[i].selector == selector) {
+				func = pmac_mb.features[i].function;
+				break;
+			}
+	if (!func)
+		for (i=0; any_features[i].function; i++)
+			if (any_features[i].selector == selector) {
+				func = any_features[i].function;
+				break;
+			}
+	if (!func)
+		return -ENODEV;
+
+	va_start(args, selector);
+	node = (struct device_node*)va_arg(args, void*);
+	param = va_arg(args, int);
+	value = va_arg(args, int);
+	va_end(args);
+
+	return func(node, param, value);
+}
+
+static int __init
+probe_motherboard(void)
+{
+	int i;
+	struct macio_chip* macio = &macio_chips[0];
+
+	/* Lookup known motherboard type in device-tree */
+	for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+	    if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
+		pmac_mb = pmac_mb_defs[i];
+		goto found;
+	    }
+	}
+
+	/* Fallback to selection depending on mac-io chip type */
+	switch(macio->type) {
+	    case macio_grand_central:
+		pmac_mb.model_id = PMAC_TYPE_PSURGE;
+		pmac_mb.model_name = "Unknown PowerSurge";
+		break;
+	    case macio_ohare:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
+		pmac_mb.model_name = "Unknown OHare-based";
+	    	break;
+	    case macio_heathrow:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
+		pmac_mb.model_name = "Unknown Heathrow-based";
+		pmac_mb.features = heathrow_desktop_features;
+		break;
+	    case macio_paddington:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
+		pmac_mb.model_name = "Unknown Paddington-based";
+	    	pmac_mb.features = paddington_features;
+		break;
+	    case macio_keylargo:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
+		pmac_mb.model_name = "Unknown Keylargo-based";
+	    	pmac_mb.features = core99_features;
+		break;
+	    case macio_pangea:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
+		pmac_mb.model_name = "Unknown Pangea-based";
+	    	pmac_mb.features = pangea_features;
+		break;
+	    default:
+	    	return -ENODEV;
+	}
+found:
+	/* Fixup Hooper vs. Comet */
+	if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
+		u32* mach_id_ptr = (u32*)ioremap(0xf3000034, 4);
+		if (!mach_id_ptr)
+			return -ENODEV;
+		/* Here, I used to disable the media-bay on comet. It
+		 * appears this is wrong, the floppy connector is actually
+		 * a kind of media-bay and works with the current driver.
+		 */
+		if ((*mach_id_ptr) & 0x20000000UL)
+			pmac_mb.model_id = PMAC_TYPE_COMET;
+		iounmap(mach_id_ptr);
+	}
+
+	/* Set default value of powersave_nap on machines that support it.
+	 * It appears that uninorth rev 3 has a problem with it, we don't
+	 * enable it on those. In theory, the flush-on-lock property is
+	 * supposed to be set when not supported, but I'm not very confident
+	 * that all Apple OF revs did it properly, I do it the paranoid way.
+	 */
+	while (uninorth_base && uninorth_rev > 3) {
+		struct device_node* np = find_path_device("/cpus");
+		u32 pvr = mfspr(PVR);
+		if (!np || !np->child) {
+			printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
+			break;
+		}
+		np = np->child;
+		/* Nap mode not supported on SMP */
+		if (np->sibling)
+			break;
+		/* Nap mode not supported if flush-on-lock property is present */
+		if (get_property(np, "flush-on-lock", NULL))
+			break;
+		/* Some 7450 may have problem with NAP mode too ... */
+		if (((pvr >> 16) == 0x8000) && ((pvr & 0xffff) < 0x0201))
+			break;
+		powersave_nap = 1;
+		printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
+		break;
+	}
+
+	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
+	return 0;
+}
+
+/* Initialize the Core99 UniNorth host bridge and memory controller
+ */
+static void __init
+probe_uninorth(void)
+{
+	unsigned long actrl;
+	
+	/* Locate core99 Uni-N */
+	uninorth_node = find_devices("uni-n");
+	if (uninorth_node && uninorth_node->n_addrs > 0) {
+		uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x1000);
+		uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+	} else
+		uninorth_node = NULL;
+		
+	if (!uninorth_node)
+		return;
+	
+	printk(KERN_INFO "Found Uninorth memory controller & host bridge, revision: %d\n",
+			uninorth_rev);
+
+	/* Set the arbitrer QAck delay according to what Apple does
+	 */
+	if (uninorth_rev < 0x10) {
+		actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
+		actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
+			UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+		UN_OUT(UNI_N_ARB_CTRL, actrl);
+	}
+}	
+
+static void __init
+probe_one_macio(const char* name, const char* compat, int type)
+{
+	struct device_node*	node;
+	int			i;
+	volatile u32*		base;
+	u32*			revp;
+	
+	node = find_devices(name);
+	if (!node || !node->n_addrs)
+		return;
+	if (compat)
+		do {
+			if (device_is_compatible(node, compat))
+				break;
+			node = node->next;
+		} while (node);
+	if (!node)
+		return;
+	for(i=0; i<MAX_MACIO_CHIPS; i++) {
+		if (!macio_chips[i].of_node)
+			break;
+		if (macio_chips[i].of_node == node)
+			return;
+	}
+	if (i >= MAX_MACIO_CHIPS) {
+		printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
+		printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
+		return;
+	}
+	base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size);
+	if (!base) {
+		printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
+		return;
+	}
+	if (type == macio_keylargo) {
+		u32* did = (u32 *)get_property(node, "device-id", NULL);
+		if (*did == 0x00000025)
+			type = macio_pangea;
+	}
+	macio_chips[i].of_node	= node;
+	macio_chips[i].type	= type;
+	macio_chips[i].base	= base;
+	macio_chips[i].flags	= MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
+	revp = (u32 *)get_property(node, "revision-id", NULL);
+	if (revp)
+		macio_chips[i].rev = *revp;
+	printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
+		macio_names[type], macio_chips[i].rev, macio_chips[i].base);
+}
+
+static int __init
+probe_macios(void)
+{
+	/* Warning, ordering is important */
+	probe_one_macio("gc", NULL, macio_grand_central);
+	probe_one_macio("ohare", NULL, macio_ohare);
+	probe_one_macio("pci106b,7", NULL, macio_ohareII);
+	probe_one_macio("mac-io", "keylargo", macio_keylargo);
+	probe_one_macio("mac-io", "paddington", macio_paddington);
+	probe_one_macio("mac-io", "gatwick", macio_gatwick);
+	probe_one_macio("mac-io", "heathrow", macio_heathrow);
+
+	/* Make sure the "main" macio chip appear first */
+	if (macio_chips[0].type == macio_gatwick
+	    && macio_chips[1].type == macio_heathrow) {
+		struct macio_chip temp = macio_chips[0];
+		macio_chips[0] = macio_chips[1];
+		macio_chips[1] = temp;
+	}
+	if (macio_chips[0].type == macio_ohareII
+	    && macio_chips[1].type == macio_ohare) {
+		struct macio_chip temp = macio_chips[0];
+		macio_chips[0] = macio_chips[1];
+		macio_chips[1] = temp;
+	}
+
+	return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
+}
+
+static void __init
+initial_serial_shutdown(struct device_node* np)
+{
+	int len;
+	struct slot_names_prop {
+		int	count;
+		char	name[1];
+	} *slots;
+	char *conn;
+	int port_type = PMAC_SCC_ASYNC;
+	int modem = 0;
+	
+	slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
+	conn = get_property(np, "AAPL,connector", &len);
+	if (conn && (strcmp(conn, "infrared") == 0))
+		port_type = PMAC_SCC_IRDA;
+	else if (device_is_compatible(np, "cobalt"))
+		modem = 1;
+	else if (slots && slots->count > 0) {
+		if (strcmp(slots->name, "IrDA") == 0)
+			port_type = PMAC_SCC_IRDA;
+		else if (strcmp(slots->name, "Modem") == 0)
+			modem = 1;
+	}
+	if (modem)
+		pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
+	pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
+}
+
+static void __init
+set_initial_features(void)
+{
+	struct device_node* np;
+	
+	/* That hack appears to be necessary for some StarMax motherboards
+	 * but I'm not too sure it was audited for side-effects on other
+	 * ohare based machines...
+	 * Since I still have difficulties figuring the right way to
+	 * differenciate them all and since that hack was there for a long
+	 * time, I'll keep it around
+	 */
+	if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
+		struct macio_chip* macio = &macio_chips[0];
+		MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
+	} else if (macio_chips[0].type == macio_ohare) {
+		struct macio_chip* macio = &macio_chips[0];
+		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+	} else if (macio_chips[1].type == macio_ohare) {
+		struct macio_chip* macio = &macio_chips[1];
+		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+	}
+
+	if (macio_chips[0].type == macio_keylargo ||
+	    macio_chips[0].type == macio_pangea) {
+		/* Enable GMAC for now for PCI probing. It will be disabled
+		 * later on after PCI probe
+		 */
+		np = find_devices("ethernet");
+		while(np) {
+			if (np->parent
+			    && device_is_compatible(np->parent, "uni-north")
+			    && device_is_compatible(np, "gmac"))
+				core99_gmac_enable(np, 0, 1);
+			np = np->next;
+		}
+
+		/* Enable FW before PCI probe. Will be disabled later on
+		 * Note: We should have a batter way to check that we are
+		 * dealing with uninorth internal cell and not a PCI cell
+		 * on the external PCI. The code below works though.
+		 */
+		np = find_devices("firewire");
+		while(np) {
+			if (np->parent
+			    && device_is_compatible(np->parent, "uni-north")
+			    && (device_is_compatible(np, "pci106b,18") || 
+	     		        device_is_compatible(np, "pci106b,30") ||
+	     		        device_is_compatible(np, "pci11c1,5811"))) {
+				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
+				core99_firewire_enable(np, 0, 1);
+			}
+			np = np->next;
+		}
+		
+		/* Switch airport off */
+		np = find_devices("radio");
+		while(np) {
+			if (np && np->parent == macio_chips[0].of_node) {
+				macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
+				core99_airport_enable(np, 0, 0);
+			}
+			np = np->next;
+		}
+	}
+
+	/* On all machines that support sound PM, switch sound off */
+	if (macio_chips[0].of_node)
+		pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
+			macio_chips[0].of_node, 0, 0);
+
+	/* While on some desktop G3s, we turn it back on */
+	if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
+		&& (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
+		    pmac_mb.model_id == PMAC_TYPE_SILK)) {
+		struct macio_chip* macio = &macio_chips[0];
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+	}
+
+
+	/* On all machines, switch modem & serial ports off */
+	np = find_devices("ch-a");
+	while(np) {
+		initial_serial_shutdown(np);
+		np = np->next;
+	}
+	np = find_devices("ch-b");
+	while(np) {
+		initial_serial_shutdown(np);
+		np = np->next;
+	}
+	
+	/* Let hardware settle down */
+	mdelay(10);
+}
+
+void __init
+pmac_feature_init(void)
+{
+	/* Detect the UniNorth memory controller */
+	probe_uninorth();
+
+	/* Probe mac-io controllers */
+	if (probe_macios()) {
+		printk(KERN_WARNING "No mac-io chip found\n");
+		return;
+	}
+
+	/* Probe machine type */
+	if (probe_motherboard())
+		printk(KERN_WARNING "Unknown PowerMac !\n");
+
+	/* Set some initial features (turn off some chips that will
+	 * be later turned on)
+	 */
+	set_initial_features();
+}
+
+void __init
+pmac_feature_late_init(void)
+{
+	struct device_node* np;
+	
+	/* Request some resources late */
+	if (uninorth_node)
+		request_OF_resource(uninorth_node, 0, NULL);
+	np = find_devices("hammerhead");
+	if (np)
+		request_OF_resource(np, 0, NULL);
+	np = find_devices("interrupt-controller");
+	if (np)
+		request_OF_resource(np, 0, NULL);
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/pmac_nvram.c linux-2.4.20-pre2/arch/ppc/platforms/pmac_nvram.c
--- linux-2.4.20-pre1/arch/ppc/platforms/pmac_nvram.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/pmac_nvram.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,402 @@
+/*
+ * BK Id: SCCS/s.pmac_nvram.c 1.17 12/01/01 20:09:06 benh
+ */
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+#undef DEBUG
+
+#define NVRAM_SIZE		0x2000	/* 8kB of non-volatile RAM */
+
+#define CORE99_SIGNATURE	0x5a
+#define CORE99_ADLER_START	0x14
+
+/* Core99 nvram is a flash */
+#define CORE99_FLASH_STATUS_DONE	0x80
+#define CORE99_FLASH_STATUS_ERR		0x38
+#define CORE99_FLASH_CMD_ERASE_CONFIRM	0xd0
+#define CORE99_FLASH_CMD_ERASE_SETUP	0x20
+#define CORE99_FLASH_CMD_RESET		0xff
+#define CORE99_FLASH_CMD_WRITE_SETUP	0x40
+
+/* CHRP NVRAM header */
+struct chrp_header {
+  u8		signature;
+  u8		cksum;
+  u16		len;
+  char          name[12];
+  u8		data[0];
+};
+
+struct core99_header {
+  struct chrp_header	hdr;
+  u32			adler;
+  u32			generation;
+  u32			reserved[2];
+};
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+static int nvram_mult, is_core_99;
+static int core99_bank = 0;
+static int nvram_partitions[3];
+
+/* FIXME: kmalloc fails to allocate the image now that I had to move it
+ *        before time_init(). For now, I allocate a static buffer here
+ *        but it's a waste of space on all but core99 machines
+ */
+#if 0
+static char* nvram_image;
+#else
+static char nvram_image[NVRAM_SIZE] __pmacdata;
+#endif
+
+extern int pmac_newworld;
+
+static u8 __openfirmware
+chrp_checksum(struct chrp_header* hdr)
+{
+	u8 *ptr;
+	u16 sum = hdr->signature;
+	for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
+		sum += *ptr;
+	while (sum > 0xFF)
+		sum = (sum & 0xFF) + (sum>>8);
+	return sum;
+}
+
+static u32 __pmac
+core99_calc_adler(u8 *buffer)
+{
+	int cnt;
+	u32 low, high;
+
+   	buffer += CORE99_ADLER_START;
+	low = 1;
+	high = 0;
+	for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+		if ((cnt % 5000) == 0) {
+			high  %= 65521UL;
+			high %= 65521UL;
+		}
+		low += buffer[cnt];
+		high += low;
+	}
+	low  %= 65521UL;
+	high %= 65521UL;
+  
+	return (high << 16) | low;
+}
+
+static u32 __pmac
+core99_check(u8* datas)
+{
+	struct core99_header* hdr99 = (struct core99_header*)datas;
+
+	if (hdr99->hdr.signature != CORE99_SIGNATURE) {
+#ifdef DEBUG
+		printk("Invalid signature\n");
+#endif		
+		return 0;
+	}
+	if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
+#ifdef DEBUG
+		printk("Invalid checksum\n");
+#endif
+		return 0;
+	}
+	if (hdr99->adler != core99_calc_adler(datas)) {
+#ifdef DEBUG
+		printk("Invalid adler\n");
+#endif
+		return 0;
+	}
+	return hdr99->generation;
+}
+
+static int __pmac
+core99_erase_bank(int bank)
+{
+	int stat, i;
+	
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	
+	out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
+	out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
+	do { stat = in_8(base); }
+	while(!(stat & CORE99_FLASH_STATUS_DONE));
+	out_8(base, CORE99_FLASH_CMD_RESET);
+	if (stat & CORE99_FLASH_STATUS_ERR) {
+		printk("nvram: flash error 0x%02x on erase !\n", stat);
+		return -ENXIO;
+	}
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != 0xff) {
+			printk("nvram: flash erase failed !\n");
+			return -ENXIO;
+		}
+	return 0;
+}
+
+static int __pmac
+core99_write_bank(int bank, u8* datas)
+{
+	int i, stat = 0;
+	
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	
+	for (i=0; i<NVRAM_SIZE; i++) {
+		out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
+		out_8(base+i, datas[i]);
+		do { stat = in_8(base); }
+		while(!(stat & CORE99_FLASH_STATUS_DONE));
+		if (stat & CORE99_FLASH_STATUS_ERR)
+			break;
+	}
+	out_8(base, CORE99_FLASH_CMD_RESET);
+	if (stat & CORE99_FLASH_STATUS_ERR) {
+		printk("nvram: flash error 0x%02x on write !\n", stat);
+		return -ENXIO;
+	}
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != datas[i]) {
+			printk("nvram: flash write failed !\n");
+			return -ENXIO;
+		}
+	return 0;	
+}
+
+static void __init
+lookup_partitions(void)
+{
+	u8 buffer[17];
+	int i, offset;
+	struct chrp_header* hdr;
+
+	if (pmac_newworld) {
+		nvram_partitions[pmac_nvram_OF] = -1;
+		nvram_partitions[pmac_nvram_XPRAM] = -1;
+		nvram_partitions[pmac_nvram_NR] = -1;
+		hdr = (struct chrp_header *)buffer;
+	
+		offset = 0;
+		buffer[16] = 0;
+		do {
+			for (i=0;i<16;i++)
+				buffer[i] = nvram_read_byte(offset+i);
+			if (!strcmp(hdr->name, "common"))
+				nvram_partitions[pmac_nvram_OF] = offset + 0x10;
+			if (!strcmp(hdr->name, "APL,MacOS75")) {
+				nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
+				nvram_partitions[pmac_nvram_NR] = offset + 0x110;
+			}
+			offset += (hdr->len * 0x10);
+		} while(offset < NVRAM_SIZE);
+	} else {
+		nvram_partitions[pmac_nvram_OF] = 0x1800;
+		nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
+		nvram_partitions[pmac_nvram_NR] = 0x1400;
+	}	
+#ifdef DEBUG
+	printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
+	printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
+	printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+#endif	
+}
+
+void __init
+pmac_nvram_init(void)
+{
+	struct device_node *dp;
+
+	nvram_naddrs = 0;
+
+	dp = find_devices("nvram");
+	if (dp == NULL) {
+		printk(KERN_ERR "Can't find NVRAM device\n");
+		return;
+	}
+	nvram_naddrs = dp->n_addrs;
+	is_core_99 = device_is_compatible(dp, "nvram,flash");
+	if (is_core_99) {
+		int i;
+		u32 gen_bank0, gen_bank1;
+		
+		if (nvram_naddrs < 1) {
+			printk(KERN_ERR "nvram: no address\n");
+			return;
+		}
+#if 0
+		nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
+		if (!nvram_image) {
+			printk(KERN_ERR "nvram: can't allocate image\n");
+			return;
+		}
+#endif
+		nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+#ifdef DEBUG
+		printk("nvram: Checking bank 0...\n");
+#endif
+		gen_bank0 = core99_check((u8 *)nvram_data);
+		gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
+		core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
+#ifdef DEBUG
+		printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
+		printk("nvram: Active bank is: %d\n", core99_bank);
+#endif
+		for (i=0; i<NVRAM_SIZE; i++)
+			nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
+	} else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+		nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
+				     dp->addrs[0].size);
+		nvram_mult = 1;
+	} else if (nvram_naddrs == 1) {
+		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+		nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
+	} else if (nvram_naddrs == 2) {
+		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+	} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
+		nvram_naddrs = -1;
+	} else {
+		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
+		       nvram_naddrs);
+	}
+	lookup_partitions();
+}
+
+void __pmac
+pmac_nvram_update(void)
+{
+	struct core99_header* hdr99;
+	
+	if (!is_core_99 || !nvram_data || !nvram_image)
+		return;
+	if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
+		NVRAM_SIZE))
+		return;
+#ifdef DEBUG
+	printk("Updating nvram...\n");
+#endif
+	hdr99 = (struct core99_header*)nvram_image;
+	hdr99->generation++;
+	hdr99->hdr.signature = CORE99_SIGNATURE;
+	hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
+	hdr99->adler = core99_calc_adler(nvram_image);
+	core99_bank = core99_bank ? 0 : 1;
+	if (core99_erase_bank(core99_bank)) {
+		printk("nvram: Error erasing bank %d\n", core99_bank);
+		return;
+	}
+	if (core99_write_bank(core99_bank, nvram_image))
+		printk("nvram: Error writing bank %d\n", core99_bank);
+}
+
+unsigned char __openfirmware
+nvram_read_byte(int addr)
+{
+	switch (nvram_naddrs) {
+#ifdef CONFIG_ADB_PMU
+	case -1: {
+		struct adb_request req;
+
+		if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
+				(addr >> 8) & 0xff, addr & 0xff))
+			break;
+		while (!req.complete)
+			pmu_poll();
+		return req.reply[0];
+	}
+#endif
+	case 1:
+		if (is_core_99)
+			return nvram_image[addr];
+		return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
+	case 2:
+		*nvram_addr = addr >> 5;
+		eieio();
+		return nvram_data[(addr & 0x1f) << 4];
+	}
+	return 0;
+}
+
+void __openfirmware
+nvram_write_byte(unsigned char val, int addr)
+{
+	switch (nvram_naddrs) {
+#ifdef CONFIG_ADB_PMU
+	case -1: {
+		struct adb_request req;
+
+		if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
+				(addr >> 8) & 0xff, addr & 0xff, val))
+			break;
+		while (!req.complete)
+			pmu_poll();
+		break;
+	}
+#endif
+	case 1:
+		if (is_core_99) {
+			nvram_image[addr] = val;
+			break;
+		}
+		nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
+		break;
+	case 2:
+		*nvram_addr = addr >> 5;
+		eieio();
+		nvram_data[(addr & 0x1f) << 4] = val;
+		break;
+	}
+	eieio();
+}
+
+int __pmac
+pmac_get_partition(int partition)
+{
+	return nvram_partitions[partition];
+}
+
+u8 __pmac
+pmac_xpram_read(int xpaddr)
+{
+	int offset = nvram_partitions[pmac_nvram_XPRAM];
+	
+	if (offset < 0)
+		return 0;
+		
+	return nvram_read_byte(xpaddr + offset);
+}
+
+void __pmac
+pmac_xpram_write(int xpaddr, u8 data)
+{
+	int offset = nvram_partitions[pmac_nvram_XPRAM];
+	
+	if (offset < 0)
+		return;
+		
+	nvram_write_byte(xpaddr + offset, data);
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/pmac_pci.c linux-2.4.20-pre2/arch/ppc/platforms/pmac_pci.c
--- linux-2.4.20-pre1/arch/ppc/platforms/pmac_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/pmac_pci.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,613 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+
+#undef DEBUG
+
+static void add_bridges(struct device_node *dev);
+
+/* XXX Could be per-controller, but I don't think we risk anything by
+ * assuming we won't have both UniNorth and Bandit */
+static int has_uninorth;
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define BANDIT_DEVID_2	8
+#define BANDIT_REVID	3
+
+#define BANDIT_DEVNUM	11
+#define BANDIT_MAGIC	0x50
+#define BANDIT_COHERENT	0x40
+
+static int __init
+fixup_one_level_bus_range(struct device_node *node, int higher)
+{
+	for (; node != 0;node = node->sibling) {
+		int * bus_range;
+		unsigned int *class_code;			
+		int len;
+
+		/* For PCI<->PCI bridges or CardBus bridges, we go down */
+		class_code = (unsigned int *) get_property(node, "class-code", 0);
+		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+			continue;
+		bus_range = (int *) get_property(node, "bus-range", &len);
+		if (bus_range != NULL && len > 2 * sizeof(int)) {
+			if (bus_range[1] > higher)
+				higher = bus_range[1];
+		}
+		higher = fixup_one_level_bus_range(node->child, higher);
+	}
+	return higher;
+}
+
+/* This routine fixes the "bus-range" property of all bridges in the
+ * system since they tend to have their "last" member wrong on macs
+ * 
+ * Note that the bus numbers manipulated here are OF bus numbers, they
+ * are not Linux bus numbers.
+ */
+static void __init
+fixup_bus_range(struct device_node *bridge)
+{
+	int * bus_range;
+	int len;
+	
+	/* Lookup the "bus-range" property for the hose */		
+	bus_range = (int *) get_property(bridge, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int)) {
+		printk(KERN_WARNING "Can't get bus-range for %s\n",
+			       bridge->full_name);
+		return;
+	}
+	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+}
+
+/*
+ * Apple MacRISC (UniNorth, Bandit, Chaos) PCI controllers.
+ * 
+ * The "Bandit" version is present in all early PCI PowerMacs,
+ * and up to the first ones using Grackle. Some machines may
+ * have 2 bandit controllers (2 PCI busses).
+ * 
+ * "Chaos" is used in some "Bandit"-type machines as a bridge
+ * for the separate display bus. It is accessed the same
+ * way as bandit, but cannot be probed for devices. It therefore
+ * has its own config access functions.
+ *
+ * The "UniNorth" version is present in all Core99 machines
+ * (iBook, G4, new IMacs, and all the recent Apple machines).
+ * It contains 3 controllers in one ASIC.
+ */
+
+#define MACRISC_CFA0(devfn, off)	\
+	((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+	| (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+	| (((unsigned long)(off)) & 0xFCUL))
+
+#define MACRISC_CFA1(bus, devfn, off)	\
+	((((unsigned long)(bus)) << 16) \
+	|(((unsigned long)(devfn)) << 8) \
+	|(((unsigned long)(off)) & 0xFCUL) \
+	|1UL)
+	
+static unsigned int __pmac
+macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset)
+{
+	unsigned int caddr;
+	
+	if (bus == hose->first_busno) {
+		if (dev_fn < (11 << 3))
+			return 0;
+		caddr = MACRISC_CFA0(dev_fn, offset);
+	} else
+		caddr = MACRISC_CFA1(bus, dev_fn, offset);
+	
+	/* Uninorth will return garbage if we don't read back the value ! */
+	do {
+		out_le32(hose->cfg_addr, caddr);
+	} while(in_le32(hose->cfg_addr) != caddr);
+
+	offset &= has_uninorth ? 0x07 : 0x03;
+	return (unsigned int)(hose->cfg_data) + (unsigned int)offset;
+}
+
+#define cfg_read(val, addr, type, op, op2)	\
+	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op, op2)	\
+	op((type *)(addr), (val)); (void) op2((type *)(addr))
+
+#define cfg_read_bad(val, size)		*val = bad_##size;
+#define cfg_write_bad(val, size)
+
+#define bad_byte	0xff
+#define bad_word	0xffff
+#define bad_dword	0xffffffffU
+
+#define MACRISC_PCI_OP(rw, size, type, op, op2)				    \
+static int __pmac							    \
+macrisc_##rw##_config_##size(struct pci_dev *dev, int off, type val)	    \
+{									    \
+	struct pci_controller *hose = dev->sysdata;			    \
+	unsigned int addr;						    \
+									    \
+	addr = macrisc_cfg_access(hose, dev->bus->number, dev->devfn, off); \
+	if (!addr) {							    \
+		cfg_##rw##_bad(val, size)				    \
+		return PCIBIOS_DEVICE_NOT_FOUND;			    \
+	}								    \
+	cfg_##rw(val, addr, type, op, op2);				    \
+	return PCIBIOS_SUCCESSFUL;					    \
+}
+
+MACRISC_PCI_OP(read, byte, u8 *, in_8, x)
+MACRISC_PCI_OP(read, word, u16 *, in_le16, x)
+MACRISC_PCI_OP(read, dword, u32 *, in_le32, x)
+MACRISC_PCI_OP(write, byte, u8, out_8, in_8)
+MACRISC_PCI_OP(write, word, u16, out_le16, in_le16)
+MACRISC_PCI_OP(write, dword, u32, out_le32, in_le32)
+
+static struct pci_ops macrisc_pci_ops =
+{
+	macrisc_read_config_byte,
+	macrisc_read_config_word,
+	macrisc_read_config_dword,
+	macrisc_write_config_byte,
+	macrisc_write_config_word,
+	macrisc_write_config_dword
+};
+
+/*
+ * Verifiy that a specific (bus, dev_fn) exists on chaos
+ */
+static int __pmac
+chaos_validate_dev(struct pci_dev *dev, int offset)
+{
+	if(pci_device_to_OF_node(dev) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if((dev->vendor == 0x106b) && (dev->device == 3) && (offset >= 0x10) &&
+	    (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) {
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#define CHAOS_PCI_OP(rw, size, type)					\
+static int __pmac							\
+chaos_##rw##_config_##size(struct pci_dev *dev, int off, type val)	\
+{									\
+	int result = chaos_validate_dev(dev, off);			\
+	if(result == PCIBIOS_BAD_REGISTER_NUMBER) {			\
+		cfg_##rw##_bad(val, size)				\
+		return PCIBIOS_BAD_REGISTER_NUMBER;			\
+	}								\
+	if(result == PCIBIOS_SUCCESSFUL)				\
+		return macrisc_##rw##_config_##size(dev, off, val);	\
+	return result;							\
+}
+
+CHAOS_PCI_OP(read, byte, u8 *)
+CHAOS_PCI_OP(read, word, u16 *)
+CHAOS_PCI_OP(read, dword, u32 *)
+CHAOS_PCI_OP(write, byte, u8)
+CHAOS_PCI_OP(write, word, u16)
+CHAOS_PCI_OP(write, dword, u32) 
+
+static struct pci_ops chaos_pci_ops =
+{
+	chaos_read_config_byte,
+	chaos_read_config_word,
+	chaos_read_config_dword,
+	chaos_write_config_byte,
+	chaos_write_config_word,
+	chaos_write_config_dword
+};
+
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we could clean this up using the hose ops directly.
+ */
+static void __init
+init_bandit(struct pci_controller *bp)
+{
+	unsigned int vendev, magic;
+	int rev;
+
+	/* read the word at offset 0 in config space for device 11 */
+	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+	udelay(2);
+	vendev = in_le32((volatile unsigned int *)bp->cfg_data);
+	if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + 
+			PCI_VENDOR_ID_APPLE) {
+		/* read the revision id */
+		out_le32(bp->cfg_addr,
+			 (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+		udelay(2);
+		rev = in_8(bp->cfg_data);
+		if (rev != BANDIT_REVID)
+			printk(KERN_WARNING
+			       "Unknown revision %d for bandit\n", rev);
+	} else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
+		printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+		return;
+	}
+
+	/* read the word at offset 0x50 */
+	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+	udelay(2);
+	magic = in_le32((volatile unsigned int *)bp->cfg_data);
+	if ((magic & BANDIT_COHERENT) != 0)
+		return;
+	magic |= BANDIT_COHERENT;
+	udelay(2);
+	out_le32((volatile unsigned int *)bp->cfg_data, magic);
+	printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
+}
+
+
+/*
+ * Tweak the PCI-PCI bridge chip on the blue & white G3s.
+ */
+static void __init
+init_p2pbridge(void)
+{
+	struct device_node *p2pbridge;
+	struct pci_controller* hose;
+	u8 bus, devfn;
+	u16 val;
+
+	/* XXX it would be better here to identify the specific
+	   PCI-PCI bridge chip we have. */
+	if ((p2pbridge = find_devices("pci-bridge")) == 0
+	    || p2pbridge->parent == NULL
+	    || strcmp(p2pbridge->parent->name, "pci") != 0)
+		return;
+	if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
+#ifdef DEBUG
+		printk("Can't find PCI infos for PCI<->PCI bridge\n");
+#endif		
+		return;
+	}
+	/* Warning: At this point, we have not yet renumbered all busses. 
+	 * So we must use OF walking to find out hose
+	 */
+	hose = pci_find_hose_for_OF_device(p2pbridge);
+	if (!hose) {
+#ifdef DEBUG
+		printk("Can't find hose for PCI<->PCI bridge\n");
+#endif		
+		return;
+	}
+	if (early_read_config_word(hose, bus, devfn,
+				   PCI_BRIDGE_CONTROL, &val) < 0) {
+		printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
+		return;
+	}
+	val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
+	early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
+}
+
+void __init
+pmac_find_bridges(void)
+{
+	add_bridges(find_devices("bandit"));
+	add_bridges(find_devices("chaos"));
+	add_bridges(find_devices("pci"));
+	init_p2pbridge();
+}
+
+#define GRACKLE_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
+				 | (((o) & ~3) << 24))
+
+#define GRACKLE_PICR1_STG		0x00000040
+#define GRACKLE_PICR1_LOOPSNOOP		0x00000010
+
+/* N.B. this is called before bridges is initialized, so we can't
+   use grackle_pcibios_{read,write}_config_dword. */
+static inline void grackle_set_stg(struct pci_controller* bp, int enable)
+{
+	unsigned int val;
+
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	val = in_le32((volatile unsigned int *)bp->cfg_data);
+	val = enable? (val | GRACKLE_PICR1_STG) :
+		(val & ~GRACKLE_PICR1_STG);
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	out_le32((volatile unsigned int *)bp->cfg_data, val);
+	(void)in_le32((volatile unsigned int *)bp->cfg_data);
+}
+
+static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
+{
+	unsigned int val;
+
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	val = in_le32((volatile unsigned int *)bp->cfg_data);
+	val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
+		(val & ~GRACKLE_PICR1_LOOPSNOOP);
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	out_le32((volatile unsigned int *)bp->cfg_data, val);
+	(void)in_le32((volatile unsigned int *)bp->cfg_data);
+}
+
+static int __init
+setup_uninorth(struct pci_controller* hose, struct reg_property* addr)
+{
+	pci_assign_all_busses = 1;
+	has_uninorth = 1;
+	hose->ops = &macrisc_pci_ops;
+	hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+	hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+	/* We "know" that the bridge at f2000000 has the PCI slots. */
+	return addr->address == 0xf2000000;
+}
+
+static void __init
+setup_bandit(struct pci_controller* hose, struct reg_property* addr)
+{
+	hose->ops = &macrisc_pci_ops;
+	hose->cfg_addr = (volatile unsigned int *)
+		ioremap(addr->address + 0x800000, 0x1000);
+	hose->cfg_data = (volatile unsigned char *)
+		ioremap(addr->address + 0xc00000, 0x1000);
+	init_bandit(hose);
+}
+
+static void __init
+setup_chaos(struct pci_controller* hose, struct reg_property* addr)
+{
+	/* assume a `chaos' bridge */
+	hose->ops = &chaos_pci_ops;
+	hose->cfg_addr = (volatile unsigned int *)
+		ioremap(addr->address + 0x800000, 0x1000);
+	hose->cfg_data = (volatile unsigned char *)
+		ioremap(addr->address + 0xc00000, 0x1000);
+}
+
+void __init
+setup_grackle(struct pci_controller *hose)
+{
+	setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
+	if (machine_is_compatible("AAPL,PowerBook1998"))
+		grackle_set_loop_snoop(hose, 1);
+#if 0	/* Disabled for now, HW problems ??? */
+	grackle_set_stg(hose, 1);
+#endif
+}
+
+/*
+ * We assume that if we have a G3 powermac, we have one bridge called
+ * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
+ * if we have one or more bandit or chaos bridges, we don't have a MPC106.
+ */
+static void __init
+add_bridges(struct device_node *dev)
+{
+	int len;
+	struct pci_controller *hose;
+	struct reg_property *addr;
+	char* disp_name;
+	int *bus_range;
+	int first = 1, primary;
+	
+	for (; dev != NULL; dev = dev->next) {
+		addr = (struct reg_property *) get_property(dev, "reg", &len);
+		if (addr == NULL || len < sizeof(*addr)) {
+			printk(KERN_WARNING "Can't use %s: no address\n",
+			       dev->full_name);
+			continue;
+		}
+		bus_range = (int *) get_property(dev, "bus-range", &len);
+		if (bus_range == NULL || len < 2 * sizeof(int)) {
+			printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
+				       dev->full_name);
+		}
+		
+		hose = pcibios_alloc_controller();
+		if (!hose)
+			continue;
+		hose->arch_data = dev;
+		hose->first_busno = bus_range ? bus_range[0] : 0;
+		hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+		disp_name = NULL;
+		primary = first;
+		if (device_is_compatible(dev, "uni-north")) {
+			primary = setup_uninorth(hose, addr);
+			disp_name = "UniNorth";
+		} else if (strcmp(dev->name, "pci") == 0) {
+			/* XXX assume this is a mpc106 (grackle) */
+			setup_grackle(hose);
+			disp_name = "Grackle (MPC106)";
+		} else if (strcmp(dev->name, "bandit") == 0) {
+			setup_bandit(hose, addr);
+			disp_name = "Bandit";
+		} else if (strcmp(dev->name, "chaos") == 0) {
+			setup_chaos(hose, addr);
+			disp_name = "Chaos";
+			primary = 0;
+		}
+		printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
+			disp_name, addr->address, hose->first_busno, hose->last_busno);
+#ifdef DEBUG
+		printk(" ->Hose at 0x%08lx, cfg_addr=0x%08lx,cfg_data=0x%08lx\n",
+			hose, hose->cfg_addr, hose->cfg_data);
+#endif		
+		
+		/* Interpret the "ranges" property */
+		/* This also maps the I/O region and sets isa_io/mem_base */
+		pci_process_bridge_OF_ranges(hose, dev, primary);
+
+		/* Fixup "bus-range" OF property */
+		fixup_bus_range(dev);
+
+		first &= !primary;
+	}
+}
+
+static void __init
+pcibios_fixup_OF_interrupts(void)
+{	
+	struct pci_dev* dev;
+	
+	/*
+	 * Open Firmware often doesn't initialize the
+	 * PCI_INTERRUPT_LINE config register properly, so we
+	 * should find the device node and apply the interrupt
+	 * obtained from the OF device-tree
+	 */
+	pci_for_each_dev(dev) {
+		struct device_node* node = pci_device_to_OF_node(dev);
+		/* this is the node, see if it has interrupts */
+		if (node && node->n_intrs > 0)
+			dev->irq = node->intrs[0].line;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+}
+
+void __init
+pmac_pcibios_fixup(void)
+{
+	/* Fixup interrupts according to OF tree */
+	pcibios_fixup_OF_interrupts();
+}
+
+int __pmac
+pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
+{
+	struct device_node* node;
+	int updatecfg = 0;
+	int uninorth_child;
+
+	node = pci_device_to_OF_node(dev);
+
+	/* We don't want to enable USB controllers absent from the OF tree
+	 * (iBook second controller)
+	 */
+	if (dev->vendor == PCI_VENDOR_ID_APPLE
+	    && dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node)
+		return -EINVAL;
+
+	if (!node)
+		return 0;
+
+	uninorth_child = node->parent &&
+		device_is_compatible(node->parent, "uni-north");
+		
+	/* Firewire & GMAC were disabled after PCI probe, the driver is
+	 * claiming them, we must re-enable them now.
+	 */
+	if (uninorth_child && !strcmp(node->name, "firewire") && 
+	    (device_is_compatible(node, "pci106b,18") || 
+	     device_is_compatible(node, "pci106b,30") ||
+	     device_is_compatible(node, "pci11c1,5811"))) {
+		pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
+		pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
+		updatecfg = 1;
+	}
+	if (uninorth_child && !strcmp(node->name, "ethernet") && 
+	    device_is_compatible(node, "gmac")) {
+		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
+		updatecfg = 1;
+	}
+
+	if (updatecfg) {
+		u16 cmd;
+		
+		/*
+		 * Make sure PCI is correctly configured
+		 *
+		 * We use old pci_bios versions of the function since, by
+		 * default, gmac is not powered up, and so will be absent
+		 * from the kernel initial PCI lookup. 
+		 * 
+		 * Should be replaced by 2.4 new PCI mecanisms and really
+		 * regiser the device.
+		 */
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+    		pci_write_config_word(dev, PCI_COMMAND, cmd);
+    		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
+    		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
+	}
+	
+	return 0;
+}
+
+/* We power down some devices after they have been probed. They'll
+ * be powered back on later on
+ */
+void __init
+pmac_pcibios_after_init(void)
+{
+	struct device_node* nd;
+
+#ifdef CONFIG_BLK_DEV_IDE
+	struct pci_dev *dev;
+
+	/* OF fails to initialize IDE controllers on macs
+	 * (and maybe other machines)
+	 * 
+	 * Ideally, this should be moved to the IDE layer, but we need
+	 * to check specifically with Andre Hedrick how to do it cleanly
+	 * since the common IDE code seem to care about the fact that the
+	 * BIOS may have disabled a controller.
+	 * 
+	 * -- BenH
+	 */
+	pci_for_each_dev(dev) {
+		if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE)
+			pci_enable_device(dev);
+	}
+#endif /* CONFIG_BLK_DEV_IDE */
+
+	nd = find_devices("firewire");
+	while (nd) {
+		if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
+				   device_is_compatible(nd, "pci106b,30") ||
+				   device_is_compatible(nd, "pci11c1,5811"))
+		    && device_is_compatible(nd->parent, "uni-north")) {
+			pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
+			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
+		}
+		nd = nd->next;
+	}
+	nd = find_devices("ethernet");
+	while (nd) {
+		if (nd->parent && device_is_compatible(nd, "gmac")
+		    && device_is_compatible(nd->parent, "uni-north"))
+			pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
+		nd = nd->next;
+	}
+}
+
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/pmac_pic.c linux-2.4.20-pre2/arch/ppc/platforms/pmac_pic.c
--- linux-2.4.20-pre1/arch/ppc/platforms/pmac_pic.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/pmac_pic.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,528 @@
+/*
+ * BK Id: SCCS/s.pmac_pic.c 1.24 12/19/01 10:53:01 paulus
+ */
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/pci.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+
+#include "pmac_pic.h"
+
+struct pmac_irq_hw {
+        unsigned int    event;
+        unsigned int    enable;
+        unsigned int    ack;
+        unsigned int    level;
+};
+
+/* Default addresses */
+static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = {
+        (struct pmac_irq_hw *) 0xf3000020,
+        (struct pmac_irq_hw *) 0xf3000010,
+        (struct pmac_irq_hw *) 0xf4000020,
+        (struct pmac_irq_hw *) 0xf4000010,
+};
+
+#define GC_LEVEL_MASK		0x3ff00000
+#define OHARE_LEVEL_MASK	0x1ff00000
+#define HEATHROW_LEVEL_MASK	0x1ff00000
+
+static int max_irqs __pmacdata;
+static int max_real_irqs __pmacdata;
+static u32 level_mask[4] __pmacdata;
+
+static spinlock_t pmac_pic_lock __pmacdata = SPIN_LOCK_UNLOCKED;
+
+
+#define GATWICK_IRQ_POOL_SIZE        10
+static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE] __pmacdata;
+
+/*
+ * Mark an irq as "lost".  This is only used on the pmac
+ * since it can lose interrupts (see pmac_set_irq_mask).
+ * -- Cort
+ */
+void __pmac
+__set_lost(unsigned long irq_nr, int nokick)
+{
+	if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
+		atomic_inc(&ppc_n_lost_interrupts);
+		if (!nokick)
+			set_dec(1);
+	}
+}
+
+static void __pmac
+pmac_mask_and_ack_irq(unsigned int irq_nr)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+        unsigned long flags;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+                atomic_dec(&ppc_n_lost_interrupts);
+	spin_lock_irqsave(&pmac_pic_lock, flags);
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+        out_le32(&pmac_irq_hw[i]->ack, bit);
+        do {
+                /* make sure ack gets to controller before we enable
+                   interrupts */
+                mb();
+        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+                != (ppc_cached_irq_mask[i] & bit));
+	spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+        unsigned long flags;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+	spin_lock_irqsave(&pmac_pic_lock, flags);
+        /* enable unmasked interrupts */
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+
+        do {
+                /* make sure mask gets to controller before we
+                   return to user */
+                mb();
+        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+                != (ppc_cached_irq_mask[i] & bit));
+
+        /*
+         * Unfortunately, setting the bit in the enable register
+         * when the device interrupt is already on *doesn't* set
+         * the bit in the flag register or request another interrupt.
+         */
+        if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
+		__set_lost((ulong)irq_nr, nokicklost);
+	spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+static void __pmac pmac_mask_irq(unsigned int irq_nr)
+{
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr, 0);
+        mb();
+}
+
+static void __pmac pmac_unmask_irq(unsigned int irq_nr)
+{
+        set_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr, 0);
+}
+
+static void __pmac pmac_end_irq(unsigned int irq_nr)
+{
+	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+        	set_bit(irq_nr, ppc_cached_irq_mask);
+	        pmac_set_irq_mask(irq_nr, 1);
+	}
+}
+
+
+struct hw_interrupt_type pmac_pic = {
+        " PMAC-PIC ",
+        NULL,
+        NULL,
+        pmac_unmask_irq,
+        pmac_mask_irq,
+        pmac_mask_and_ack_irq,
+        pmac_end_irq,
+        NULL
+};
+
+struct hw_interrupt_type gatwick_pic = {
+	" GATWICK  ",
+	NULL,
+	NULL,
+	pmac_unmask_irq,
+	pmac_mask_irq,
+	pmac_mask_and_ack_irq,
+	pmac_end_irq,
+	NULL
+};
+
+static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int irq, bits;
+	
+	for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
+		int i = irq >> 5;
+		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
+		/* We must read level interrupts from the level register */
+		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
+		bits &= ppc_cached_irq_mask[i];
+		if (bits == 0)
+			continue;
+		irq += __ilog2(bits);
+		break;
+	}
+	/* The previous version of this code allowed for this case, we
+	 * don't.  Put this here to check for it.
+	 * -- Cort
+	 */
+	if ( irq_desc[irq].handler != &gatwick_pic )
+		printk("gatwick irq not from gatwick pic\n");
+	else
+		ppc_irq_dispatch_handler( regs, irq );
+}
+
+int
+pmac_get_irq(struct pt_regs *regs)
+{
+	int irq;
+	unsigned long bits = 0;
+
+#ifdef CONFIG_SMP
+	void psurge_smp_message_recv(struct pt_regs *);
+	
+       	/* IPI's are a hack on the powersurge -- Cort */
+       	if ( smp_processor_id() != 0 ) {
+		psurge_smp_message_recv(regs);
+		return -2;	/* ignore, already handled */
+        }
+#endif /* CONFIG_SMP */
+	for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
+		int i = irq >> 5;
+		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
+		/* We must read level interrupts from the level register */
+		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
+		bits &= ppc_cached_irq_mask[i];
+		if (bits == 0)
+			continue;
+		irq += __ilog2(bits);
+		break;
+	}
+
+	return irq;
+}
+
+/* This routine will fix some missing interrupt values in the device tree
+ * on the gatwick mac-io controller used by some PowerBooks
+ */
+static void __init
+pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+{
+	struct device_node *node;
+	int count;
+	
+	memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
+	node = gw->child;
+	count = 0;
+	while(node)
+	{
+		/* Fix SCC */
+		if (strcasecmp(node->name, "escc") == 0)
+			if (node->child) {
+				if (node->child->n_intrs < 3) {
+					node->child->intrs = &gatwick_int_pool[count];
+					count += 3;
+				}
+				node->child->n_intrs = 3;				
+				node->child->intrs[0].line = 15+irq_base;
+				node->child->intrs[1].line =  4+irq_base;
+				node->child->intrs[2].line =  5+irq_base;
+				printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
+					node->child->intrs[0].line,
+					node->child->intrs[1].line,
+					node->child->intrs[2].line);
+			}
+		/* Fix media-bay & left SWIM */
+		if (strcasecmp(node->name, "media-bay") == 0) {
+			struct device_node* ya_node;
+
+			if (node->n_intrs == 0)
+				node->intrs = &gatwick_int_pool[count++];
+			node->n_intrs = 1;
+			node->intrs[0].line = 29+irq_base;
+			printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
+					node->intrs[0].line);
+			
+			ya_node = node->child;
+			while(ya_node)
+			{
+				if (strcasecmp(ya_node->name, "floppy") == 0) {
+					if (ya_node->n_intrs < 2) {
+						ya_node->intrs = &gatwick_int_pool[count];
+						count += 2;
+					}
+					ya_node->n_intrs = 2;
+					ya_node->intrs[0].line = 19+irq_base;
+					ya_node->intrs[1].line =  1+irq_base;
+					printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
+						ya_node->intrs[0].line, ya_node->intrs[1].line);
+				} 
+				if (strcasecmp(ya_node->name, "ata4") == 0) {
+					if (ya_node->n_intrs < 2) {
+						ya_node->intrs = &gatwick_int_pool[count];
+						count += 2;
+					}
+					ya_node->n_intrs = 2;
+					ya_node->intrs[0].line = 14+irq_base;
+					ya_node->intrs[1].line =  3+irq_base;
+					printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
+						ya_node->intrs[0].line, ya_node->intrs[1].line);
+				} 
+				ya_node = ya_node->sibling;
+			}
+		}
+		node = node->sibling;
+	}
+	if (count > 10) {
+		printk("WARNING !! Gatwick interrupt pool overflow\n");
+		printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
+		printk("              requested = %d\n", count);
+	}
+}
+
+/*
+ * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
+ * card which includes an ohare chip that acts as a second interrupt
+ * controller.  If we find this second ohare, set it up and fix the
+ * interrupt value in the device tree for the ethernet chip.
+ */
+static int __init enable_second_ohare(void)
+{
+	unsigned char bus, devfn;
+	unsigned short cmd;
+        unsigned long addr;
+	struct device_node *irqctrler = find_devices("pci106b,7");
+	struct device_node *ether;
+
+	if (irqctrler == NULL || irqctrler->n_addrs <= 0)
+		return -1;
+	addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
+	pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
+	max_irqs = 64;
+	if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
+		struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
+		if (!hose)
+		    printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+		else {
+		    early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
+		    cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+	  	    cmd &= ~PCI_COMMAND_IO;
+		    early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
+		}
+	}
+
+	/* Fix interrupt for the modem/ethernet combo controller. The number
+	   in the device tree (27) is bogus (correct for the ethernet-only
+	   board but not the combo ethernet/modem board).
+	   The real interrupt is 28 on the second controller -> 28+32 = 60.
+	*/
+	ether = find_devices("pci1011,14");
+	if (ether && ether->n_intrs > 0) {
+		ether->intrs[0].line = 60;
+		printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
+		       ether->intrs[0].line);
+	}
+
+	/* Return the interrupt number of the cascade */
+	return irqctrler->intrs[0].line;
+}
+
+void __init
+pmac_pic_init(void)
+{
+        int i;
+        struct device_node *irqctrler;
+        unsigned long addr;
+	int irq_cascade = -1;
+	
+	/* We first try to detect Apple's new Core99 chipset, since mac-io
+	 * is quite different on those machines and contains an IBM MPIC2.
+	 */
+	irqctrler = find_type_devices("open-pic");
+	if (irqctrler != NULL)
+	{
+		printk("PowerMac using OpenPIC irq controller\n");
+		if (irqctrler->n_addrs > 0)
+		{
+			int nmi_irq = -1;
+			unsigned char senses[NR_IRQS];
+#ifdef CONFIG_XMON
+			struct device_node* pswitch;
+
+			pswitch = find_devices("programmer-switch");
+			if (pswitch && pswitch->n_intrs)
+				nmi_irq = pswitch->intrs[0].line;
+#endif /* CONFIG_XMON */
+			prom_get_irq_senses(senses, 0, NR_IRQS);
+			OpenPIC_InitSenses = senses;
+			OpenPIC_NumInitSenses = NR_IRQS;
+			ppc_md.get_irq = openpic_get_irq;
+			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
+					       irqctrler->addrs[0].size);
+			openpic_init(1, 0, 0, nmi_irq);
+#ifdef CONFIG_XMON
+			if (nmi_irq >= 0)
+				request_irq(nmi_irq, xmon_irq, 0,
+					    "NMI - XMON", 0);
+#endif	/* CONFIG_XMON */
+			return;
+		}
+		irqctrler = NULL;
+	}
+
+	/* Get the level/edge settings, assume if it's not
+	 * a Grand Central nor an OHare, then it's an Heathrow
+	 * (or Paddington).
+	 */
+	if (find_devices("gc"))
+		level_mask[0] = GC_LEVEL_MASK;
+	else if (find_devices("ohare")) {
+		level_mask[0] = OHARE_LEVEL_MASK;
+		/* We might have a second cascaded ohare */
+		level_mask[1] = OHARE_LEVEL_MASK;
+	} else {
+		level_mask[0] = HEATHROW_LEVEL_MASK;
+		level_mask[1] = 0;
+		/* We might have a second cascaded heathrow */
+		level_mask[2] = HEATHROW_LEVEL_MASK;
+		level_mask[3] = 0;
+	}
+
+	/*
+	 * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
+	 * 1998 G3 Series PowerBooks have 128, 
+	 * other powermacs have 32.
+	 * The combo ethernet/modem card for the Powerstar powerbooks
+	 * (2400/3400/3500, ohare based) has a second ohare chip
+	 * effectively making a total of 64.
+	 */
+	max_irqs = max_real_irqs = 32;
+	irqctrler = find_devices("mac-io");
+	if (irqctrler)
+	{
+		max_real_irqs = 64;
+		if (irqctrler->next)
+			max_irqs = 128;
+		else
+			max_irqs = 64;
+	}
+	for ( i = 0; i < max_real_irqs ; i++ )
+		irq_desc[i].handler = &pmac_pic;
+
+	/* get addresses of first controller */
+	if (irqctrler) {
+		if  (irqctrler->n_addrs > 0) {
+			addr = (unsigned long) 
+				ioremap(irqctrler->addrs[0].address, 0x40);
+			for (i = 0; i < 2; ++i)
+				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+					(addr + (2 - i) * 0x10);
+		}
+		
+		/* get addresses of second controller */
+		irqctrler = irqctrler->next;
+		if (irqctrler && irqctrler->n_addrs > 0) {
+			addr = (unsigned long) 
+				ioremap(irqctrler->addrs[0].address, 0x40);
+			for (i = 2; i < 4; ++i)
+				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+					(addr + (4 - i) * 0x10);
+			irq_cascade = irqctrler->intrs[0].line;
+			if (device_is_compatible(irqctrler, "gatwick"))
+				pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+		}
+	} else {
+		/* older powermacs have a GC (grand central) or ohare at
+		   f3000000, with interrupt control registers at f3000020. */
+		addr = (unsigned long) ioremap(0xf3000000, 0x40);
+		pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
+	}
+
+	/* PowerBooks 3400 and 3500 can have a second controller in a second
+	   ohare chip, on the combo ethernet/modem card */
+	if (machine_is_compatible("AAPL,3400/2400")
+	     || machine_is_compatible("AAPL,3500"))
+		irq_cascade = enable_second_ohare();
+
+	/* disable all interrupts in all controllers */
+	for (i = 0; i * 32 < max_irqs; ++i)
+		out_le32(&pmac_irq_hw[i]->enable, 0);
+	/* mark level interrupts */
+	for (i = 0; i < max_irqs; i++)
+		if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
+			irq_desc[i].status = IRQ_LEVEL;
+	
+	/* get interrupt line of secondary interrupt controller */
+	if (irq_cascade >= 0) {
+		printk(KERN_INFO "irq: secondary controller on irq %d\n",
+			(int)irq_cascade);
+		for ( i = max_real_irqs ; i < max_irqs ; i++ )
+			irq_desc[i].handler = &gatwick_pic;
+		request_irq( irq_cascade, gatwick_action, SA_INTERRUPT,
+			     "cascade", 0 );
+	}
+	printk("System has %d possible interrupts\n", max_irqs);
+	if (max_irqs != max_real_irqs)
+		printk(KERN_DEBUG "%d interrupts on main controller\n",
+			max_real_irqs);
+
+#ifdef CONFIG_XMON
+	request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
+#endif	/* CONFIG_XMON */
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * These procedures are used in implementing sleep on the powerbooks.
+ * sleep_save_intrs() saves the states of all interrupt enables
+ * and disables all interrupts except for the nominated one.
+ * sleep_restore_intrs() restores the states of all interrupt enables.
+ */
+unsigned int sleep_save_mask[2];
+
+void __pmac
+pmac_sleep_save_intrs(int viaint)
+{
+	sleep_save_mask[0] = ppc_cached_irq_mask[0];
+	sleep_save_mask[1] = ppc_cached_irq_mask[1];
+	ppc_cached_irq_mask[0] = 0;
+	ppc_cached_irq_mask[1] = 0;
+	if (viaint > 0)
+		set_bit(viaint, ppc_cached_irq_mask);
+	out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
+	if (max_real_irqs > 32)
+		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
+	(void)in_le32(&pmac_irq_hw[0]->event);
+	/* make sure mask gets to controller before we return to caller */
+	mb();
+        (void)in_le32(&pmac_irq_hw[0]->enable);
+}
+
+void __pmac
+pmac_sleep_restore_intrs(void)
+{
+	int i;
+
+	out_le32(&pmac_irq_hw[0]->enable, 0);
+	if (max_real_irqs > 32)
+		out_le32(&pmac_irq_hw[1]->enable, 0);
+	mb();
+	for (i = 0; i < max_real_irqs; ++i)
+		if (test_bit(i, sleep_save_mask))
+			pmac_unmask_irq(i);
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/pmac_pic.h linux-2.4.20-pre2/arch/ppc/platforms/pmac_pic.h
--- linux-2.4.20-pre1/arch/ppc/platforms/pmac_pic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/pmac_pic.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,14 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+#ifndef __PPC_PLATFORMS_PMAC_PIC_H
+#define __PPC_PLATFORMS_PMAC_PIC_H
+
+#include <linux/irq.h>
+
+extern struct hw_interrupt_type pmac_pic;
+
+void pmac_pic_init(void);
+int pmac_get_irq(struct pt_regs *regs);
+
+#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/pmac_setup.c linux-2.4.20-pre2/arch/ppc/platforms/pmac_setup.c
--- linux-2.4.20-pre1/arch/ppc/platforms/pmac_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/pmac_setup.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,955 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/setup.c
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  Derived from "arch/alpha/kernel/setup.c"
+ *    Copyright (C) 1995 Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the 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/init.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/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/ohare.h>
+#include <asm/mediabay.h>
+#include <asm/machdep.h>
+#include <asm/keyboard.h>
+#include <asm/dma.h>
+#include <asm/bootx.h>
+#include <asm/cputable.h>
+#include <asm/btext.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+
+#include "pmac_pic.h"
+#include "mem_pieces.h"
+#include "scsi.h" /* sd_find_target */
+#include "sd.h"
+#include "mac.h"
+
+extern long pmac_time_init(void);
+extern unsigned long pmac_get_rtc_time(void);
+extern int pmac_set_rtc_time(unsigned long nowtime);
+extern void pmac_read_rtc_time(void);
+extern void pmac_calibrate_decr(void);
+extern void pmac_pcibios_fixup(void);
+extern void pmac_find_bridges(void);
+extern int pmac_ide_check_base(ide_ioreg_t base);
+extern ide_ioreg_t pmac_ide_get_base(int index);
+extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
+	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
+		     char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void __init mackbd_init_hw(void);
+extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
+				 char raw_mode);
+extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
+extern void mac_hid_init_hw(void);
+extern unsigned char mac_hid_kbd_sysrq_xlate[];
+extern unsigned char pckbd_sysrq_xlate[];
+extern unsigned char mackbd_sysrq_xlate[];
+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 int keyboard_sends_linux_keycodes;
+extern void pmac_nvram_update(void);
+
+extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial);
+extern void pmac_pcibios_after_init(void);
+
+struct device_node *memory_node;
+
+unsigned char drive_info;
+
+int ppc_override_l2cr = 0;
+int ppc_override_l2cr_value;
+int has_l2cache = 0;
+
+static int current_root_goodness = -1;
+
+extern char saved_command_line[];
+
+extern int pmac_newworld;
+
+#define DEFAULT_ROOT_DEVICE 0x0801	/* sda1 - slightly silly choice */
+
+extern void zs_kgdb_hook(int tty_num);
+static void ohare_init(void);
+#ifdef CONFIG_BOOTX_TEXT
+void pmac_progress(char *s, unsigned short hex);
+#endif
+
+sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
+
+#ifdef CONFIG_SMP
+extern struct smp_ops_t psurge_smp_ops;
+extern struct smp_ops_t core99_smp_ops;
+#endif /* CONFIG_SMP */
+
+/*
+ * Assume here that all clock rates are the same in a
+ * smp system.  -- Cort
+ */
+int __openfirmware
+of_show_percpuinfo(struct seq_file *m, int i)
+{
+	struct device_node *cpu_node;
+	int *fp, s;
+			
+	cpu_node = find_type_devices("cpu");
+	if (!cpu_node)
+		return 0;
+	for (s = 0; s < i && cpu_node->next; s++)
+		cpu_node = cpu_node->next;
+	fp = (int *) get_property(cpu_node, "clock-frequency", NULL);
+	if (fp)
+		seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
+	return 0;
+}
+
+int __pmac
+pmac_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *np;
+	char *pp;
+	int plen;
+	int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+		NULL, PMAC_MB_INFO_MODEL, 0);
+	unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+		NULL, PMAC_MB_INFO_FLAGS, 0);
+	char* mbname;
+
+	if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
+		mbname = "Unknown";
+		
+	/* find motherboard type */
+	seq_printf(m, "machine\t\t: ");
+	np = find_devices("device-tree");
+	if (np != NULL) {
+		pp = (char *) get_property(np, "model", NULL);
+		if (pp != NULL)
+			seq_printf(m, "%s\n", pp);
+		else
+			seq_printf(m, "PowerMac\n");
+		pp = (char *) get_property(np, "compatible", &plen);
+		if (pp != NULL) {
+			seq_printf(m, "motherboard\t:");
+			while (plen > 0) {
+				int l = strlen(pp) + 1;
+				seq_printf(m, " %s", pp);
+				plen -= l;
+				pp += l;
+			}
+			seq_printf(m, "\n");
+		}
+	} else
+		seq_printf(m, "PowerMac\n");
+
+	/* print parsed model */
+	seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
+	seq_printf(m, "pmac flags\t: %08x\n", mbflags);
+	
+	/* find l2 cache info */
+	np = find_devices("l2-cache");
+	if (np == 0)
+		np = find_type_devices("cache");
+	if (np != 0) {
+		unsigned int *ic = (unsigned int *)
+			get_property(np, "i-cache-size", NULL);
+		unsigned int *dc = (unsigned int *)
+			get_property(np, "d-cache-size", NULL);
+		seq_printf(m, "L2 cache\t:");
+		has_l2cache = 1;
+		if (get_property(np, "cache-unified", NULL) != 0 && dc) {
+			seq_printf(m, " %dK unified", *dc / 1024);
+		} else {
+			if (ic)
+				seq_printf(m, " %dK instruction", *ic / 1024);
+			if (dc)
+				seq_printf(m, "%s %dK data",
+					   (ic? " +": ""), *dc / 1024);
+		}
+		pp = get_property(np, "ram-type", NULL);
+		if (pp)
+			seq_printf(m, " %s", pp);
+		seq_printf(m, "\n");
+	}
+
+	/* find ram info */
+	np = find_devices("memory");
+	if (np != 0) {
+		int n;
+		struct reg_property *reg = (struct reg_property *)
+			get_property(np, "reg", &n);
+		
+		if (reg != 0) {
+			unsigned long total = 0;
+
+			for (n /= sizeof(struct reg_property); n > 0; --n)
+				total += (reg++)->size;
+			seq_printf(m, "memory\t\t: %luMB\n", total >> 20);
+		}
+	}
+
+	/* Checks "l2cr-value" property in the registry */
+	np = find_devices("cpus");		
+	if (np == 0)
+		np = find_type_devices("cpu");		
+	if (np != 0) {
+		unsigned int *l2cr = (unsigned int *)
+			get_property(np, "l2cr-value", NULL);
+		if (l2cr != 0) {
+			seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr);
+		}
+	}
+	
+	/* Indicate newworld/oldworld */
+	seq_printf(m, "pmac-generation\t: %s\n",
+		   pmac_newworld ? "NewWorld" : "OldWorld");
+	
+
+	return 0;
+}
+
+#ifdef CONFIG_VT
+/*
+ * Dummy mksound function that does nothing.
+ * The real one is in the dmasound driver.
+ */
+static void __pmac
+pmac_mksound(unsigned int hz, unsigned int ticks)
+{
+}
+#endif /* CONFIG_VT */
+
+static volatile u32 *sysctrl_regs;
+
+void __init
+pmac_setup_arch(void)
+{
+	struct device_node *cpu;
+	int *fp;
+	unsigned long pvr;
+	
+	pvr = PVR_VER(mfspr(PVR));
+
+	/* Set loops_per_jiffy to a half-way reasonable value,
+	   for use until calibrate_delay gets called. */
+	cpu = find_type_devices("cpu");
+	if (cpu != 0) {
+		fp = (int *) get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0) {
+			if (pvr == 4 || pvr >= 8)
+				/* 604, G3, G4 etc. */
+				loops_per_jiffy = *fp / HZ;
+			else
+				/* 601, 603, etc. */
+				loops_per_jiffy = *fp / (2*HZ);
+		} else
+			loops_per_jiffy = 50000000 / HZ;
+	}
+
+	/* this area has the CPU identification register
+	   and some registers used by smp boards */
+	sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
+	ohare_init();
+
+	/* Lookup PCI hosts */
+	pmac_find_bridges();
+	
+	/* Checks "l2cr-value" property in the registry */
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) {
+		struct device_node *np = find_devices("cpus");		
+		if (np == 0)
+			np = find_type_devices("cpu");		
+		if (np != 0) {
+			unsigned int *l2cr = (unsigned int *)
+				get_property(np, "l2cr-value", NULL);
+			if (l2cr != 0) {
+				ppc_override_l2cr = 1;
+				ppc_override_l2cr_value = *l2cr;
+				_set_L2CR(0);
+				_set_L2CR(ppc_override_l2cr_value);
+			}
+		}
+	}
+
+	if (ppc_override_l2cr)
+		printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
+			ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
+				? "enabled" : "disabled");
+	
+#ifdef CONFIG_KGDB
+	zs_kgdb_hook(0);
+#endif
+
+#ifdef CONFIG_ADB_CUDA
+	find_via_cuda();
+#else
+	if (find_devices("via-cuda")) {
+		printk("WARNING ! Your machine is Cuda based but your kernel\n");
+		printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
+	}
+#endif	
+#ifdef CONFIG_ADB_PMU
+	find_via_pmu();
+#else
+	if (find_devices("via-pmu")) {
+		printk("WARNING ! Your machine is PMU based but your kernel\n");
+		printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
+	}
+#endif	
+#ifdef CONFIG_NVRAM
+	pmac_nvram_init();
+#endif
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+#ifdef CONFIG_VT
+	kd_mksound = pmac_mksound;
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	else
+#endif
+		ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+
+#ifdef CONFIG_SMP
+	/* Check for Core99 */
+	if (find_devices("uni-n"))
+		ppc_md.smp_ops = &core99_smp_ops;
+	else
+		ppc_md.smp_ops = &psurge_smp_ops;
+#endif /* CONFIG_SMP */
+}
+
+static void __init ohare_init(void)
+{
+	/*
+	 * Turn on the L2 cache.
+	 * We assume that we have a PSX memory controller iff
+	 * we have an ohare I/O controller.
+	 */
+	if (find_devices("ohare") != NULL) {
+		if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
+			if (sysctrl_regs[4] & 0x10)
+				sysctrl_regs[4] |= 0x04000020;
+			else
+				sysctrl_regs[4] |= 0x04000000;
+			if(has_l2cache)
+				printk(KERN_INFO "Level 2 cache enabled\n");
+		}
+	}
+}
+
+extern char *bootpath;
+extern char *bootdevice;
+void *boot_host;
+int boot_target;
+int boot_part;
+extern kdev_t boot_dev;
+
+void __init
+pmac_init2(void)
+{
+#ifdef CONFIG_ADB_PMU
+	via_pmu_start();
+#endif
+#ifdef CONFIG_ADB_CUDA
+	via_cuda_start();
+#endif
+#ifdef CONFIG_PMAC_PBOOK
+	media_bay_init();
+#endif
+	pmac_feature_late_init();
+}
+
+/* Borrowed from fs/partition/check.c */
+static unsigned char* __init
+read_one_block(struct block_device *bdev, unsigned long n, struct page **v)
+{
+	struct address_space *mapping = bdev->bd_inode->i_mapping;
+	int sect = PAGE_CACHE_SIZE / 512;
+	struct page *page;
+
+	page = read_cache_page(mapping, n/sect,
+			(filler_t *)mapping->a_ops->readpage, NULL);
+	if (!IS_ERR(page)) {
+		wait_on_page(page);
+		if (!Page_Uptodate(page))
+			goto fail;
+		if (PageError(page))
+			goto fail;
+		*v = page;
+		return (unsigned char *)page_address(page) + 512 * (n % sect);
+fail:
+		page_cache_release(page);
+	}
+	*v = NULL;
+	return NULL;
+}
+
+#ifdef CONFIG_SCSI
+void __init
+note_scsi_host(struct device_node *node, void *host)
+{
+	int l;
+	char *p;
+
+	l = strlen(node->full_name);
+	if (bootpath != NULL && bootdevice != NULL
+	    && strncmp(node->full_name, bootdevice, l) == 0
+	    && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+		boot_host = host;
+		/*
+		 * There's a bug in OF 1.0.5.  (Why am I not surprised.)
+		 * If you pass a path like scsi/sd@1:0 to canon, it returns
+		 * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+		 * That is, the scsi target number doesn't get preserved.
+		 * So we pick the target number out of bootpath and use that.
+		 */
+		p = strstr(bootpath, "/sd@");
+		if (p != NULL) {
+			p += 4;
+			boot_target = simple_strtoul(p, NULL, 10);
+			p = strchr(p, ':');
+			if (p != NULL)
+				boot_part = simple_strtoul(p + 1, NULL, 10);
+		}
+	}
+}
+#endif /* CONFIG_SCSI */
+
+#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
+kdev_t __init
+find_ide_boot(void)
+{
+	char *p;
+	int n;
+	kdev_t __init pmac_find_ide_boot(char *bootdevice, int n);
+
+	if (bootdevice == NULL)
+		return 0;
+	p = strrchr(bootdevice, '/');
+	if (p == NULL)
+		return 0;
+	n = p - bootdevice;
+
+	return pmac_find_ide_boot(bootdevice, n);
+}
+#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
+
+void __init
+find_boot_device(void)
+{
+#if defined(CONFIG_SCSI) && defined(CONFIG_BLK_DEV_SD)
+	if (boot_host != NULL) {
+		boot_dev = sd_find_target(boot_host, boot_target);
+		if (boot_dev != 0)
+			return;
+	}
+#endif
+#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
+	boot_dev = find_ide_boot();
+#endif
+}
+
+static void __init
+check_bootable_part(kdev_t dev, int blk, struct mac_partition *part)
+{
+	int goodness = 0;
+
+	macpart_fix_string(part->processor, 16);
+	macpart_fix_string(part->name, 32);
+	macpart_fix_string(part->type, 32);					
+    
+	if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
+	    && strcasecmp(part->processor, "powerpc") == 0)
+		goodness++;
+
+	if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
+	    || (strnicmp(part->type, "Linux", 5) == 0
+	    && strcasecmp(part->type, "Linux_swap") != 0)) {
+		int i, l;
+
+		goodness++;
+		l = strlen(part->name);
+		if (strcmp(part->name, "/") == 0)
+			goodness++;
+		for (i = 0; i <= l - 4; ++i) {
+			if (strnicmp(part->name + i, "root",
+				     4) == 0) {
+				goodness += 2;
+				break;
+			}
+		}
+		if (strnicmp(part->name, "swap", 4) == 0)
+			goodness--;
+	}
+
+	if (goodness > current_root_goodness) {
+		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + blk);
+		current_root_goodness = goodness;
+	}
+}
+
+static void __init
+check_bootable_disk(kdev_t dev, struct block_device *bdev)
+{
+	struct mac_partition *part;
+	struct mac_driver_desc *md;
+	struct page* pg;
+	unsigned secsize, blocks_in_map, blk;
+	unsigned char* data;
+	
+	/* Check driver descriptor */
+	md = (struct mac_driver_desc *) read_one_block(bdev, 0, &pg);
+	if (!md)
+		return;
+	if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
+		goto fail;
+	secsize = be16_to_cpu(md->block_size);
+	page_cache_release(pg);
+	
+	/* Check if it looks like a mac partition map */
+	data = read_one_block(bdev, secsize/512, &pg);
+	if (!data)
+		goto fail;
+	part = (struct mac_partition *) (data + secsize%512);
+	if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+		goto fail;
+
+	/* Iterate the partition map */
+	blocks_in_map = be32_to_cpu(part->map_count);
+	for (blk = 1; blk <= blocks_in_map; ++blk) {
+		int pos = blk * secsize;
+		page_cache_release(pg);
+		data = read_one_block(bdev, pos/512, &pg);
+		if (!data)
+			break;
+		part = (struct mac_partition *) (data + pos%512);
+		if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+			break;
+		check_bootable_part(dev, blk, part);
+	}
+fail:
+	if (pg)	
+		page_cache_release(pg);
+}
+
+static int __init
+walk_bootable(struct gendisk *hd, void *data)
+{
+	int drive;
+	
+	for (drive=0; drive<hd->nr_real; drive++) {
+		kdev_t dev;
+		struct block_device *bdev;
+		int rc;
+
+		dev = MKDEV(hd->major, drive << hd->minor_shift);
+		if (boot_dev && boot_dev != dev)
+			continue;
+		bdev = bdget(kdev_t_to_nr(dev));
+		if (bdev == NULL)
+			continue;
+		rc = blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW);
+		if (rc == 0) {
+			check_bootable_disk(dev, bdev);
+			blkdev_put(bdev, BDEV_RAW);
+		}
+	}
+
+	return 0;
+}
+
+void __init
+pmac_discover_root(void)
+{
+	char* p;
+
+	/* Check if root devices already got selected by other ways */
+	if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))
+		return;
+	p = strstr(saved_command_line, "root=");
+	if (p != NULL && (p == saved_command_line || p[-1] == ' '))
+		return;
+
+	/* Find the device used for booting if we can */
+	find_boot_device();
+
+	/* Try to locate a partition */
+	walk_gendisk(walk_bootable, NULL);
+}
+
+void __pmac
+pmac_restart(char *cmd)
+{
+#ifdef CONFIG_ADB_CUDA
+	struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
+
+#ifdef CONFIG_NVRAM
+	pmac_nvram_update();
+#endif
+	
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
+		cuda_request(&req, NULL, 2, CUDA_PACKET,
+			     CUDA_RESET_SYSTEM);
+		for (;;)
+			cuda_poll();
+		break;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU		
+	case SYS_CTRLER_PMU:
+		pmu_restart();
+		break;
+#endif /* CONFIG_ADB_PMU */		
+	default: ;
+	}
+}
+
+void __pmac
+pmac_power_off(void)
+{
+#ifdef CONFIG_ADB_CUDA
+	struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
+
+#ifdef CONFIG_NVRAM
+	pmac_nvram_update();
+#endif
+	
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
+		cuda_request(&req, NULL, 2, CUDA_PACKET,
+			     CUDA_POWERDOWN);
+		for (;;)
+			cuda_poll();
+		break;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
+		pmu_shutdown();
+		break;
+#endif /* CONFIG_ADB_PMU */
+	default: ;
+	}
+}
+
+void __pmac
+pmac_halt(void)
+{
+   pmac_power_off();
+}
+
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+static int __pmac
+pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	if (pmac_ide_check_base(from) >= 0)
+		return 0;
+#endif
+	return check_region(from, extent);
+}
+
+static void __pmac
+pmac_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	if (pmac_ide_check_base(from) >= 0)
+		return;
+#endif
+	request_region(from, extent, name);
+}
+
+static void __pmac
+pmac_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	if (pmac_ide_check_base(from) >= 0)
+		return;
+#endif
+	release_region(from, extent);
+}
+
+#ifndef CONFIG_BLK_DEV_IDE_PMAC
+/*
+ * This is only used if we have a PCI IDE controller, not
+ * for the IDE controller in the ohare/paddington/heathrow/keylargo.
+ */
+static void __pmac
+pmac_ide_pci_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;
+	}
+	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+}
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
+
+/*
+ * Read in a property describing some pieces of memory.
+ */
+
+static int __init
+get_mem_prop(char *name, struct mem_pieces *mp)
+{
+	struct reg_property *rp;
+	int i, s;
+	unsigned int *ip;
+	int nac = prom_n_addr_cells(memory_node);
+	int nsc = prom_n_size_cells(memory_node);
+
+	ip = (unsigned int *) get_property(memory_node, name, &s);
+	if (ip == NULL) {
+		printk(KERN_ERR "error: couldn't get %s property on /memory\n",
+		       name);
+		return 0;
+	}
+	s /= (nsc + nac) * 4;
+	rp = mp->regions;
+	for (i = 0; i < s; ++i, ip += nac+nsc) {
+		if (nac >= 2 && ip[nac-2] != 0)
+			continue;
+		rp->address = ip[nac-1];
+		if (nsc >= 2 && ip[nac+nsc-2] != 0)
+			rp->size = ~0U;
+		else
+			rp->size = ip[nac+nsc-1];
+		++rp;
+	}
+	mp->n_regions = rp - mp->regions;
+
+	/* Make sure the pieces are sorted. */
+	mem_pieces_sort(mp);
+	mem_pieces_coalesce(mp);
+	return 1;
+}
+
+/*
+ * On systems with Open Firmware, collect information about
+ * physical RAM and which pieces are already in use.
+ * At this point, we have (at least) the first 8MB mapped with a BAT.
+ * Our text, data, bss use something over 1MB, starting at 0.
+ * Open Firmware may be using 1MB at the 4MB point.
+ */
+unsigned long __init
+pmac_find_end_of_memory(void)
+{
+	unsigned long a, total;
+	struct mem_pieces phys_mem;
+
+	/*
+	 * Find out where physical memory is, and check that it
+	 * starts at 0 and is contiguous.  It seems that RAM is
+	 * always physically contiguous on Power Macintoshes.
+	 *
+	 * Supporting discontiguous physical memory isn't hard,
+	 * it just makes the virtual <-> physical mapping functions
+	 * more complicated (or else you end up wasting space
+	 * in mem_map).
+	 */
+	memory_node = find_devices("memory");
+	if (memory_node == NULL || !get_mem_prop("reg", &phys_mem)
+	    || phys_mem.n_regions == 0)
+		panic("No RAM??");
+	a = phys_mem.regions[0].address;
+	if (a != 0)
+		panic("RAM doesn't start at physical address 0");
+	total = phys_mem.regions[0].size;
+
+	if (phys_mem.n_regions > 1) {
+		printk("RAM starting at 0x%x is not contiguous\n",
+		       phys_mem.regions[1].address);
+		printk("Using RAM from 0 to 0x%lx\n", total-1);
+	}
+
+	return total;
+}
+
+void __init
+select_adb_keyboard(void)
+{
+#ifdef CONFIG_VT
+#ifdef CONFIG_INPUT
+	ppc_md.kbd_init_hw       = mac_hid_init_hw;
+	ppc_md.kbd_translate     = mac_hid_kbd_translate;
+	ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
+	ppc_md.kbd_setkeycode    = 0;
+	ppc_md.kbd_getkeycode    = 0;
+	ppc_md.kbd_leds		 = 0;
+#ifdef CONFIG_MAGIC_SYSRQ
+#ifdef CONFIG_MAC_ADBKEYCODES
+	if (!keyboard_sends_linux_keycodes) {
+		ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
+		SYSRQ_KEY = 0x69;
+	} else
+#endif /* CONFIG_MAC_ADBKEYCODES */
+	{
+		ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+		SYSRQ_KEY = 0x54;
+	}
+#endif /* CONFIG_MAGIC_SYSRQ */
+#elif defined(CONFIG_ADB_KEYBOARD)
+	ppc_md.kbd_setkeycode       = mackbd_setkeycode;
+	ppc_md.kbd_getkeycode       = mackbd_getkeycode;
+	ppc_md.kbd_translate        = mackbd_translate;
+	ppc_md.kbd_unexpected_up    = mackbd_unexpected_up;
+	ppc_md.kbd_leds             = mackbd_leds;
+	ppc_md.kbd_init_hw          = mackbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.ppc_kbd_sysrq_xlate  = mackbd_sysrq_xlate;
+	SYSRQ_KEY = 0x69;
+#endif /* CONFIG_MAGIC_SYSRQ */
+#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */
+#endif /* CONFIG_VT */
+}
+
+void __init
+pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7)
+{
+	/* isa_io_base gets set in pmac_find_bridges */
+	isa_mem_base = PMAC_ISA_MEM_BASE;
+	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 1;
+	DMA_MODE_WRITE = 2;
+
+	ppc_md.setup_arch     = pmac_setup_arch;
+	ppc_md.show_cpuinfo   = pmac_show_cpuinfo;
+	ppc_md.show_percpuinfo = of_show_percpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = pmac_pic_init;
+	ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
+	ppc_md.init           = pmac_init2;
+	
+	ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
+	ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
+	ppc_md.pcibios_after_init = pmac_pcibios_after_init;
+
+	ppc_md.discover_root  = pmac_discover_root;
+
+	ppc_md.restart        = pmac_restart;
+	ppc_md.power_off      = pmac_power_off;
+	ppc_md.halt           = pmac_halt;
+
+	ppc_md.time_init      = pmac_time_init;
+	ppc_md.set_rtc_time   = pmac_set_rtc_time;
+	ppc_md.get_rtc_time   = pmac_get_rtc_time;
+	ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
+
+	ppc_md.feature_call   = pmac_do_feature_call;
+
+	select_adb_keyboard();
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.ide_check_region	= pmac_ide_check_region;
+        ppc_ide_md.ide_request_region	= pmac_ide_request_region;
+        ppc_ide_md.ide_release_region	= pmac_ide_release_region;
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+        ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
+        ppc_ide_md.default_io_base	= pmac_ide_get_base;
+#else /* CONFIG_BLK_DEV_IDE_PMAC */
+        ppc_ide_md.ide_init_hwif	= pmac_ide_pci_init_hwif_ports;
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
+
+#ifdef CONFIG_BOOTX_TEXT
+	ppc_md.progress = pmac_progress;
+#endif /* CONFIG_BOOTX_TEXT */
+
+	if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
+	
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+void __init
+pmac_progress(char *s, unsigned short hex)
+{
+	if (boot_text_mapped) {
+		btext_drawstring(s);
+		btext_drawchar('\n');
+	}
+}
+#endif /* CONFIG_BOOTX_TEXT */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/pmac_smp.c linux-2.4.20-pre2/arch/ppc/platforms/pmac_smp.c
--- linux-2.4.20-pre1/arch/ppc/platforms/pmac_smp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/pmac_smp.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,623 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * SMP support for power macintosh.
+ *
+ * We support both the old "powersurge" SMP architecture
+ * and the current Core99 (G4 PowerMac) machines.
+ *
+ * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
+ * and Ben Herrenschmidt <benh@kernel.crashing.org>.
+ *
+ * Support for DayStar quad CPU cards
+ * Copyright (C) XLR8, Inc. 1994-2000
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the 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/spinlock.h>
+#include <linux/stringify.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/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/residual.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+#include <asm/processor.h>
+
+/*
+ * Powersurge (old powermac SMP) support.
+ */
+
+extern void __secondary_start_psurge(void);
+extern void __secondary_start_psurge2(void);	/* Temporary horrible hack */
+extern void __secondary_start_psurge3(void);	/* Temporary horrible hack */
+
+/* Addresses for powersurge registers */
+#define HAMMERHEAD_BASE		0xf8000000
+#define HHEAD_CONFIG		0x90
+#define HHEAD_SEC_INTR		0xc0
+
+/* register for interrupting the primary processor on the powersurge */
+/* N.B. this is actually the ethernet ROM! */
+#define PSURGE_PRI_INTR		0xf3019000
+
+/* register for storing the start address for the secondary processor */
+/* N.B. this is the PCI config space address register for the 1st bridge */
+#define PSURGE_START		0xf2800000
+
+/* Daystar/XLR8 4-CPU card */
+#define PSURGE_QUAD_REG_ADDR	0xf8800000
+
+#define PSURGE_QUAD_IRQ_SET	0
+#define PSURGE_QUAD_IRQ_CLR	1
+#define PSURGE_QUAD_IRQ_PRIMARY	2
+#define PSURGE_QUAD_CKSTOP_CTL	3
+#define PSURGE_QUAD_PRIMARY_ARB	4
+#define PSURGE_QUAD_BOARD_ID	6
+#define PSURGE_QUAD_WHICH_CPU	7
+#define PSURGE_QUAD_CKSTOP_RDBK	8
+#define PSURGE_QUAD_RESET_CTL	11
+
+#define PSURGE_QUAD_OUT(r, v)	(out_8(quad_base + ((r) << 4) + 4, (v)))
+#define PSURGE_QUAD_IN(r)	(in_8(quad_base + ((r) << 4) + 4) & 0x0f)
+#define PSURGE_QUAD_BIS(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
+#define PSURGE_QUAD_BIC(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
+
+/* virtual addresses for the above */
+static volatile u8 *hhead_base;
+static volatile u8 *quad_base;
+static volatile u32 *psurge_pri_intr;
+static volatile u8 *psurge_sec_intr;
+static volatile u32 *psurge_start;
+
+/* what sort of powersurge board we have */
+static int psurge_type;
+
+/* values for psurge_type */
+#define PSURGE_DUAL		0
+#define PSURGE_QUAD_OKEE	1
+#define PSURGE_QUAD_COTTON	2
+#define PSURGE_QUAD_ICEGRASS	3
+
+volatile static long int core99_l2_cache;
+volatile static long int core99_l3_cache;
+
+static void __init
+core99_init_caches(void)
+{
+	int cpu = smp_processor_id();
+
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
+		return;
+
+	if (cpu == 0){
+		core99_l2_cache = _get_L2CR();
+		printk("CPU0: L2CR is %lx\n", core99_l2_cache);
+	} else {
+		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
+		_set_L2CR(0);
+		_set_L2CR(core99_l2_cache);
+		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
+	}
+
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
+		return;
+
+	if (cpu == 0){
+		core99_l3_cache = _get_L3CR();
+		printk("CPU0: L3CR is %lx\n", core99_l3_cache);
+	} else {
+		printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
+		_set_L3CR(0);
+		_set_L3CR(core99_l3_cache);
+		printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
+	}
+}
+
+/* Some CPU registers have to be saved from the first CPU and
+ * applied to others. Note that we override what is setup by
+ * the cputable intentionally.
+ */
+
+#define	reg_hid0	0
+#define	reg_hid1	1
+#define	reg_msscr0	2
+#define	reg_msssr0	3
+#define	reg_ictrl	4
+#define	reg_ldstcr	5
+#define	reg_ldstdb	6
+#define	reg_count	7
+
+#define stringify __stringify
+
+static unsigned long cpu_regs[reg_count];
+
+static void __pmac
+cpu_setup_grab(void)
+{
+	unsigned int pvers = mfspr(SPRN_PVR)>>16;
+
+	/* Read cache setting of CPU 0 */
+	core99_init_caches();
+
+	/* 7400/7410/7450 */
+	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
+		cpu_regs[reg_hid0] = mfspr(SPRN_HID0);
+		cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0);
+		cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0);
+	}
+	/* 7450 only */
+	if (pvers == 0x8000) {
+		cpu_regs[reg_hid1] = mfspr(SPRN_HID1);
+		cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL);
+		cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR);
+		cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB);
+	}
+	flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]);
+}
+
+static void __pmac
+cpu_setup_apply(int cpu_nr)
+{
+	unsigned int pvers = mfspr(SPRN_PVR)>>16;
+
+	/* Apply cache setting from CPU 0 */
+	core99_init_caches();
+
+	/* 7400/7410/7450 */
+	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"lwz	%0,4*"stringify(reg_hid0)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_HID0)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_msscr0)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_MSSCR0)", %0\n"
+			"isync;sync\n"
+//			"lwz	%0, "stringify(reg_msssr0)"(%1)\n"
+//			"sync\n"
+//			"mtspr	"stringify(SPRN_MSSSR0)", %0\n"
+//			"isync;sync\n"
+		: "=&r" (tmp) : "r" (cpu_regs));			
+	}
+	/* 7410 only */
+	if (pvers == 0x800c) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"li	%0, 0\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_L2CR2)", %0\n"
+			"isync;sync\n"
+		: "=&r" (tmp));		
+	}
+	/* 7450 only */
+	if (pvers == 0x8000) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"lwz	%0, 4*"stringify(reg_hid1)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_HID1)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ictrl)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_ICTRL)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ldstcr)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_LDSTCR)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ldstdb)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_LDSTDB)", %0\n"
+			"isync;sync\n"
+		: "=&r" (tmp) : "r" (cpu_regs));		
+	}
+}
+
+/*
+ * Set and clear IPIs for powersurge.
+ */
+static inline void psurge_set_ipi(int cpu)
+{
+	if (cpu == 0)
+		in_be32(psurge_pri_intr);
+	else if (psurge_type == PSURGE_DUAL)
+		out_8(psurge_sec_intr, 0);
+	else
+		PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
+}
+
+static inline void psurge_clr_ipi(int cpu)
+{
+	if (cpu > 0) {
+		if (psurge_type == PSURGE_DUAL)
+			out_8(psurge_sec_intr, ~0);
+		else
+			PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
+	}
+}
+
+/*
+ * On powersurge (old SMP powermac architecture) we don't have
+ * separate IPIs for separate messages like openpic does.  Instead
+ * we have a bitmap for each processor, where a 1 bit means that
+ * the corresponding message is pending for that processor.
+ * Ideally each cpu's entry would be in a different cache line.
+ *  -- paulus.
+ */
+static unsigned long psurge_smp_message[NR_CPUS];
+
+void __pmac
+psurge_smp_message_recv(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	int msg;
+
+	/* clear interrupt */
+	psurge_clr_ipi(cpu);
+
+	if (smp_num_cpus < 2)
+		return;
+
+	/* make sure there is a message there */
+	for (msg = 0; msg < 4; msg++)
+		if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
+			smp_message_recv(msg, regs);
+}
+
+void __pmac
+psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
+{
+	psurge_smp_message_recv(regs);
+}
+
+static void __pmac
+smp_psurge_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	int i;
+
+	if (smp_num_cpus < 2)
+		return;
+
+	for (i = 0; i < smp_num_cpus; i++) {
+		if (target == MSG_ALL
+		    || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
+		    || target == i) {
+			set_bit(msg, &psurge_smp_message[i]);
+			psurge_set_ipi(i);
+		}
+	}
+}
+
+/*
+ * Determine a quad card presence. We read the board ID register, we
+ * force the data bus to change to something else, and we read it again.
+ * It it's stable, then the register probably exist (ugh !)
+ */
+static int __init psurge_quad_probe(void)
+{
+	int type;
+	unsigned int i;
+
+	type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
+	if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
+	    || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+		return PSURGE_DUAL;
+
+	/* looks OK, try a slightly more rigorous test */
+	/* bogus is not necessarily cacheline-aligned,
+	   though I don't suppose that really matters.  -- paulus */
+	for (i = 0; i < 100; i++) {
+		volatile u32 bogus[8];
+		bogus[(0+i)%8] = 0x00000000;
+		bogus[(1+i)%8] = 0x55555555;
+		bogus[(2+i)%8] = 0xFFFFFFFF;
+		bogus[(3+i)%8] = 0xAAAAAAAA;
+		bogus[(4+i)%8] = 0x33333333;
+		bogus[(5+i)%8] = 0xCCCCCCCC;
+		bogus[(6+i)%8] = 0xCCCCCCCC;
+		bogus[(7+i)%8] = 0x33333333;
+		wmb();
+		asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
+		mb();
+		if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+			return PSURGE_DUAL;
+	}
+	return type;
+}
+
+static void __init psurge_quad_init(void)
+{
+	int procbits;
+
+	if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
+	procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
+	if (psurge_type == PSURGE_QUAD_ICEGRASS)
+		PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+	else
+		PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
+	mdelay(33);
+	out_8(psurge_sec_intr, ~0);
+	PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
+	PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+	if (psurge_type != PSURGE_QUAD_ICEGRASS)
+		PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
+	PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
+	mdelay(33);
+	PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
+	mdelay(33);
+	PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
+	mdelay(33);
+}
+
+static int __init smp_psurge_probe(void)
+{
+	int i, ncpus;
+
+	/* We don't do SMP on the PPC601 -- paulus */
+	if (PVR_VER(mfspr(PVR)) == 1)
+		return 1;
+
+	/*
+	 * The powersurge cpu board can be used in the generation
+	 * of powermacs that have a socket for an upgradeable cpu card,
+	 * including the 7500, 8500, 9500, 9600.
+	 * The device tree doesn't tell you if you have 2 cpus because
+	 * OF doesn't know anything about the 2nd processor.
+	 * Instead we look for magic bits in magic registers,
+	 * in the hammerhead memory controller in the case of the
+	 * dual-cpu powersurge board.  -- paulus.
+	 */
+	if (find_devices("hammerhead") == NULL)
+		return 1;
+
+	hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
+	quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
+	psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
+
+	psurge_type = psurge_quad_probe();
+	if (psurge_type != PSURGE_DUAL) {
+		psurge_quad_init();
+		/* All released cards using this HW design have 4 CPUs */
+		ncpus = 4;
+	} else {
+		iounmap((void *) quad_base);
+		if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
+			/* not a dual-cpu card */
+			iounmap((void *) hhead_base);
+			return 1;
+		}
+		ncpus = 2;
+	}
+
+	psurge_start = ioremap(PSURGE_START, 4);
+	psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
+
+	/* this is not actually strictly necessary -- paulus. */
+	for (i = 1; i < ncpus; ++i)
+		smp_hw_index[i] = i;
+
+	if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
+
+	return ncpus;
+}
+
+static void __init smp_psurge_kick_cpu(int nr)
+{
+	void (*start)(void) = __secondary_start_psurge;
+	unsigned long a;
+
+	/* may need to flush here if secondary bats aren't setup */
+	for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+		asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+	asm volatile("sync");
+
+	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
+
+	/* setup entry point of secondary processor */
+	switch (nr) {
+	case 2:
+		start = __secondary_start_psurge2;
+		break;
+	case 3:
+		start = __secondary_start_psurge3;
+		break;
+	}
+
+	out_be32(psurge_start, __pa(start));
+	mb();
+
+	psurge_set_ipi(nr);
+	udelay(10);
+	psurge_clr_ipi(nr);
+
+	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
+}
+
+/*
+ * With the dual-cpu powersurge board, the decrementers and timebases
+ * of both cpus are frozen after the secondary cpu is started up,
+ * until we give the secondary cpu another interrupt.  This routine
+ * uses this to get the timebases synchronized.
+ *  -- paulus.
+ */
+static void __init psurge_dual_sync_tb(int cpu_nr)
+{
+	static volatile int sec_tb_reset = 0;
+	int t;
+
+	set_dec(tb_ticks_per_jiffy);
+	set_tb(0, 0);
+	last_jiffy_stamp(cpu_nr) = 0;
+
+	if (cpu_nr > 0) {
+		mb();
+		sec_tb_reset = 1;
+		return;
+	}
+
+	/* wait for the secondary to have reset its TB before proceeding */
+	for (t = 10000000; t > 0 && !sec_tb_reset; --t)
+		;
+
+	/* now interrupt the secondary, starting both TBs */
+	psurge_set_ipi(1);
+
+	smp_tb_synchronized = 1;
+}
+
+static void __init
+smp_psurge_setup_cpu(int cpu_nr)
+{
+
+	if (cpu_nr == 0) {
+		if (smp_num_cpus < 2)
+			return;
+		/* reset the entry point so if we get another intr we won't
+		 * try to startup again */
+		out_be32(psurge_start, 0x100);
+		if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0))
+			printk(KERN_ERR "Couldn't get primary IPI interrupt");
+	}
+
+	if (psurge_type == PSURGE_DUAL)
+		psurge_dual_sync_tb(cpu_nr);
+}
+
+static int __init
+smp_core99_probe(void)
+{
+	struct device_node *cpus;
+	int i, ncpus = 1;
+	extern int powersave_nap;
+
+	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
+	cpus = find_type_devices("cpu");
+	if (cpus)
+		while ((cpus = cpus->next) != NULL)
+			++ncpus;
+	printk("smp_core99_probe: found %d cpus\n", ncpus);
+	if (ncpus > 1) {
+		openpic_request_IPIs();
+		for (i = 1; i < ncpus; ++i)
+			smp_hw_index[i] = i;
+		powersave_nap = 0;
+		cpu_setup_grab();
+	}
+
+	return ncpus;
+}
+
+static void __init
+smp_core99_kick_cpu(int nr)
+{
+	unsigned long save_vector, new_vector;
+	unsigned long flags;
+
+	volatile unsigned long *vector
+		 = ((volatile unsigned long *)(KERNELBASE+0x100));
+	if (nr < 1 || nr > 3)
+		return;
+	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
+
+	local_irq_save(flags);
+	local_irq_disable();
+	
+	/* Save reset vector */
+	save_vector = *vector;
+	
+	/* Setup fake reset vector that does	  
+	 *   b __secondary_start_psurge - KERNELBASE
+	 */  
+	switch(nr) {
+		case 1:
+			new_vector = (unsigned long)__secondary_start_psurge;
+			break;
+		case 2:
+			new_vector = (unsigned long)__secondary_start_psurge2;
+			break;
+		case 3:
+			new_vector = (unsigned long)__secondary_start_psurge3;
+			break;
+	}
+	*vector = 0x48000002 + new_vector - KERNELBASE;
+	
+	/* flush data cache and inval instruction cache */
+	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+	
+	/* Put some life in our friend */
+	pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
+	
+	/* FIXME: We wait a bit for the CPU to take the exception, I should
+	 * instead wait for the entry code to set something for me. Well,
+	 * ideally, all that crap will be done in prom.c and the CPU left
+	 * in a RAM-based wait loop like CHRP.
+	 */
+	mdelay(1);
+	
+	/* Restore our exception vector */
+	*vector = save_vector;
+	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+	
+	local_irq_restore(flags);
+	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
+}
+
+static void __init
+smp_core99_setup_cpu(int cpu_nr)
+{
+	/* Setup some registers */
+	if (cpu_nr != 0)
+		cpu_setup_apply(cpu_nr);
+	
+	/* Setup openpic */
+	do_openpic_setup_cpu();
+
+	/* Setup L2/L3 */
+	if (cpu_nr == 0)
+		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+}
+
+/* PowerSurge-style Macs */
+struct smp_ops_t psurge_smp_ops __pmacdata = {
+	smp_psurge_message_pass,
+	smp_psurge_probe,
+	smp_psurge_kick_cpu,
+	smp_psurge_setup_cpu,
+};
+
+/* Core99 Macs (dual G4s) */
+struct smp_ops_t core99_smp_ops __pmacdata = {
+	smp_openpic_message_pass,
+	smp_core99_probe,
+	smp_core99_kick_cpu,
+	smp_core99_setup_cpu,
+};
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/pmac_time.c linux-2.4.20-pre2/arch/ppc/platforms/pmac_time.c
--- linux-2.4.20-pre1/arch/ppc/platforms/pmac_time.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/pmac_time.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,282 @@
+/*
+ * BK Id: SCCS/s.pmac_time.c 1.19 12/04/01 01:24:51 benh
+ */
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * We use the decrementer register for our periodic interrupts.
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#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/init.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/hardirq.h>
+#include <asm/time.h>
+#include <asm/nvram.h>
+
+extern rwlock_t xtime_lock;
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET	2082844800
+
+/*
+ * Calibrate the decrementer frequency with the VIA timer 1.
+ */
+#define VIA_TIMER_FREQ_6	4700000	/* time 1 frequency * 6 */
+
+/* VIA registers */
+#define RS		0x200		/* skip between registers */
+#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
+#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
+#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
+#define ACR		(11*RS)		/* Auxiliary control register */
+#define IFR		(13*RS)		/* Interrupt flag register */
+
+/* Bits in ACR */
+#define T1MODE		0xc0		/* Timer 1 mode */
+#define T1MODE_CONT	0x40		/*  continuous interrupts */
+
+/* Bits in IFR and IER */
+#define T1_INT		0x40		/* Timer 1 interrupt */
+
+extern struct timezone sys_tz;
+
+long __init
+pmac_time_init(void)
+{
+#ifdef CONFIG_NVRAM
+	s32 delta = 0;
+	int dst;
+	
+	delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
+	delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
+	delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
+	if (delta & 0x00800000UL)
+		delta |= 0xFF000000UL;
+	dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
+	printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
+		dst ? "on" : "off");
+	return delta;
+#else
+	return 0;
+#endif
+}
+
+unsigned long __pmac
+pmac_get_rtc_time(void)
+{
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
+	struct adb_request req;
+	unsigned long now;
+#endif
+
+	/* Get the time from the RTC */
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
+		if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
+			return 0;
+		while (!req.complete)
+			cuda_poll();
+		if (req.reply_len != 7)
+			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+			       req.reply_len);
+		now = (req.reply[3] << 24) + (req.reply[4] << 16)
+			+ (req.reply[5] << 8) + req.reply[6];
+		return now - RTC_OFFSET;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
+		if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+			return 0;
+		while (!req.complete)
+			pmu_poll();
+		if (req.reply_len != 4)
+			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+			       req.reply_len);
+		now = (req.reply[0] << 24) + (req.reply[1] << 16)
+			+ (req.reply[2] << 8) + req.reply[3];
+		return now - RTC_OFFSET;
+#endif /* CONFIG_ADB_PMU */
+	default: ;
+	}
+	return 0;
+}
+
+int __pmac
+pmac_set_rtc_time(unsigned long nowtime)
+{
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
+	struct adb_request req;
+#endif
+
+	nowtime += RTC_OFFSET;
+
+	switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+	case SYS_CTRLER_CUDA:
+		if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+				 nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+			return 0;
+		while (!req.complete)
+			cuda_poll();
+		if ((req.reply_len != 3) && (req.reply_len != 7))
+			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+			       req.reply_len);
+		return 1;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+	case SYS_CTRLER_PMU:
+		if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+				nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+			return 0;
+		while (!req.complete)
+			pmu_poll();
+		if (req.reply_len != 0)
+			printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+			       req.reply_len);
+		return 1;
+#endif /* CONFIG_ADB_PMU */
+	default:
+		return 0;
+	}
+}
+
+/*
+ * Calibrate the decrementer register using VIA timer 1.
+ * This is used both on powermacs and CHRP machines.
+ */
+int __init
+via_calibrate_decr(void)
+{
+	struct device_node *vias;
+	volatile unsigned char *via;
+	int count = VIA_TIMER_FREQ_6 / HZ;
+	unsigned int dstart, dend;
+
+	vias = find_devices("via-cuda");
+	if (vias == 0)
+		vias = find_devices("via-pmu");
+	if (vias == 0)
+		vias = find_devices("via");
+	if (vias == 0 || vias->n_addrs == 0)
+		return 0;
+	via = (volatile unsigned char *)
+		ioremap(vias->addrs[0].address, vias->addrs[0].size);
+
+	/* set timer 1 for continuous interrupts */
+	out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
+	/* set the counter to a small value */
+	out_8(&via[T1CH], 2);
+	/* set the latch to `count' */
+	out_8(&via[T1LL], count);
+	out_8(&via[T1LH], count >> 8);
+	/* wait until it hits 0 */
+	while ((in_8(&via[IFR]) & T1_INT) == 0)
+		;
+	dstart = get_dec();
+	/* clear the interrupt & wait until it hits 0 again */
+	in_8(&via[T1CL]);
+	while ((in_8(&via[IFR]) & T1_INT) == 0)
+		;
+	dend = get_dec();
+
+	tb_ticks_per_jiffy = (dstart - dend) / 6;
+	tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
+
+	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
+	       tb_ticks_per_jiffy, dstart - dend);
+
+	return 1;
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Reset the time after a sleep.
+ */
+static int __pmac
+time_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	static unsigned long time_diff;
+	unsigned long flags;
+
+	switch (when) {
+	case PBOOK_SLEEP_NOW:
+		read_lock_irqsave(&xtime_lock, flags);
+		time_diff = xtime.tv_sec - pmac_get_rtc_time();
+		read_unlock_irqrestore(&xtime_lock, flags);
+		break;
+	case PBOOK_WAKE:
+		write_lock_irqsave(&xtime_lock, flags);
+		xtime.tv_sec = pmac_get_rtc_time() + time_diff;
+		xtime.tv_usec = 0;
+		last_rtc_update = xtime.tv_sec;
+		write_unlock_irqrestore(&xtime_lock, flags);
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+
+static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
+	time_sleep_notify, SLEEP_LEVEL_MISC,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+/*
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
+ */
+void __init
+pmac_calibrate_decr(void)
+{
+	struct device_node *cpu;
+	unsigned int freq, *fp;
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&time_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+	/* We assume MacRISC2 machines have correct device-tree
+	 * calibration. That's better since the VIA itself seems
+	 * to be slightly off. --BenH
+	 */
+	if (!machine_is_compatible("MacRISC2"))
+		if (via_calibrate_decr())
+			return;
+
+	/*
+	 * The cpu node should have a timebase-frequency property
+	 * to tell us the rate at which the decrementer counts.
+	 */
+	cpu = find_type_devices("cpu");
+	if (cpu == 0)
+		panic("can't find cpu node in time_init");
+	fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
+	if (fp == 0)
+		panic("can't get cpu timebase frequency");
+	freq = *fp;
+	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
+	       freq/1000000, freq%1000000);
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/prep_pci.c linux-2.4.20-pre2/arch/ppc/platforms/prep_pci.c
--- linux-2.4.20-pre1/arch/ppc/platforms/prep_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/prep_pci.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,1269 @@
+/*
+ * BK Id: SCCS/s.prep_pci.c 1.33 12/20/01 15:36:12 trini
+ */
+/*
+ * PReP pci functions.
+ * Originally by Gary Thomas
+ * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * The motherboard routes/maps will disappear shortly. -- Cort
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/sections.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/residual.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/open_pic.h>
+
+#define MAX_DEVNR 22
+
+/* Which PCI interrupt line does a given device [slot] use? */
+/* Note: This really should be two dimensional based in slot/pin used */
+static unsigned char *Motherboard_map;
+unsigned char *Motherboard_map_name;
+
+/* How is the 82378 PIRQ mapping setup? */
+static unsigned char *Motherboard_routes;
+
+static void (*Motherboard_non0)(struct pci_dev *);
+
+static void Powerplus_Map_Non0(struct pci_dev *);
+
+/* Used for Motorola to store system config register */
+static unsigned long	*ProcInfo;
+
+/* Tables for known hardware */   
+
+/* Motorola PowerStackII - Utah */
+static char Utah_pci_IRQ_map[23] __prepdata =
+{
+        0,   /* Slot 0  - unused */
+        0,   /* Slot 1  - unused */
+        5,   /* Slot 2  - SCSI - NCR825A  */
+        0,   /* Slot 3  - unused */
+        1,   /* Slot 4  - Ethernet - DEC2114x */
+        0,   /* Slot 5  - unused */
+        3,   /* Slot 6  - PCI Card slot #1 */
+        4,   /* Slot 7  - PCI Card slot #2 */
+        5,   /* Slot 8  - PCI Card slot #3 */
+        5,   /* Slot 9  - PCI Bridge */
+             /* added here in case we ever support PCI bridges */
+             /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
+        0,   /* Slot 10 - unused */
+        0,   /* Slot 11 - unused */
+        5,   /* Slot 12 - SCSI - NCR825A */
+        0,   /* Slot 13 - unused */
+        3,   /* Slot 14 - enet */
+        0,   /* Slot 15 - unused */
+        2,   /* Slot 16 - unused */
+        3,   /* Slot 17 - unused */
+        5,   /* Slot 18 - unused */
+        0,   /* Slot 19 - unused */
+        0,   /* Slot 20 - unused */
+        0,   /* Slot 21 - unused */
+        0,   /* Slot 22 - unused */
+};
+
+static char Utah_pci_IRQ_routes[] __prepdata =
+{
+        0,   /* Line 0 - Unused */
+        9,   /* Line 1 */
+	10,  /* Line 2 */
+        11,  /* Line 3 */
+        14,  /* Line 4 */
+        15,  /* Line 5 */
+};
+
+/* Motorola PowerStackII - Omaha */
+/* no integrated SCSI or ethernet */
+static char Omaha_pci_IRQ_map[23] __prepdata =
+{
+        0,   /* Slot 0  - unused */
+        0,   /* Slot 1  - unused */
+        3,   /* Slot 2  - Winbond EIDE */
+        0,   /* Slot 3  - unused */
+        0,   /* Slot 4  - unused */
+        0,   /* Slot 5  - unused */
+        1,   /* Slot 6  - PCI slot 1 */
+        2,   /* Slot 7  - PCI slot 2  */
+        3,   /* Slot 8  - PCI slot 3 */
+        4,   /* Slot 9  - PCI slot 4 */ /* needs indirect access */
+        0,   /* Slot 10 - unused */
+        0,   /* Slot 11 - unused */
+        0,   /* Slot 12 - unused */
+        0,   /* Slot 13 - unused */
+        0,   /* Slot 14 - unused */
+        0,   /* Slot 15 - unused */
+        1,   /* Slot 16  - PCI slot 1 */
+        2,   /* Slot 17  - PCI slot 2  */
+        3,   /* Slot 18  - PCI slot 3 */
+        4,   /* Slot 19  - PCI slot 4 */ /* needs indirect access */
+        0,
+        0,
+        0,
+};
+
+static char Omaha_pci_IRQ_routes[] __prepdata =
+{
+        0,   /* Line 0 - Unused */
+        9,   /* Line 1 */
+        11,  /* Line 2 */
+        14,  /* Line 3 */
+        15   /* Line 4 */
+};
+
+/* Motorola PowerStack */
+static char Blackhawk_pci_IRQ_map[19] __prepdata =
+{
+  	0,	/* Slot 0  - unused */
+  	0,	/* Slot 1  - unused */
+  	0,	/* Slot 2  - unused */
+  	0,	/* Slot 3  - unused */
+  	0,	/* Slot 4  - unused */
+  	0,	/* Slot 5  - unused */
+  	0,	/* Slot 6  - unused */
+  	0,	/* Slot 7  - unused */
+  	0,	/* Slot 8  - unused */
+  	0,	/* Slot 9  - unused */
+  	0,	/* Slot 10 - unused */
+  	0,	/* Slot 11 - unused */
+  	3,	/* Slot 12 - SCSI */
+  	0,	/* Slot 13 - unused */
+  	1,	/* Slot 14 - Ethernet */
+  	0,	/* Slot 15 - unused */
+ 	1,	/* Slot P7 */
+ 	2,	/* Slot P6 */
+ 	3,	/* Slot P5 */
+};
+
+static char Blackhawk_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* Line 0 - Unused */
+   	9,	/* Line 1 */
+   	11,	/* Line 2 */
+   	15,	/* Line 3 */
+   	15	/* Line 4 */
+};
+   
+/* Motorola Mesquite */
+static char Mesquite_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+	0,	/* Slot 12 - unused */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - Ethernet */
+	0,	/* Slot 15 - unused */
+	3,	/* Slot 16 - PMC */
+	0,	/* Slot 17 - unused */
+	0,	/* Slot 18 - unused */
+	0,	/* Slot 19 - unused */
+	0,	/* Slot 20 - unused */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola Sitka */
+static char Sitka_pci_IRQ_map[21] __prepdata =
+{
+	0,      /* Slot 0  - unused */
+	0,      /* Slot 1  - unused */
+	0,      /* Slot 2  - unused */
+	0,      /* Slot 3  - unused */
+	0,      /* Slot 4  - unused */
+	0,      /* Slot 5  - unused */
+	0,      /* Slot 6  - unused */
+	0,      /* Slot 7  - unused */
+	0,      /* Slot 8  - unused */
+	0,      /* Slot 9  - unused */
+	0,      /* Slot 10 - unused */
+	0,      /* Slot 11 - unused */
+	0,      /* Slot 12 - unused */
+	0,      /* Slot 13 - unused */
+	2,      /* Slot 14 - Ethernet */
+	0,      /* Slot 15 - unused */
+	9,      /* Slot 16 - PMC 1  */
+	12,     /* Slot 17 - PMC 2  */
+	0,      /* Slot 18 - unused */
+	0,      /* Slot 19 - unused */
+	4,      /* Slot 20 - NT P2P bridge */
+};
+
+/* Motorola MTX */
+static char MTX_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+	3,	/* Slot 12 - SCSI */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - Ethernet */
+	0,	/* Slot 15 - unused */
+	9,      /* Slot 16 - PCI/PMC slot 1 */
+	10,     /* Slot 17 - PCI/PMC slot 2 */
+	11,     /* Slot 18 - PCI slot 3 */
+	0,	/* Slot 19 - unused */
+	0,	/* Slot 20 - unused */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola MTX Plus */
+/* Secondary bus interrupt routing is not supported yet */
+static char MTXplus_pci_IRQ_map[23] __prepdata =
+{
+        0,      /* Slot 0  - unused */
+        0,      /* Slot 1  - unused */
+        0,      /* Slot 2  - unused */
+        0,      /* Slot 3  - unused */
+        0,      /* Slot 4  - unused */
+        0,      /* Slot 5  - unused */
+        0,      /* Slot 6  - unused */
+        0,      /* Slot 7  - unused */
+        0,      /* Slot 8  - unused */
+        0,      /* Slot 9  - unused */
+        0,      /* Slot 10 - unused */
+        0,      /* Slot 11 - unused */
+        3,      /* Slot 12 - SCSI */
+        0,      /* Slot 13 - unused */
+        2,      /* Slot 14 - Ethernet 1 */
+        0,      /* Slot 15 - unused */
+        9,      /* Slot 16 - PCI slot 1P */
+        10,     /* Slot 17 - PCI slot 2P */
+        11,     /* Slot 18 - PCI slot 3P */
+        10,     /* Slot 19 - Ethernet 2 */
+        0,      /* Slot 20 - P2P Bridge */
+        0,      /* Slot 21 - unused */
+        0,      /* Slot 22 - unused */
+};
+
+static char Raven_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* This is a dummy structure */
+};
+   
+/* Motorola MVME16xx */
+static char Genesis_pci_IRQ_map[16] __prepdata =
+{
+  	0,	/* Slot 0  - unused */
+  	0,	/* Slot 1  - unused */
+  	0,	/* Slot 2  - unused */
+  	0,	/* Slot 3  - unused */
+  	0,	/* Slot 4  - unused */
+  	0,	/* Slot 5  - unused */
+  	0,	/* Slot 6  - unused */
+  	0,	/* Slot 7  - unused */
+  	0,	/* Slot 8  - unused */
+  	0,	/* Slot 9  - unused */
+  	0,	/* Slot 10 - unused */
+  	0,	/* Slot 11 - unused */
+  	3,	/* Slot 12 - SCSI */
+  	0,	/* Slot 13 - unused */
+  	1,	/* Slot 14 - Ethernet */
+  	0,	/* Slot 15 - unused */
+};
+
+static char Genesis_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* Line 0 - Unused */
+   	10,	/* Line 1 */
+   	11,	/* Line 2 */
+   	14,	/* Line 3 */
+   	15	/* Line 4 */
+};
+   
+static char Genesis2_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - Ethernet */
+	0,	/* Slot 11 - Universe PCI - VME Bridge */
+	3,	/* Slot 12 - unused */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - SCSI */
+	0,	/* Slot 15 - unused */
+	9,	/* Slot 16 - PMC 1 */
+	12,	/* Slot 17 - pci */
+	11,	/* Slot 18 - pci */
+	10,	/* Slot 19 - pci */
+	0,	/* Slot 20 - pci */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola Series-E */
+static char Comet_pci_IRQ_map[23] __prepdata =
+{
+  	0,	/* Slot 0  - unused */
+  	0,	/* Slot 1  - unused */
+  	0,	/* Slot 2  - unused */
+  	0,	/* Slot 3  - unused */
+  	0,	/* Slot 4  - unused */
+  	0,	/* Slot 5  - unused */
+  	0,	/* Slot 6  - unused */
+  	0,	/* Slot 7  - unused */
+  	0,	/* Slot 8  - unused */
+  	0,	/* Slot 9  - unused */
+  	0,	/* Slot 10 - unused */
+  	0,	/* Slot 11 - unused */
+  	3,	/* Slot 12 - SCSI */
+  	0,	/* Slot 13 - unused */
+  	1,	/* Slot 14 - Ethernet */
+  	0,	/* Slot 15 - unused */
+	1,	/* Slot 16 - PCI slot 1 */
+	2,	/* Slot 17 - PCI slot 2 */
+	3,	/* Slot 18 - PCI slot 3 */
+	4,	/* Slot 19 - PCI bridge */
+	0,
+	0,
+	0,
+};
+
+static char Comet_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* Line 0 - Unused */
+   	10,	/* Line 1 */
+   	11,	/* Line 2 */
+   	14,	/* Line 3 */
+   	15	/* Line 4 */
+};
+
+/* Motorola Series-EX */
+static char Comet2_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	3,	/* Slot 2  - SCSI - NCR825A */
+	0,	/* Slot 3  - unused */
+	1,	/* Slot 4  - Ethernet - DEC2104X */
+	0,	/* Slot 5  - unused */
+	1,	/* Slot 6  - PCI slot 1 */
+	2,	/* Slot 7  - PCI slot 2 */
+	3,	/* Slot 8  - PCI slot 3 */
+	4,	/* Slot 9  - PCI bridge  */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+	3,	/* Slot 12 - SCSI - NCR825A */
+	0,	/* Slot 13 - unused */
+	1,	/* Slot 14 - Ethernet - DEC2104X */
+	0,	/* Slot 15 - unused */
+	1,	/* Slot 16 - PCI slot 1 */
+	2,	/* Slot 17 - PCI slot 2 */
+	3,	/* Slot 18 - PCI slot 3 */
+	4,	/* Slot 19 - PCI bridge */
+	0,
+	0,
+	0,
+};
+
+static char Comet2_pci_IRQ_routes[] __prepdata =
+{
+	0,	/* Line 0 - Unused */
+	10,	/* Line 1 */
+	11,	/* Line 2 */
+	14,	/* Line 3 */
+	15,	/* Line 4 */
+};
+
+/*
+ * ibm 830 (and 850?).
+ * This is actually based on the Carolina motherboard
+ * -- Cort
+ */
+static char ibm8xx_pci_IRQ_map[23] __prepdata = {
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 - FireCoral */
+        4, /* Slot 12 - Ethernet  PCIINTD# */
+        2, /* Slot 13 - PCI Slot #2 */
+        2, /* Slot 14 - S3 Video PCIINTD# */
+        0, /* Slot 15 - onboard SCSI (INDI) [1] */
+        3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
+        0, /* Slot 17 - unused */
+        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+        0, /* Slot 19 - unused */
+        0, /* Slot 20 - unused */
+        0, /* Slot 21 - unused */
+        2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+
+static char ibm8xx_pci_IRQ_routes[] __prepdata = {
+        0,      /* Line 0 - unused */
+        15,     /* Line 1 */
+        15,     /* Line 2 */
+        15,     /* Line 3 */
+        15,     /* Line 4 */
+};
+
+/*
+ * a 6015 ibm board
+ * -- Cort
+ */
+static char ibm6015_pci_IRQ_map[23] __prepdata = {
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 -  */
+        1, /* Slot 12 - SCSI */
+        2, /* Slot 13 -  */
+        2, /* Slot 14 -  */
+        1, /* Slot 15 -  */
+        1, /* Slot 16 -  */
+        0, /* Slot 17 -  */
+        2, /* Slot 18 -  */
+        0, /* Slot 19 -  */
+        0, /* Slot 20 -  */
+        0, /* Slot 21 -  */
+        2, /* Slot 22 -  */
+};
+
+static char ibm6015_pci_IRQ_routes[] __prepdata = {
+        0,      /* Line 0 - unused */
+        13,     /* Line 1 */
+        15,     /* Line 2 */
+        15,     /* Line 3 */
+        15,     /* Line 4 */
+};
+
+
+/* IBM Nobis and Thinkpad 850 */
+static char Nobis_pci_IRQ_map[23] __prepdata ={
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 - unused */
+        3, /* Slot 12 - SCSI */
+        0, /* Slot 13 - unused */
+        0, /* Slot 14 - unused */
+        0, /* Slot 15 - unused */
+};
+
+static char Nobis_pci_IRQ_routes[] __prepdata = {
+        0, /* Line 0 - Unused */
+        13, /* Line 1 */
+        13, /* Line 2 */
+        13, /* Line 3 */
+        13      /* Line 4 */
+};
+
+/*
+ * IBM RS/6000 43p/140  -- paulus
+ * XXX we should get all this from the residual data
+ */
+static char ibm43p_pci_IRQ_map[23] __prepdata = {
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 - FireCoral ISA bridge */
+        6, /* Slot 12 - Ethernet  */
+        0, /* Slot 13 - openpic */
+        0, /* Slot 14 - unused */
+        0, /* Slot 15 - unused */
+        7, /* Slot 16 - NCR58C825a onboard scsi */
+        0, /* Slot 17 - unused */
+        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+        0, /* Slot 19 - unused */
+        0, /* Slot 20 - unused */
+        0, /* Slot 21 - unused */
+        1, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+
+static char ibm43p_pci_IRQ_routes[] __prepdata = {
+        0,      /* Line 0 - unused */
+        15,     /* Line 1 */
+        15,     /* Line 2 */
+        15,     /* Line 3 */
+        15,     /* Line 4 */
+};
+
+/* Motorola PowerPlus architecture PCI IRQ tables */
+/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
+
+struct powerplus_irq_list
+{
+	unsigned char primary[4];       /* INT A-D */
+	unsigned char secondary[4];     /* INT A-D */
+};
+
+/*
+ * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
+ * OpenPIC inputs 9-12.  PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 5-8.  These values are offset by
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata =
+{
+	{25, 26, 27, 28},
+	{21, 22, 23, 24}
+};
+
+/*
+ * For the MCP750 (system slot board), cPCI INTs A-D are routed to
+ * OpenPIC inputs 8-11 and the PMC INTs A-D are routed to OpenPIC
+ * input 3.  On a hot swap MCP750, the companion card PCI INTs A-D
+ * are routed to OpenPIC inputs 12-15. These values are offset by
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata =
+{
+	{24, 25, 26, 27},
+	{28, 29, 30, 31}
+};
+
+/*
+ * This table represents the standard PCI swizzle defined in the
+ * PCI bus specification.
+ */
+static unsigned char prep_pci_intpins[4][4] __prepdata =
+{
+	{ 1, 2, 3, 4},  /* Buses 0, 4, 8, ... */
+	{ 2, 3, 4, 1},  /* Buses 1, 5, 9, ... */
+	{ 3, 4, 1, 2},  /* Buses 2, 6, 10 ... */
+	{ 4, 1, 2, 3},  /* Buses 3, 7, 11 ... */
+};
+
+/* We have to turn on LEVEL mode for changed IRQ's */
+/* All PCI IRQ's need to be level mode, so this should be something
+ * other than hard-coded as well... IRQ's are individually mappable
+ * to either edge or level.
+ */
+
+/*
+ * 8259 edge/level control definitions
+ */
+#define ISA8259_M_ELCR 0x4d0
+#define ISA8259_S_ELCR 0x4d1
+
+#define ELCRS_INT15_LVL         0x80
+#define ELCRS_INT14_LVL         0x40
+#define ELCRS_INT12_LVL         0x10
+#define ELCRS_INT11_LVL         0x08
+#define ELCRS_INT10_LVL         0x04
+#define ELCRS_INT9_LVL          0x02
+#define ELCRS_INT8_LVL          0x01
+#define ELCRM_INT7_LVL          0x80
+#define ELCRM_INT5_LVL          0x20
+
+#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset)
+#define DEVNO(dev)  (dev>>3)                                  
+
+#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
+#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define cfg_read_bad(val, size)		*val = bad_##size;
+#define cfg_write_bad(val, size)
+
+#define bad_byte	0xff
+#define bad_word	0xffff
+#define bad_dword	0xffffffffU
+
+#define PREP_PCI_OP(rw, size, type, op)					\
+static int __prep							\
+prep_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
+{									\
+	if ((dev->bus->number != 0) || (DEVNO(dev->devfn) > MAX_DEVNR))	\
+	{                   						\
+		cfg_##rw##_bad(val, size)				\
+		return PCIBIOS_DEVICE_NOT_FOUND;    			\
+	}								\
+	cfg_##rw(val, CFGPTR(dev->devfn), type, op);			\
+	return PCIBIOS_SUCCESSFUL;					\
+}
+
+PREP_PCI_OP(read, byte, u8 *, in_8)
+PREP_PCI_OP(read, word, u16 *, in_le16)
+PREP_PCI_OP(read, dword, u32 *, in_le32)
+PREP_PCI_OP(write, byte, u8, out_8)
+PREP_PCI_OP(write, word, u16, out_le16)
+PREP_PCI_OP(write, dword, u32, out_le32)
+
+static struct pci_ops prep_pci_ops =
+{
+	prep_read_config_byte,
+	prep_read_config_word,
+	prep_read_config_dword,
+	prep_write_config_byte,
+	prep_write_config_word,
+	prep_write_config_dword
+};
+
+#define MOTOROLA_CPUTYPE_REG	0x800
+#define MOTOROLA_BASETYPE_REG	0x803
+#define MPIC_RAVEN_ID		0x48010000
+#define	MPIC_HAWK_ID		0x48030000
+#define	MOT_PROC2_BIT		0x800
+
+static u_char mvme2600_openpic_initsenses[] __initdata = {
+    1,	/* MVME2600_INT_SIO */
+    0,	/* MVME2600_INT_FALCN_ECC_ERR */
+    1,	/* MVME2600_INT_PCI_ETHERNET */
+    1,	/* MVME2600_INT_PCI_SCSI */
+    1,	/* MVME2600_INT_PCI_GRAPHICS */
+    1,	/* MVME2600_INT_PCI_VME0 */
+    1,	/* MVME2600_INT_PCI_VME1 */
+    1,	/* MVME2600_INT_PCI_VME2 */
+    1,	/* MVME2600_INT_PCI_VME3 */
+    1,	/* MVME2600_INT_PCI_INTA */
+    1,	/* MVME2600_INT_PCI_INTB */
+    1,	/* MVME2600_INT_PCI_INTC */
+    1,	/* MVME2600_INT_PCI_INTD */
+    1,	/* MVME2600_INT_LM_SIG0 */
+    1,	/* MVME2600_INT_LM_SIG1 */
+};
+
+#define MOT_RAVEN_PRESENT	0x1
+#define MOT_HAWK_PRESENT	0x2
+
+int mot_entry = -1;
+int prep_keybd_present = 1;
+int MotMPIC;
+int mot_multi;
+
+int __init
+raven_init(void)
+{
+	unsigned int	devid;
+	unsigned int	pci_membase;
+	unsigned char	base_mod;
+
+	/* Check to see if the Raven chip exists. */
+	if ( _prep_type != _PREP_Motorola) {
+		OpenPIC_Addr = NULL;
+		return 0;
+	}
+
+	/* Check to see if this board is a type that might have a Raven. */
+	if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
+		OpenPIC_Addr = NULL;
+		return 0;
+	}
+
+	/* Check the first PCI device to see if it is a Raven. */
+	early_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &devid);
+
+	switch (devid & 0xffff0000) {
+	case MPIC_RAVEN_ID:
+		MotMPIC = MOT_RAVEN_PRESENT;
+		break;
+	case MPIC_HAWK_ID:
+		MotMPIC = MOT_HAWK_PRESENT;
+		break;
+	default:
+		OpenPIC_Addr = NULL;
+		return 0;
+	}
+
+
+	/* Read the memory base register. */
+	early_read_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+	if (pci_membase == 0) {
+		OpenPIC_Addr = NULL;
+		return 0;
+	}
+
+	/* Map the Raven MPIC registers to virtual memory. */
+	OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000);
+
+	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+
+	ppc_md.get_irq = openpic_get_irq;
+	
+	/* If raven is present on Motorola store the system config register
+	 * for later use.
+	 */
+	ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
+
+	/* Indicate to system if this is a multiprocessor board */
+	if (!(*ProcInfo & MOT_PROC2_BIT)) {
+		mot_multi = 1;
+	}
+
+	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
+	 * no keyboard controller and we have to indicate that.
+	 */
+	base_mod = inb(MOTOROLA_BASETYPE_REG);
+	if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
+	    (base_mod == 0xFA) || (base_mod == 0xE1))
+		prep_keybd_present = 0;
+
+	return 1;
+}
+
+struct mot_info {
+	int		cpu_type;	/* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
+					/* 0x200 if this board has a Hawk chip. */
+	int		base_type;
+	int		max_cpu;	/* ored with 0x80 if this board should be checked for multi CPU */
+	const char	*name;
+	unsigned char	*map;
+	unsigned char	*routes;
+	void            (*map_non0_bus)(struct pci_dev *);      /* For boards with more than bus 0 devices. */
+	struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
+	unsigned char   secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */
+} mot_info[] __prepdata = {
+	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
+	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x000, 0x00, 0x00, "",					NULL,			NULL, NULL, NULL, 0x00}
+};
+
+void __init
+ibm_prep_init(void)
+{
+	u32 addr;
+#ifdef CONFIG_PREP_RESIDUAL
+	PPC_DEVICE *mpic;
+#endif
+
+	if (inb(0x0852) == 0xd5) {
+		/* This is for the 43p-140 */
+		early_read_config_dword(0, 0, PCI_DEVFN(13, 0),
+					PCI_BASE_ADDRESS_0, &addr);
+		if (addr != 0xffffffff
+		    && !(addr & PCI_BASE_ADDRESS_SPACE_IO)
+		    && (addr &= PCI_BASE_ADDRESS_MEM_MASK) != 0) {
+			addr += PREP_ISA_MEM_BASE;
+			OpenPIC_Addr = ioremap(addr, 0x40000);
+			ppc_md.get_irq = openpic_get_irq;
+		}
+	}
+
+#ifdef CONFIG_PREP_RESIDUAL
+	mpic = residual_find_device(-1, NULL, SystemPeripheral,
+				    ProgrammableInterruptController, MPIC, 0);
+	if (mpic != NULL)
+		printk("mpic = %p\n", mpic);
+#endif
+}
+
+static void __init
+ibm43p_pci_map_non0(struct pci_dev *dev)
+{
+	unsigned char intpin;
+	static unsigned char bridge_intrs[4] = { 3, 4, 5, 8 };
+
+	if (dev == NULL)
+		return;
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin);
+	if (intpin < 1 || intpin > 4)
+		return;
+	intpin = (PCI_SLOT(dev->devfn) + intpin - 1) & 3;
+	dev->irq = openpic_to_irq(bridge_intrs[intpin]);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+}
+
+void __init
+prep_route_pci_interrupts(void)
+{
+	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
+	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
+	int i;
+	
+	if ( _prep_type == _PREP_Motorola)
+	{
+		unsigned short irq_mode;
+		unsigned char  cpu_type;
+		unsigned char  base_mod;
+		int	       entry;
+
+		cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
+		base_mod = inb(MOTOROLA_BASETYPE_REG);
+
+		for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
+			if (mot_info[entry].cpu_type & 0x200) {		 	/* Check for Hawk chip */
+				if (!(MotMPIC & MOT_HAWK_PRESENT))
+					continue;
+			} else {						/* Check non hawk boards */
+				if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
+					continue;
+
+				if (mot_info[entry].base_type == 0) {
+					mot_entry = entry;
+					break;
+				}
+
+				if (mot_info[entry].base_type != base_mod)
+					continue;
+			}
+
+			if (!(mot_info[entry].max_cpu & 0x80)) {
+				mot_entry = entry;
+				break;
+			}
+
+			/* processor 1 not present and max processor zero indicated */
+			if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
+				mot_entry = entry;
+				break;
+			}
+
+			/* processor 1 present and max processor zero indicated */
+			if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
+				mot_entry = entry;
+				break;
+			}
+		}
+
+		if (mot_entry == -1) 	/* No particular cpu type found - assume Blackhawk */
+			mot_entry = 3;
+
+		Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
+		Motherboard_map = mot_info[mot_entry].map;
+		Motherboard_routes = mot_info[mot_entry].routes;
+		Motherboard_non0 = mot_info[mot_entry].map_non0_bus;
+
+		if (!(mot_info[entry].cpu_type & 0x100)) {
+			/* AJF adjust level/edge control according to routes */
+			irq_mode = 0;
+			for (i = 1;  i <= 4;  i++)
+				irq_mode |= ( 1 << Motherboard_routes[i] );
+			outb( irq_mode & 0xff, 0x4d0 );
+			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
+		}
+	} else if ( _prep_type == _PREP_IBM ) {
+		unsigned char planar_id = inb(0x0852);
+		unsigned char irq_edge_mask_lo, irq_edge_mask_hi;
+
+		printk("IBM ID: %08x\n", planar_id);
+		switch(planar_id) {
+		case 0xff:
+			Motherboard_map_name = "IBM Thinkpad 850/860";
+			Motherboard_map = Nobis_pci_IRQ_map;
+			Motherboard_routes = Nobis_pci_IRQ_routes;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+			break;
+		case 0xfc:
+			Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
+			Motherboard_map = ibm6015_pci_IRQ_map;
+			Motherboard_routes = ibm6015_pci_IRQ_routes;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+			break;
+		case 0xd5:
+			Motherboard_map_name = "IBM 43P-140 (Tiger1)";
+			Motherboard_map = ibm43p_pci_IRQ_map;
+			Motherboard_routes = ibm43p_pci_IRQ_routes;
+			Motherboard_non0 = ibm43p_pci_map_non0;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+			break;
+		default:
+			printk(KERN_ERR "Unknown IBM motherboard! Defaulting to Carolina.\n");
+		case 0xf0: /* PowerSeries 830/850 */
+		case 0xf1: /* PowerSeries 830/850 */
+		case 0xf2: /* PowerSeries 830/850 */
+		case 0xf4: /* 7248-43P */
+		case 0xf5: /* 7248-43P */
+		case 0xf6: /* 7248-43P */
+		case 0xf7: /* 7248-43P (missing from Carolina Tech Spec) */
+			Motherboard_map_name = "IBM PS830/PS850/7248 (Carolina)";
+			Motherboard_map = ibm8xx_pci_IRQ_map;
+			Motherboard_routes = ibm8xx_pci_IRQ_routes;
+			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+			irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
+			break;
+		}
+
+		outb(inb(0x04d0)|irq_edge_mask_lo, 0x04d0); /* primary 8259 */
+		outb(inb(0x04d1)|irq_edge_mask_hi, 0x04d1); /* cascaded 8259 */
+	} else {
+		printk("No known machine pci routing!\n");
+		return;
+	}
+	
+	/* Set up mapping from slots */
+	for (i = 1;  i <= 4;  i++)
+		ibc_pirq[i-1] = Motherboard_routes[i];
+	/* Enable PCI interrupts */
+	*ibc_pcicon |= 0x20;
+}
+
+void __init
+prep_pib_init(void)
+{
+	unsigned char   reg;
+	unsigned short  short_reg;
+
+	struct pci_dev *dev = NULL;
+
+	if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) {
+		/*
+		 * Perform specific configuration for the Via Tech or
+		 * or Winbond PCI-ISA-Bridge part.
+		 */
+		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, 
+					PCI_DEVICE_ID_VIA_82C586_1, dev))) {
+			/*
+			 * PPCBUG does not set the enable bits
+			 * for the IDE device. Force them on here.
+			 */
+			pci_read_config_byte(dev, 0x40, &reg);
+
+			reg |= 0x03; /* IDE: Chip Enable Bits */
+			pci_write_config_byte(dev, 0x40, reg);
+		}
+		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+						PCI_DEVICE_ID_VIA_82C586_2,
+						dev)) && (dev->devfn = 0x5a)) {
+			/* Force correct USB interrupt */
+			dev->irq = 11;
+			pci_write_config_byte(dev,
+					PCI_INTERRUPT_LINE,
+					dev->irq);
+		}
+		if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+					PCI_DEVICE_ID_WINBOND_83C553, dev))) {
+			 /* Clear PCI Interrupt Routing Control Register. */
+			short_reg = 0x0000;
+			pci_write_config_word(dev, 0x44, short_reg);
+			if (OpenPIC_Addr){
+				/* Route IDE interrupts to IRQ 14 */
+				reg = 0xEE;
+				pci_write_config_byte(dev, 0x43, reg);
+			}
+		}
+	}
+
+	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+				   PCI_DEVICE_ID_WINBOND_82C105, dev))){
+		if (OpenPIC_Addr){
+			/*
+			 * Disable LEGIRQ mode so PCI INTS are routed
+			 * directly to the 8259 and enable both channels
+			 */
+			pci_write_config_dword(dev, 0x40, 0x10ff0033);
+
+			/* Force correct IDE interrupt */
+			dev->irq = 14;
+			pci_write_config_byte(dev,
+					PCI_INTERRUPT_LINE,
+					dev->irq);
+		} else {
+			/* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
+			pci_write_config_dword(dev, 0x40, 0x10ff08a1);
+		}
+	}
+}
+
+static void __init
+Powerplus_Map_Non0(struct pci_dev *dev)
+{
+	struct pci_bus  *pbus;          /* Parent bus structure pointer */
+	struct pci_dev  *tdev = dev;    /* Temporary device structure */
+	unsigned int    devnum;         /* Accumulated device number */
+	unsigned char   intline;        /* Linux interrupt value */
+	unsigned char   intpin;         /* PCI interrupt pin */
+
+	/* Check for valid PCI dev pointer */
+	if (dev == NULL) return;
+
+	/* Initialize bridge IDSEL variable */
+	devnum = PCI_SLOT(tdev->devfn);
+
+	/* Read the interrupt pin of the device and adjust for indexing */
+	pcibios_read_config_byte(dev->bus->number, dev->devfn,
+			PCI_INTERRUPT_PIN, &intpin);
+
+	/* If device doesn't request an interrupt, return */
+	if ( (intpin < 1) || (intpin > 4) )
+		return;
+
+	intpin--;
+
+	/*
+	 * Walk up to bus 0, adjusting the interrupt pin for the standard
+	 * PCI bus swizzle.
+	 */
+	do {
+		intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+		pbus = tdev->bus;        /* up one level */
+		tdev = pbus->self;
+		devnum = PCI_SLOT(tdev->devfn);
+	} while(tdev->bus->number);
+
+	/* Use the primary interrupt inputs by default */
+	intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+
+	/*
+	 * If the board has secondary interrupt inputs, walk the bus and
+	 * note the devfn of the bridge from bus 0.  If it is the same as
+	 * the devfn of the bus bridge with secondary inputs, use those.
+	 * Otherwise, assume it's a PMC site and get the interrupt line
+	 * value from the interrupt routing table.
+	 */ 
+	if (mot_info[mot_entry].secondary_bridge_devfn) {
+		pbus = dev->bus;
+
+		while (pbus->primary != 0)
+			pbus = pbus->parent;
+
+		if ((pbus->self)->devfn != 0xA0) {
+			if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
+				intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
+			else {
+				if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map)
+					intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16;
+				else {
+					int i;
+					for (i=0;i<3;i++)
+						intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+					intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+				}
+			}
+		}
+	}
+
+	/* Write calculated interrupt value to header and device list */
+	dev->irq = intline;
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)dev->irq);
+}
+
+void __init
+prep_pcibios_fixup(void)
+{
+        struct pci_dev *dev;
+        extern unsigned char *Motherboard_map;
+        extern unsigned char *Motherboard_routes;
+        unsigned char i;
+
+	prep_route_pci_interrupts();
+
+	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+	if (OpenPIC_Addr) {
+		/* PCI interrupts are controlled by the OpenPIC */
+		pci_for_each_dev(dev) {
+			if (dev->bus->number == 0) {
+                       		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
+				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq);
+			} else {
+				if (Motherboard_non0 != NULL)
+					Motherboard_non0(dev);
+			}
+		}
+
+		/* Setup the Winbond or Via PIB */
+		prep_pib_init();
+
+		return;
+	}
+
+	pci_for_each_dev(dev) {
+		/*
+		 * Use our old hard-coded kludge to figure out what
+		 * irq this device uses.  This is necessary on things
+		 * without residual data. -- Cort
+		 */
+		unsigned char d = PCI_SLOT(dev->devfn);
+		dev->irq = Motherboard_routes[Motherboard_map[d]];
+
+		for ( i = 0 ; i <= 5 ; i++ ) {
+			/*
+			 * Relocate PCI I/O resources if necessary so the
+			 * standard 256MB BAT covers them.
+			 */
+			if ( (pci_resource_flags(dev, i) & IORESOURCE_IO) &&
+				      (dev->resource[i].start > 0x10000000))  {
+				printk("Relocating PCI address %lx -> %lx\n",
+						dev->resource[i].start,
+						(dev->resource[i].start & 
+						 0x00FFFFFF)| 0x01000000);
+				dev->resource[i].start =
+					(dev->resource[i].start & 0x00FFFFFF)
+					| 0x01000000;
+		                pci_write_config_dword(dev,
+						PCI_BASE_ADDRESS_0 + (i*0x4),
+						dev->resource[i].start);
+				dev->resource[i].end = 
+					(dev->resource[i].end & 0x00FFFFFF)
+					| 0x01000000;
+		        }
+		}
+#if 0
+		/*
+		 * If we have residual data and if it knows about this
+		 * device ask it what the irq is.
+		 *  -- Cort
+		 */
+		ppcd = residual_find_device_id( ~0L, dev->device,
+		                                -1,-1,-1, 0);
+#endif
+	}
+}
+
+static void __init
+prep_pcibios_after_init(void)
+{
+	struct pci_dev *dev;
+	
+	/* If there is a WD 90C, reset the IO BAR to 0x0 (it started that 
+	 * way, but the PCI layer relocated it because it thought 0x0 was
+	 * invalid for a BAR).
+	 * If you don't do this, the card's VGA base will be <IO BAR>+0xc0000
+	 * instead of 0xc0000. vgacon.c (for example) is completely unaware of
+	 * this little quirk.
+	 */
+	dev = pci_find_device(PCI_VENDOR_ID_WD, PCI_DEVICE_ID_WD_90C, NULL);
+	if (dev) {
+		dev->resource[1].end -= dev->resource[1].start;
+		dev->resource[1].start = 0;
+		/* tell the hardware */
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0x0);
+	}
+}
+
+static void __init
+prep_init_resource(struct resource *res, unsigned long start,
+		   unsigned long end, int flags)
+{
+	res->flags = flags;
+	res->start = start;
+	res->end = end;
+	res->name = "PCI host bridge";
+	res->parent = NULL;
+	res->sibling = NULL;
+	res->child = NULL;
+}
+
+void __init
+prep_find_bridges(void)
+{
+	struct pci_controller* hose;
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
+	hose->io_base_phys = PREP_ISA_IO_BASE;
+	hose->io_base_virt = (void *)0x80000000; /* see prep_map_io() */
+	prep_init_resource(&hose->io_resource, 0, 0x0fffffff, IORESOURCE_IO);
+	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
+			   IORESOURCE_MEM);
+	
+	printk("PReP architecture\n");
+	{
+#ifdef CONFIG_PREP_RESIDUAL	  
+		PPC_DEVICE *hostbridge;
+
+		hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
+			BridgeController, PCIBridge, -1, 0);
+		if (hostbridge &&
+			hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
+			PnP_TAG_PACKET * pkt;
+			pkt = PnP_find_large_vendor_packet(
+				res->DevicePnPHeap+hostbridge->AllocatedOffset,
+				3, 0);
+			if(pkt) {
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+				setup_indirect_pci(hose, 
+					ld_le32((unsigned *) (p.PPCData)),
+					ld_le32((unsigned *) (p.PPCData+8)));
+			} else
+				setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
+		} else
+#endif /* CONFIG_PREP_RESIDUAL */
+			hose->ops = &prep_pci_ops;
+	}
+
+	ppc_md.pcibios_fixup = prep_pcibios_fixup;
+	ppc_md.pcibios_after_init = prep_pcibios_after_init;
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/prep_setup.c linux-2.4.20-pre2/arch/ppc/platforms/prep_setup.c
--- linux-2.4.20-pre1/arch/ppc/platforms/prep_setup.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/prep_setup.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,904 @@
+/*
+ * BK Id: SCCS/s.prep_setup.c 1.52 04/05/02 10:17:22 trini
+ */
+/*
+ *  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)
+ *
+ * Support for PReP (Motorola MTX/MVME)
+ * by Troy Benjegerdes (hozer@drgw.net)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/module.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/timex.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+
+#include <asm/sections.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/mk48t59.h>
+#include <asm/prep_nvram.h>
+#include <asm/raven.h>
+#include <asm/keyboard.h>
+#include <asm/vga.h>
+#include <asm/time.h>
+#include <asm/i8259.h>
+#include <asm/open_pic.h>
+
+#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
+#include <../drivers/sound/sound_config.h>
+#include <../drivers/sound/dev_table.h>
+#endif
+
+unsigned char ucSystemType;
+unsigned char ucBoardRev;
+unsigned char ucBoardRevMaj, ucBoardRevMin;
+
+extern unsigned long mc146818_get_rtc_time(void);
+extern int mc146818_set_rtc_time(unsigned long nowtime);
+extern unsigned long mk48t59_get_rtc_time(void);
+extern int mk48t59_set_rtc_time(unsigned long nowtime);
+
+extern unsigned char prep_nvram_read_val(int addr);
+extern void prep_nvram_write_val(int addr,
+				 unsigned char val);
+extern unsigned char rs_nvram_read_val(int addr);
+extern void rs_nvram_write_val(int addr,
+				 unsigned char val);
+extern void ibm_prep_init(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[];
+
+extern void prep_find_bridges(void);
+extern char saved_command_line[];
+
+int _prep_type;
+
+#define cached_21	(((char *)(ppc_cached_irq_mask))[3])
+#define cached_A1	(((char *)(ppc_cached_irq_mask))[2])
+
+/* for the mac fs */
+kdev_t boot_dev;
+/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
+long ppc_cs4232_dma, ppc_cs4232_dma2;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_jiffy;
+
+#ifdef CONFIG_SOUND_MODULE
+EXPORT_SYMBOL(ppc_cs4232_dma);
+EXPORT_SYMBOL(ppc_cs4232_dma2);
+#endif
+
+static int __prep
+prep_show_cpuinfo(struct seq_file *m)
+{
+	extern char *Motherboard_map_name;
+	int cachew;
+#ifdef CONFIG_PREP_RESIDUAL
+	int i;
+#endif
+
+	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+	switch ( _prep_type ) {
+	case _PREP_IBM:
+		cachew = inw(0x80c);
+		if (cachew & (1<<6))
+			seq_printf(m, "Upgrade CPU\n");
+		seq_printf(m, "L2\t\t: ");
+		if (cachew & (1<<7)) {
+			seq_printf(m, "not present\n");
+			goto no_l2;
+		}
+		seq_printf(m, "%sKb,", (cachew & (1 << 10))? "512" : "256");
+		seq_printf(m, "%ssync\n", (cachew & (1 << 15))? "" : "a");
+		break;
+	case _PREP_Motorola:
+		cachew = *((unsigned char *)CACHECRBA);
+		seq_printf(m, "L2\t\t: ");
+		switch (cachew & L2CACHE_MASK) {
+		case L2CACHE_512KB:
+			seq_printf(m, "512Kb");
+			break;
+		case L2CACHE_256KB:
+			seq_printf(m, "256Kb");
+			break;
+		case L2CACHE_1MB:
+			seq_printf(m, "1MB");
+			break;
+		case L2CACHE_NONE:
+			seq_printf(m, "none\n");
+			goto no_l2;
+			break;
+		default:
+			seq_printf(m, "%x\n", cachew);
+		}
+		
+		seq_printf(m, ", parity %s",
+			   (cachew & L2CACHE_PARITY)? "enabled" : "disabled");
+
+		seq_printf(m, " SRAM:");
+		
+		switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
+		case 1: seq_printf(m, "synchronous,parity,flow-through\n");
+			break;
+		case 2: seq_printf(m, "asynchronous,no parity\n");
+			break;
+		case 3: seq_printf(m, "asynchronous,parity\n");
+			break;
+		default:seq_printf(m, "synchronous,pipelined,no parity\n");
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+no_l2:
+#ifdef CONFIG_PREP_RESIDUAL
+	if (res->ResidualLength != 0) {
+		/* print info about SIMMs */
+		seq_printf(m, "simms\t\t: ");
+		for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
+			if (res->Memories[i].SIMMSize != 0)
+				seq_printf(m, "%d:%ldM ", i,
+					(res->Memories[i].SIMMSize > 1024) ? 
+					res->Memories[i].SIMMSize>>20 : 
+					res->Memories[i].SIMMSize);
+		}
+		seq_printf(m, "\n");
+	}
+#endif
+
+	return 0;
+}
+
+static int __prep
+prep_show_percpuinfo(struct seq_file *m, int i)
+{
+	/* PREP's without residual data will give incorrect values here */
+	seq_printf(m, "clock\t\t: ");
+#ifdef CONFIG_PREP_RESIDUAL	
+	if (res->ResidualLength)
+		seq_printf(m, "%ldMHz\n",
+			   (res->VitalProductData.ProcessorHz > 1024) ?
+			   res->VitalProductData.ProcessorHz / 1000000 :
+			   res->VitalProductData.ProcessorHz);
+	else
+#endif /* CONFIG_PREP_RESIDUAL */
+		seq_printf(m, "???\n");
+
+	return 0;
+}
+
+static void __init
+prep_setup_arch(void)
+{
+	unsigned char reg;
+#if 0 /* unused?? */
+	unsigned char ucMothMemType;
+	unsigned char ucEquipPres1;
+#endif
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000;
+	
+	/* Lookup PCI host bridges */
+	prep_find_bridges();
+	
+	/* Set up floppy in PS/2 mode */
+	outb(0x09, SIO_CONFIG_RA);
+	reg = inb(SIO_CONFIG_RD);
+	reg = (reg & 0x3F) | 0x40;
+	outb(reg, SIO_CONFIG_RD);
+	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
+
+	/* we should determine this according to what we find! -- Cort */
+	switch ( _prep_type )
+	{
+	case _PREP_IBM:
+		/* Enable L2.  Assume we don't need to flush -- Cort*/
+		*(unsigned char *)(0x8000081c) |= 3;
+		ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+		break;
+	case _PREP_Motorola:
+		/* Enable L2.  Assume we don't need to flush -- Cort*/
+		*(unsigned char *)(0x8000081c) |= 3;
+#ifdef CONFIG_BLK_DEV_INITRD
+		if (initrd_start)
+			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */
+		else
+#endif
+#ifdef CONFIG_ROOT_NFS
+			ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs */
+#else
+			ROOT_DEV = to_kdev_t(0x0802); /* /dev/sda2 */
+#endif
+		break;
+	}
+
+	/* Read in NVRAM data */ 
+	init_prep_nvram();
+
+	/* if no bootargs, look in NVRAM */
+	if ( cmd_line[0] == '\0' ) {
+		char *bootargs;
+		 bootargs = prep_nvram_get_var("bootargs");
+		 if (bootargs != NULL) {
+			 strcpy(cmd_line, bootargs);
+			 /* again.. */
+			 strcpy(saved_command_line, cmd_line);
+		}
+	}
+
+#ifdef CONFIG_SOUND_CS4232
+	/*
+	 * setup proper values for the cs4232 driver so we don't have
+	 * to recompile for the motorola or ibm workstations sound systems.
+	 * This is a really nasty hack, but unless we change the driver
+	 * it's the only way to support both addrs from one binary.
+	 * -- Cort
+	 */
+	if ( _machine == _MACH_prep )
+	{
+		extern struct card_info snd_installed_cards[];
+		struct card_info *snd_ptr;
+
+		for ( snd_ptr = snd_installed_cards; 
+			snd_ptr < &snd_installed_cards[num_sound_cards];
+			snd_ptr++ )
+		{
+			if ( snd_ptr->card_type == SNDCARD_CS4232 )
+			{
+				if ( _prep_type == _PREP_Motorola )
+				{
+					snd_ptr->config.io_base = 0x830;
+					snd_ptr->config.irq = 10;
+					snd_ptr->config.dma = ppc_cs4232_dma = 6;
+					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
+				}
+				if ( _prep_type == _PREP_IBM )
+				{
+					snd_ptr->config.io_base = 0x530;
+					snd_ptr->config.irq = 5;
+					snd_ptr->config.dma = ppc_cs4232_dma = 1;
+					/* this is wrong - but leave it for now */
+					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
+				}
+			}
+		}
+	}
+#endif /* CONFIG_SOUND_CS4232 */	
+
+	/*print_residual_device_info();*/
+
+	switch (_prep_type) {
+	case _PREP_Motorola:
+		raven_init();
+		break;
+	case _PREP_IBM:
+		ibm_prep_init();
+		break;
+	}
+
+#ifdef CONFIG_VGA_CONSOLE
+	/* remap the VGA memory */
+	vgacon_remap_base = 0xf0000000;
+	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
+	conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+#endif
+}
+
+/*
+ * Determine the decrementer frequency from the residual data
+ * This allows for a faster boot as we do not need to calibrate the
+ * decrementer against another clock. This is important for embedded systems.
+ */
+static int __init
+prep_res_calibrate_decr(void)
+{
+#ifdef CONFIG_PREP_RESIDUAL
+	unsigned long freq, divisor = 4;
+
+	if ( res->VitalProductData.ProcessorBusHz ) {
+		freq = res->VitalProductData.ProcessorBusHz;
+		printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+				(freq/divisor)/1000000,
+				(freq/divisor)%1000000);
+		tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+		tb_ticks_per_jiffy = freq / HZ / divisor;
+		return 0;
+	} else
+#endif	
+		return 1;
+}
+
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems.  On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+/* Done with 3 interrupts: the first one primes the cache and the
+ * 2 following ones measure the interval. The precision of the method
+ * is still doubtful due to the short interval sampled.
+ */
+static volatile int calibrate_steps __initdata = 3;
+static unsigned tbstamp __initdata = 0;
+
+static void __init
+prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *regs)
+{
+	unsigned long t, freq;
+	int step=--calibrate_steps;
+
+	t = get_tbl();
+	if (step > 0) {
+		tbstamp = t;
+	} else {
+		freq = (t - tbstamp)*HZ;
+		printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+			 freq/1000000, freq%1000000);
+		tb_ticks_per_jiffy = freq / HZ;
+		tb_to_us = mulhwu_scale_factor(freq, 1000000);
+	}
+}
+
+static void __init
+prep_calibrate_decr(void)
+{
+	int res;
+
+	/* Try and get this from the residual data. */
+	res = prep_res_calibrate_decr();
+
+	/* If we didn't get it from the residual data, try this. */
+	if ( res ) {
+		unsigned long flags;
+
+		save_flags(flags);
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+		/* set timer to periodic mode */
+		outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+		/* set the clock to ~100 Hz */
+		outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
+		outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
+
+		if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+			panic("Could not allocate timer IRQ!");
+		__sti();
+		/* wait for calibrate */
+		while ( calibrate_steps )
+			;
+		restore_flags(flags);
+		free_irq( 0, NULL);
+	}
+}
+
+static long __init
+mk48t59_init(void) {
+	unsigned char tmp;
+
+	tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+	if (tmp & MK48T59_RTC_CB_STOP) {
+		printk("Warning: RTC was stopped, date will be wrong.\n");
+		ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB, 
+					 tmp & ~MK48T59_RTC_CB_STOP);
+		/* Low frequency crystal oscillators may take a very long
+		 * time to startup and stabilize. For now just ignore the
+		 * the issue, but attempting to calibrate the decrementer
+		 * from the RTC just after this wakeup is likely to be very 
+		 * inaccurate. Firmware should not allow to load
+		 * the OS with the clock stopped anyway...
+		 */
+	}
+	/* Ensure that the clock registers are updated */
+	tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE);
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp);
+	return 0;
+}
+
+/* We use the NVRAM RTC to time a second to calibrate the decrementer,
+ * the RTC registers have just been set up in the right state by the
+ * preceding routine.
+ */
+static void __init
+mk48t59_calibrate_decr(void)
+{
+	unsigned long freq;
+	unsigned long t1;
+	unsigned char save_control;
+	long i;
+	unsigned char sec;
+ 
+		
+	/* Make sure the time is not stopped. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			(save_control & (~MK48T59_RTC_CB_STOP)));
+
+	/* Now make sure the read bit is off so the value will change. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	save_control &= ~MK48T59_RTC_CA_READ;
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+
+	/* Read the seconds value to see when it changes. */
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	/* Actually this is bad for precision, we should have a loop in
+	 * which we only read the seconds counter. nvram_read_val writes
+	 * the address bytes on every call and this takes a lot of time.
+	 * Perhaps an nvram_wait_change method returning a time
+	 * stamp with a loop count as parameter would be the  solution.
+	 */
+	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
+		t1 = get_tbl();
+		if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+			break;
+		}
+	}
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	for (i = 0 ; i < 1000000 ; i++)	{ /* Should take up 1 second... */
+		freq = get_tbl()-t1;
+		if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec)
+			break;
+	}
+
+	printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+		 freq/1000000, freq%1000000);
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
+
+static void __prep
+prep_restart(char *cmd)
+{
+	unsigned long i = 10000;
+
+	__cli();
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	/* make sure bit 0 (reset) is a 0 */
+	outb( inb(0x92) & ~1L , 0x92 );
+	/* signal a reset to system control port A - soft reset */
+	outb( inb(0x92) | 1 , 0x92 );
+
+	while ( i != 0 ) i++;
+	panic("restart failed\n");
+}
+
+static void __prep
+prep_halt(void)
+{
+	unsigned long flags;
+	__cli();
+	/* set exception prefix high - to the prom */
+	save_flags( flags );
+	restore_flags( flags|MSR_IP );
+
+	/* make sure bit 0 (reset) is a 0 */
+	outb( inb(0x92) & ~1L , 0x92 );
+	/* signal a reset to system control port A - soft reset */
+	outb( inb(0x92) | 1 , 0x92 );
+
+	while ( 1 ) ;
+	/*
+	 * Not reached
+	 */
+}
+
+/*
+ * On IBM PReP's, power management is handled by a Signetics 87c750 behind the
+ * Utah component on the ISA bus. To access the 750 you must write a series of
+ * nibbles to port 0x82a (decoded by the Utah). This is described somewhat in
+ * the IBM Carolina Technical Specification.
+ * -Hollis
+ */
+static void __prep
+utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
+{
+	/*
+	 * byte1: 0 0 0 1 0  d  a5 a4
+	 * byte2: 0 0 0 1 a3 a2 a1 a0
+	 *
+	 * d = the bit's value, enabled or disabled
+	 * (a5 a4 a3) = the byte number, minus 20
+	 * (a2 a1 a0) = the bit number
+	 *
+	 * example: set the 5th bit of byte 21 (21.5)
+	 *     a5 a4 a3 = 001 (byte 1)
+	 *     a2 a1 a0 = 101 (bit 5)
+	 *
+	 *     byte1 = 0001 0100 (0x14)
+	 *     byte2 = 0001 1101 (0x1d)
+	 */
+	unsigned char byte1=0x10, byte2=0x10;
+	const unsigned int pm_reg_1=0x82a; /* ISA address */
+
+	/* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
+	bytenum -= 20;
+
+	byte1 |= (!!value) << 2;		/* set d */
+	byte1 |= (bytenum >> 1) & 0x3;	/* set a5, a4 */
+
+	byte2 |= (bytenum & 0x1) << 3;	/* set a3 */
+	byte2 |= bitnum & 0x7;			/* set a2, a1, a0 */
+
+	outb(byte1, pm_reg_1);		/* first nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+
+	outb(byte2, pm_reg_1);		/* second nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+}
+
+static void __prep
+prep_power_off(void)
+{
+	if ( _prep_type == _PREP_IBM) {
+		/* tested on:
+		 * 		Carolina's: 7248-43P, 6070 (PowerSeries 850)
+		 * should work on:
+		 * 		Carolina: 6050 (PowerSeries 830)
+		 * 		7043-140 (Tiger 1)
+		 */
+		unsigned long flags;
+		__cli();
+		/* set exception prefix high - to the prom */
+		save_flags( flags );
+		restore_flags( flags|MSR_IP );
+
+		utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
+
+		while ( 1 ) ;
+		/* not reached */
+	} else {
+		prep_halt();
+	}
+}
+
+static unsigned int __prep
+prep_irq_cannonicalize(u_int irq)
+{
+	if (irq == 2)
+	{
+		return 9;
+	}
+	else
+	{
+		return irq;
+	}
+}
+
+static int __prep
+prep_get_irq(struct pt_regs *regs)
+{
+	return i8259_irq();
+}		
+
+static void __init
+prep_init_IRQ(void)
+{
+	int i;
+
+	if (OpenPIC_Addr != NULL)
+		openpic_init(1, NUM_8259_INTERRUPTS, 0, -1);
+	for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
+		irq_desc[i].handler = &i8259_pic;
+	i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+static int __prep
+prep_ide_default_irq(ide_ioreg_t base)
+{
+	switch (base) {
+		case 0x1f0: return 13;
+		case 0x170: return 13;
+		case 0x1e8: return 11;
+		case 0x168: return 10;
+		case 0xfff0: return 14;		/* MCP(N)750 ide0 */
+		case 0xffe0: return 15;		/* MCP(N)750 ide1 */
+		default: return 0;
+	}
+}
+
+static ide_ioreg_t __prep
+prep_ide_default_io_base(int index)
+{
+	switch (index) {
+		case 0: return 0x1f0;
+		case 1: return 0x170;
+		case 2: return 0x1e8;
+		case 3: return 0x168;
+		default:
+			return 0;
+	}
+}
+
+static int __prep
+prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+	return check_region(from, extent);
+}
+
+static void __prep
+prep_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+	request_region(from, extent, name);
+}
+
+static void __prep
+prep_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+	release_region(from, extent);
+}
+
+static void __init
+prep_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;
+}
+#endif
+
+#ifdef CONFIG_SMP
+/* PReP (MTX) support */
+static int __init
+smp_prep_probe(void)
+{
+	extern int mot_multi;
+
+	if (mot_multi) {
+		openpic_request_IPIs();
+		smp_hw_index[1] = 1;
+		return 2;
+	}
+
+	return 1;
+}
+
+static void __init
+smp_prep_kick_cpu(int nr)
+{
+	*(unsigned long *)KERNELBASE = nr;
+	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+	printk("CPU1 reset, waiting\n");
+}
+
+static void __init
+smp_prep_setup_cpu(int cpu_nr)
+{
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+}
+
+static struct smp_ops_t prep_smp_ops __prepdata = {
+	smp_openpic_message_pass,
+	smp_prep_probe,
+	smp_prep_kick_cpu,
+	smp_prep_setup_cpu,
+};
+#endif /* CONFIG_SMP */
+
+/*
+ * This finds the amount of physical ram and does necessary
+ * setup for prep.  This is pretty architecture specific so
+ * this will likely stay separate from the pmac.
+ * -- Cort
+ */
+static unsigned long __init
+prep_find_end_of_memory(void)
+{
+	unsigned long total = 0;
+	extern unsigned int boot_mem_size;
+
+#ifdef CONFIG_PREP_RESIDUAL	
+	total = res->TotalMemory;
+#endif	
+
+	if (total == 0 && boot_mem_size != 0)
+		total = boot_mem_size;
+	else if (total == 0) {
+		/*
+		 * I need a way to probe the amount of memory if the residual
+		 * data doesn't contain it. -- Cort
+		 */
+		total = 0x02000000;
+		printk(KERN_INFO "Ramsize from residual data was 0"
+			 " -- defaulting to %ldM\n", total>>20);
+	}
+
+	return (total);
+}
+
+/*
+ * Setup the bat mappings we're going to load that cover
+ * the io areas.  RAM was mapped by mapin_ram().
+ * -- Cort
+ */
+static void __init
+prep_map_io(void)
+{
+	io_block_mapping(0x80000000, PREP_ISA_IO_BASE, 0x10000000, _PAGE_IO);
+	io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO);
+}
+
+static void __init
+prep_init2(void)
+{
+#ifdef CONFIG_NVRAM
+	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
+#endif
+	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
+prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		unsigned long r6, unsigned long r7)
+{
+#ifdef CONFIG_PREP_RESIDUAL	
+	/* make a copy of residual data */
+	if ( r3 ) {
+		memcpy((void *)res,(void *)(r3+KERNELBASE),
+			 sizeof(RESIDUAL));
+	}
+#endif
+
+	isa_io_base = PREP_ISA_IO_BASE;
+	isa_mem_base = PREP_ISA_MEM_BASE;
+	pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	/* figure out what kind of prep workstation we are */
+#ifdef CONFIG_PREP_RESIDUAL	
+	if ( res->ResidualLength != 0 )
+	{
+		if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+			_prep_type = _PREP_IBM;
+		else
+			_prep_type = _PREP_Motorola;
+	}
+	else /* assume motorola if no residual (netboot?) */
+#endif
+	{
+		_prep_type = _PREP_Motorola;
+	}
+
+	ppc_md.setup_arch     = prep_setup_arch;
+	ppc_md.show_percpuinfo = prep_show_percpuinfo;
+	ppc_md.show_cpuinfo   = prep_show_cpuinfo;
+	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
+	ppc_md.init_IRQ       = prep_init_IRQ;
+	/* this gets changed later on if we have an OpenPIC -- Cort */
+	ppc_md.get_irq        = prep_get_irq;
+	ppc_md.init           = prep_init2;
+
+	ppc_md.restart        = prep_restart;
+	ppc_md.power_off      = prep_power_off;
+	ppc_md.halt           = prep_halt;
+
+	ppc_md.nvram_read_val = prep_nvram_read_val;
+	ppc_md.nvram_write_val = prep_nvram_write_val;
+
+	ppc_md.time_init      = NULL;
+	if (_prep_type == _PREP_IBM) {
+		ppc_md.set_rtc_time   = mc146818_set_rtc_time;
+		ppc_md.get_rtc_time   = mc146818_get_rtc_time;
+		ppc_md.calibrate_decr = prep_calibrate_decr;
+	} else {
+		ppc_md.set_rtc_time   = mk48t59_set_rtc_time;
+		ppc_md.get_rtc_time   = mk48t59_get_rtc_time;
+		ppc_md.calibrate_decr = mk48t59_calibrate_decr;
+		ppc_md.time_init      = mk48t59_init;
+	}
+
+	ppc_md.find_end_of_memory = prep_find_end_of_memory;
+	ppc_md.setup_io_mappings = prep_map_io;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+	ppc_ide_md.default_irq = prep_ide_default_irq;
+	ppc_ide_md.default_io_base = prep_ide_default_io_base;
+	ppc_ide_md.ide_check_region = prep_ide_check_region;
+	ppc_ide_md.ide_request_region = prep_ide_request_region;
+	ppc_ide_md.ide_release_region = prep_ide_release_region;
+	ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
+#endif
+
+#ifdef CONFIG_VT
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x54;
+#endif
+#endif
+
+#ifdef CONFIG_SMP
+	ppc_md.smp_ops		 = &prep_smp_ops;
+#endif /* CONFIG_SMP */
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/prep_time.c linux-2.4.20-pre2/arch/ppc/platforms/prep_time.c
--- linux-2.4.20-pre1/arch/ppc/platforms/prep_time.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/prep_time.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,228 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/platforms/prep_time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * Adapted for PowerPC (PReP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu).
+ * Copied and modified from arch/i386/kernel/time.c
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+
+#include <asm/sections.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+#include <asm/mk48t59.h>
+
+#include <asm/time.h>
+
+extern spinlock_t rtc_lock;
+
+/*
+ * The motorola uses the m48t18 rtc (includes DS1643) whose registers
+ * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
+ * rtc (ds1386) which has regs at addr 0-d).  The intel gets
+ * past this because the bios emulates the mc146818.
+ *
+ * Why in the world did they have to use different clocks?
+ *
+ * Right now things are hacked to check which machine we're on then
+ * use the appropriate macro.  This is very very ugly and I should
+ * probably have a function that checks which machine we're on then
+ * does things correctly transparently or a function pointer which
+ * is setup at boot time to use the correct addresses.
+ * -- Cort
+ */
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+__prep
+int mc146818_set_rtc_time(unsigned long nowtime)
+{
+	unsigned char save_control, save_freq_select;
+	struct rtc_time tm;
+
+	spin_lock(&rtc_lock);
+	to_tm(nowtime, &tm);
+
+	/* tell the clock it's being set */
+	save_control = CMOS_READ(RTC_CONTROL);
+
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+	/* stop and reset prescaler */
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(tm.tm_sec);
+		BIN_TO_BCD(tm.tm_min);
+		BIN_TO_BCD(tm.tm_hour);
+		BIN_TO_BCD(tm.tm_mon);
+		BIN_TO_BCD(tm.tm_mday);
+		BIN_TO_BCD(tm.tm_year);
+	}
+	CMOS_WRITE(tm.tm_sec,  RTC_SECONDS);
+	CMOS_WRITE(tm.tm_min,  RTC_MINUTES);
+	CMOS_WRITE(tm.tm_hour, RTC_HOURS);
+	CMOS_WRITE(tm.tm_mon,  RTC_MONTH);
+	CMOS_WRITE(tm.tm_mday, RTC_DAY_OF_MONTH);
+	CMOS_WRITE(tm.tm_year, RTC_YEAR);
+
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	CMOS_WRITE(save_control,     RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+	spin_unlock(&rtc_lock);
+
+	return 0;
+}
+
+__prep
+unsigned long mc146818_get_rtc_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	int uip, i;
+
+	/* The Linux interpretation of the CMOS clock register contents:
+	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+	 * RTC registers show the second which has precisely just started.
+	 * Let's hope other operating systems interpret the RTC the same way.
+	 */
+
+	/* Since the UIP flag is set for about 2.2 ms and the clock
+	 * is typically written with a precision of 1 jiffy, trying
+	 * to obtain a precision better than a few milliseconds is 
+	 * an illusion. Only consistency is interesting, this also
+	 * allows to use the routine for /dev/rtc without a potential
+	 * 1 second kernel busy loop triggered by any reader of /dev/rtc. 
+	 */
+
+	for ( i = 0; i<1000000; i++) {
+		uip = CMOS_READ(RTC_FREQ_SELECT);
+		sec = CMOS_READ(RTC_SECONDS);
+		min = CMOS_READ(RTC_MINUTES);
+		hour = CMOS_READ(RTC_HOURS);
+		day = CMOS_READ(RTC_DAY_OF_MONTH);
+		mon = CMOS_READ(RTC_MONTH);
+		year = CMOS_READ(RTC_YEAR);
+		uip |= CMOS_READ(RTC_FREQ_SELECT);
+		if ((uip & RTC_UIP)==0) break;
+	}
+
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+	    || RTC_ALWAYS_BCD)
+	{
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+	if ((year += 1900) < 1970)
+		year += 100;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+__prep
+int mk48t59_set_rtc_time(unsigned long nowtime)
+{
+	unsigned char save_control;
+	struct rtc_time tm;
+
+	spin_lock(&rtc_lock);
+	to_tm(nowtime, &tm);
+
+	/* tell the clock it's being written */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_WRITE));
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+	BIN_TO_BCD(tm.tm_sec);
+	BIN_TO_BCD(tm.tm_min);
+	BIN_TO_BCD(tm.tm_hour);
+	BIN_TO_BCD(tm.tm_mon);
+	BIN_TO_BCD(tm.tm_mday);
+	BIN_TO_BCD(tm.tm_year);
+
+	ppc_md.nvram_write_val(MK48T59_RTC_SECONDS,      tm.tm_sec);
+	ppc_md.nvram_write_val(MK48T59_RTC_MINUTES,      tm.tm_min);
+	ppc_md.nvram_write_val(MK48T59_RTC_HOURS,        tm.tm_hour);
+	ppc_md.nvram_write_val(MK48T59_RTC_MONTH,        tm.tm_mon);
+	ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday);
+	ppc_md.nvram_write_val(MK48T59_RTC_YEAR,         tm.tm_year);
+
+	/* Turn off the write bit. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+	spin_unlock(&rtc_lock);
+
+	return 0;
+}
+
+__prep
+unsigned long mk48t59_get_rtc_time(void)
+{
+	unsigned char save_control;
+	unsigned int year, mon, day, hour, min, sec;
+
+	/* Simple: freeze the clock, read it and allow updates again */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	save_control &= ~MK48T59_RTC_CA_READ;
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	/* Set the register to read the value. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_READ));
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES);
+	hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS);
+	day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH);
+	mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH);
+	year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR);
+
+	/* Let the time values change again. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+
+	year = year + 1900;
+	if (year < 1970) {
+		year += 100;
+	}
+
+	return mktime(year, mon, day, hour, min, sec);
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/proc_rtas.c linux-2.4.20-pre2/arch/ppc/platforms/proc_rtas.c
--- linux-2.4.20-pre1/arch/ppc/platforms/proc_rtas.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/proc_rtas.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,787 @@
+/*
+ * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort
+ */
+/*
+ *   arch/ppc/kernel/proc_rtas.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/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;
+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 = find_devices("rtas");
+	if ((rtas == 0) || (_machine != _MACH_chrp)) {
+		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 = call_rtas("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 = call_rtas("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 = call_rtas("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[MAX_LINELENGTH*MAX_SENSORS]; /* May not be enough */
+
+	if (count < 0)
+		return -EINVAL;
+
+	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 =	call_rtas("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;
+		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;
+	return n;
+}
+
+/* ****************************************************************** */
+
+int ppc_rtas_find_all_sensors (void)
+{
+	unsigned long *utmp;
+	int len, i, j;
+
+	utmp = (unsigned long *) get_property(rtas, "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, 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 = call_rtas("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 = call_rtas("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.20-pre1/arch/ppc/platforms/residual.c linux-2.4.20-pre2/arch/ppc/platforms/residual.c
--- linux-2.4.20-pre1/arch/ppc/platforms/residual.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/residual.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,913 @@
+/*
+ * BK Id: SCCS/s.residual.c 1.15 02/05/02 18:08:35 trini
+ */
+/*
+ * Code to deal with the PReP residual data.
+ *
+ * Written by: Cort Dougan (cort@cs.nmt.edu)
+ * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es)
+ *
+ *  This file is based on the following documentation:
+ *
+ *	IBM Power Personal Systems Architecture
+ *	Residual Data
+ * 	Document Number: PPS-AR-FW0001
+ *
+ *  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/string.h>
+#include <asm/residual.h>
+#include <asm/pnp.h>
+#include <asm/byteorder.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/pci.h>
+#include <linux/ide.h>
+
+#include <asm/sections.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+
+
+unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,};
+RESIDUAL *res = (RESIDUAL *)&__res;
+
+char * PnP_BASE_TYPES[] __initdata = {
+  "Reserved",
+  "MassStorageDevice",
+  "NetworkInterfaceController",
+  "DisplayController",
+  "MultimediaController",
+  "MemoryController",
+  "BridgeController",
+  "CommunicationsDevice",
+  "SystemPeripheral",
+  "InputDevice",
+  "ServiceProcessor"
+  };
+
+/* Device Sub Type Codes */
+
+unsigned char * PnP_SUB_TYPES[] __initdata = {
+  "\001\000SCSIController",
+  "\001\001IDEController",
+  "\001\002FloppyController",
+  "\001\003IPIController",
+  "\001\200OtherMassStorageController",
+  "\002\000EthernetController",
+  "\002\001TokenRingController",
+  "\002\002FDDIController",
+  "\002\0x80OtherNetworkController",
+  "\003\000VGAController",
+  "\003\001SVGAController",
+  "\003\002XGAController",
+  "\003\200OtherDisplayController",
+  "\004\000VideoController",
+  "\004\001AudioController",
+  "\004\200OtherMultimediaController",
+  "\005\000RAM",
+  "\005\001FLASH",
+  "\005\200OtherMemoryDevice",
+  "\006\000HostProcessorBridge",
+  "\006\001ISABridge",
+  "\006\002EISABridge",
+  "\006\003MicroChannelBridge",
+  "\006\004PCIBridge",
+  "\006\005PCMCIABridge",
+  "\006\006VMEBridge",
+  "\006\200OtherBridgeDevice",
+  "\007\000RS232Device",
+  "\007\001ATCompatibleParallelPort",
+  "\007\200OtherCommunicationsDevice",
+  "\010\000ProgrammableInterruptController",
+  "\010\001DMAController",
+  "\010\002SystemTimer",
+  "\010\003RealTimeClock",
+  "\010\004L2Cache",
+  "\010\005NVRAM",
+  "\010\006PowerManagement",
+  "\010\007CMOS",
+  "\010\010OperatorPanel",
+  "\010\011ServiceProcessorClass1",
+  "\010\012ServiceProcessorClass2",
+  "\010\013ServiceProcessorClass3",
+  "\010\014GraphicAssist",
+  "\010\017SystemPlanar",
+  "\010\200OtherSystemPeripheral",
+  "\011\000KeyboardController",
+  "\011\001Digitizer",
+  "\011\002MouseController",
+  "\011\003TabletController",
+  "\011\0x80OtherInputController",
+  "\012\000GeneralMemoryController",
+  NULL
+};
+
+/* Device Interface Type Codes */
+
+unsigned char * PnP_INTERFACES[] __initdata = {
+  "\000\000\000General",
+  "\001\000\000GeneralSCSI",
+  "\001\001\000GeneralIDE",
+  "\001\001\001ATACompatible",
+
+  "\001\002\000GeneralFloppy",
+  "\001\002\001Compatible765",
+  "\001\002\002NS398_Floppy",         /* NS Super I/O wired to use index
+                                         register at port 398 and data
+                                         register at port 399               */
+  "\001\002\003NS26E_Floppy",         /* Ports 26E and 26F                  */
+  "\001\002\004NS15C_Floppy",         /* Ports 15C and 15D                  */
+  "\001\002\005NS2E_Floppy",          /* Ports 2E and 2F                    */
+  "\001\002\006CHRP_Floppy",          /* CHRP Floppy in PR*P system         */
+
+  "\001\003\000GeneralIPI",
+  
+  "\002\000\000GeneralEther",
+  "\002\001\000GeneralToken",
+  "\002\002\000GeneralFDDI",
+  
+  "\003\000\000GeneralVGA",
+  "\003\001\000GeneralSVGA",
+  "\003\002\000GeneralXGA",
+  
+  "\004\000\000GeneralVideo",
+  "\004\001\000GeneralAudio",
+  "\004\001\001CS4232Audio",            /* CS 4232 Plug 'n Play Configured    */
+
+  "\005\000\000GeneralRAM",
+  /* This one is obviously wrong ! */
+  "\005\000\000PCIMemoryController",    /* PCI Config Method                  */
+  "\005\000\001RS6KMemoryController",   /* RS6K Config Method                 */
+  "\005\001\000GeneralFLASH",
+  
+  "\006\000\000GeneralHostBridge",
+  "\006\001\000GeneralISABridge",
+  "\006\002\000GeneralEISABridge",
+  "\006\003\000GeneralMCABridge",
+  /* GeneralPCIBridge = 0, */
+  "\006\004\000PCIBridgeDirect",
+  "\006\004\001PCIBridgeIndirect",
+  "\006\004\002PCIBridgeRS6K",
+  "\006\005\000GeneralPCMCIABridge",
+  "\006\006\000GeneralVMEBridge",
+  
+  "\007\000\000GeneralRS232",
+  "\007\000\001COMx",
+  "\007\000\002Compatible16450",
+  "\007\000\003Compatible16550",
+  "\007\000\004NS398SerPort",         /* NS Super I/O wired to use index
+                                         register at port 398 and data
+                                         register at port 399               */
+  "\007\000\005NS26ESerPort",         /* Ports 26E and 26F                  */
+  "\007\000\006NS15CSerPort",         /* Ports 15C and 15D                  */
+  "\007\000\007NS2ESerPort",          /* Ports 2E and 2F                    */
+
+  "\007\001\000GeneralParPort",
+  "\007\001\001LPTx",
+  "\007\001\002NS398ParPort",         /* NS Super I/O wired to use index
+                                         register at port 398 and data
+                                         register at port 399               */
+  "\007\001\003NS26EParPort",         /* Ports 26E and 26F                  */
+  "\007\001\004NS15CParPort",         /* Ports 15C and 15D                  */
+  "\007\001\005NS2EParPort",          /* Ports 2E and 2F                    */
+  
+  "\010\000\000GeneralPIC",
+  "\010\000\001ISA_PIC",
+  "\010\000\002EISA_PIC",
+  "\010\000\003MPIC",
+  "\010\000\004RS6K_PIC",
+
+  "\010\001\000GeneralDMA",
+  "\010\001\001ISA_DMA",
+  "\010\001\002EISA_DMA",
+
+  "\010\002\000GeneralTimer",
+  "\010\002\001ISA_Timer",
+  "\010\002\002EISA_Timer",
+  "\010\003\000GeneralRTC",
+  "\010\003\001ISA_RTC",
+  
+  "\010\004\001StoreThruOnly",
+  "\010\004\002StoreInEnabled",
+  "\010\004\003RS6KL2Cache",
+
+  "\010\005\000IndirectNVRAM",        /* Indirectly addressed               */
+  "\010\005\001DirectNVRAM",          /* Memory Mapped                      */
+  "\010\005\002IndirectNVRAM24",      /* Indirectly addressed - 24 bit      */
+
+  "\010\006\000GeneralPowerManagement",
+  "\010\006\001EPOWPowerManagement",
+  "\010\006\002PowerControl",         // d1378
+  
+  "\010\007\000GeneralCMOS",
+
+  "\010\010\000GeneralOPPanel",
+  "\010\010\001HarddiskLight",
+  "\010\010\002CDROMLight",
+  "\010\010\003PowerLight",
+  "\010\010\004KeyLock",
+  "\010\010\005ANDisplay",            /* AlphaNumeric Display               */
+  "\010\010\006SystemStatusLED",      /* 3 digit 7 segment LED              */
+  "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system           */
+
+  "\010\011\000GeneralServiceProcessor",
+  "\010\012\000GeneralServiceProcessor",
+  "\010\013\000GeneralServiceProcessor",
+  
+  "\010\014\001TransferData",
+  "\010\014\002IGMC32",
+  "\010\014\003IGMC64",
+  
+  "\010\017\000GeneralSystemPlanar",   /* 10/5/95                            */
+  NULL
+  };
+
+static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, 
+					     unsigned char SubType) {
+	unsigned char ** s=PnP_SUB_TYPES;
+	while (*s && !((*s)[0]==BaseType 
+		       && (*s)[1]==SubType)) s++;
+	if (*s) return *s+2;
+	else return("Unknown !");
+};
+
+static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, 
+					      unsigned char SubType,
+					      unsigned char Interface) {
+	unsigned char ** s=PnP_INTERFACES;
+	while (*s && !((*s)[0]==BaseType 
+		       && (*s)[1]==SubType 
+		       && (*s)[2]==Interface)) s++;
+	if (*s) return *s+3;
+	else return NULL;
+};
+
+static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) {
+	int i, c;
+	char decomp[4];
+#define p pkt->S14_Pack.S14_Data.S14_PPCPack
+	switch(p.Type) {
+	case 1:
+	  /* Decompress first 3 chars */
+	  c = *(unsigned short *)p.PPCData;
+	  decomp[0]='A'-1+((c>>10)&0x1F);
+	  decomp[1]='A'-1+((c>>5)&0x1F);
+	  decomp[2]='A'-1+(c&0x1F);
+	  decomp[3]=0;
+	  printk("    Chip identification: %s%4.4X\n",
+		 decomp, ld_le16((unsigned short *)(p.PPCData+2)));
+	  break;
+	default:
+	  printk("    Small vendor item type 0x%2.2x, data (hex): ",
+		 p.Type);
+	  for(i=0; i<size-2; i++) printk("%2.2x ", p.PPCData[i]);
+	  printk("\n");
+	  break;
+	}
+#undef p
+}
+
+static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) {
+	static const unsigned char * intlevel[] = {"high", "low"};
+	static const unsigned char * intsense[] = {"edge", "level"};
+
+	switch (tag_small_item_name(pkt->S1_Pack.Tag)) {
+	case PnPVersion:
+	  printk("    PnPversion 0x%x.%x\n", 
+		 pkt->S1_Pack.Version[0], /* How to interpret version ? */
+		 pkt->S1_Pack.Version[1]);
+	  break;
+//	case Logicaldevice:
+	  break;
+//	case CompatibleDevice:
+	  break;
+	case IRQFormat:
+#define p pkt->S4_Pack
+	  printk("    IRQ Mask 0x%4.4x, %s %s sensitive\n", 
+		 ld_le16((unsigned short *)p.IRQMask),
+		 intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0],
+		 intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]);
+#undef p
+	  break;
+	case DMAFormat:
+#define p pkt->S5_Pack
+	  printk("    DMA channel mask 0x%2.2x, info 0x%2.2x\n",
+		 p.DMAMask, p.DMAInfo);
+#undef p
+	  break;
+	case StartDepFunc:
+	  printk("Start dependent function:\n");
+	  break;
+	case EndDepFunc:
+	  printk("End dependent function\n");
+	  break;
+	case IOPort:
+#define p pkt->S8_Pack
+	  printk("    Variable (%d decoded bits) I/O port\n"
+		 "      from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n",
+		 p.IOInfo&ISAAddr16bit?16:10,
+		 ld_le16((unsigned short *)p.RangeMin),
+ 		 ld_le16((unsigned short *)p.RangeMax),
+		 p.IOAlign, p.IONum); 
+#undef p
+	  break;
+	case FixedIOPort:
+#define p pkt->S9_Pack
+	  printk("    Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n",
+		 (p.Range[1]<<8)|p.Range[0],
+		 ((p.Range[1]<<8)|p.Range[0])+p.IONum-1);
+#undef p		 
+	  break;
+	case Res1:
+	case Res2:
+	case Res3:
+	  printk("    Undefined packet type %d!\n", 
+		 tag_small_item_name(pkt->S1_Pack.Tag));
+	  break;
+	case SmallVendorItem:
+	  printsmallvendor(pkt,size);
+	  break;
+	default:
+	  printk("    Type 0x2.2x%d, size=%d\n", 
+		 pkt->S1_Pack.Tag, size);    
+	  break;
+	}
+}
+
+static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) {
+	static const unsigned char * addrtype[] = {"I/O", "Memory", "System"};
+	static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"};
+	static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"};
+	static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"};
+	static const unsigned char * L2type[] = {"WriteThru", "CopyBack"};
+	static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"};
+
+	int i;
+	char tmpstr[30], *t;
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+	switch(p.Type) {
+	case 2:
+	  printk("    %d K %s %s L2 cache, %d/%d bytes line/sector size\n",
+		 ld_le32((unsigned int *)p.PPCData),
+		 L2type[p.PPCData[10]-1],
+		 L2assoc[p.PPCData[4]-1],
+		 ld_le16((unsigned short *)p.PPCData+3),
+		 ld_le16((unsigned short *)p.PPCData+4));
+	  break;
+	case 3:
+	  printk("    PCI Bridge parameters\n"
+		 "      ConfigBaseAddress %0x\n"
+		 "      ConfigBaseData %0x\n"
+		 "      Bus number %d\n",
+		 ld_le32((unsigned int *)p.PPCData),
+		 ld_le32((unsigned int *)(p.PPCData+8)),
+		 p.PPCData[16]);
+	  for(i=20; i<size-4; i+=12) {
+	  	int j, first;
+	  	if(p.PPCData[i]) printk("      PCI Slot %d", p.PPCData[i]);
+		else printk ("      Integrated PCI device");
+		for(j=0, first=1, t=tmpstr; j<4; j++) {
+			int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
+			if(line!=0xffff){
+			        if(first) first=0; else *t++='/';
+				*t++='A'+j;
+			}
+		}
+		*t='\0';
+		printk(" DevFunc 0x%x interrupt line(s) %s routed to",
+		       p.PPCData[i+1],tmpstr);
+		sprintf(tmpstr,
+			inttype[p.PPCData[i+2]-1],
+			p.PPCData[i+3]);
+		printk(" %s line(s) ",
+		       tmpstr);
+		for(j=0, first=1, t=tmpstr; j<4; j++) {
+			int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
+			if(line!=0xffff){
+				if(first) first=0; else *t++='/';
+				t+=sprintf(t,"%d(%c)",
+					   line&0x7fff,
+					   line&0x8000?'E':'L');
+			}
+		}
+		printk("%s\n",tmpstr);
+	  }
+	  break;
+	case 5:
+	  printk("    Bridge address translation, %s decoding:\n"
+		 "      Processor  Bus        Size       Conversion Translation\n"
+		 "      0x%8.8x 0x%8.8x 0x%8.8x %s %s\n",
+		 p.PPCData[0]&1 ? "positive" : "subtractive",
+		 ld_le32((unsigned int *)p.PPCData+1),
+		 ld_le32((unsigned int *)p.PPCData+3),
+		 ld_le32((unsigned int *)p.PPCData+5),
+		 convtype[p.PPCData[2]-1],
+		 transtype[p.PPCData[1]-1]);
+	  break;
+	case 6:
+	  printk("    Bus speed %d Hz, %d slot(s)\n",
+		 ld_le32((unsigned int *)p.PPCData),
+		 p.PPCData[4]);
+	  break;
+	case 7:
+	  printk("    SCSI buses: %d, id(s):", p.PPCData[0]);
+	  for(i=1; i<=p.PPCData[0]; i++) 
+	    printk(" %d%c", p.PPCData[i], i==p.PPCData[0] ? '\n' : ',');
+	  break;
+	case 9:
+	  printk("    %s address (%d bits), at 0x%x size 0x%x bytes\n",
+		 addrtype[p.PPCData[0]-1],
+		 p.PPCData[1],
+		 ld_le32((unsigned int *)(p.PPCData+4)),
+		 ld_le32((unsigned int *)(p.PPCData+12)));
+	  break;
+	case 10:
+	  sprintf(tmpstr,
+		  inttype[p.PPCData[0]-1],
+		  p.PPCData[1]);
+
+	  printk("    ISA interrupts routed to %s\n"
+		 "      lines", 
+		 tmpstr);
+	  for(i=0; i<16; i++) {
+	  	int line=ld_le16((unsigned short *)p.PPCData+i+1);
+		if (line!=0xffff) printk(" %d(IRQ%d)", line, i); 
+	  }
+	  printk("\n");
+	  break;
+	default:
+	  printk("    Large vendor item type 0x%2.2x\n      Data (hex):",
+		 p.Type);
+	  for(i=0; i<size-4; i++) printk(" %2.2x", p.PPCData[i]);
+	  printk("\n");
+#undef p
+	}
+}
+
+static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) {
+	switch (tag_large_item_name(pkt->S1_Pack.Tag)) {
+	case LargeVendorItem:
+	  printlargevendor(pkt, size);
+	  break;
+	default:
+	  printk("    Type 0x2.2x%d, size=%d\n", 
+		 pkt->S1_Pack.Tag, size);    
+	  break;
+	}
+}
+static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) {
+	if (pkt->S1_Pack.Tag== END_TAG) {
+		printk("  No packets describing %s resources.\n", cat);
+		return;
+	}
+	printk(  "  Packets describing %s resources:\n",cat);
+	do {
+		int size;
+		if (tag_type(pkt->S1_Pack.Tag)) {
+		  	size= 3 +
+			  pkt->L1_Pack.Count0 + 
+			  pkt->L1_Pack.Count1*256;
+			printlargepacket(pkt, size);
+		} else {
+			size=tag_small_count(pkt->S1_Pack.Tag)+1;
+			printsmallpacket(pkt, size);
+		}
+		(unsigned char *) pkt+=size;
+	} while (pkt->S1_Pack.Tag != END_TAG);
+}
+
+void __init print_residual_device_info(void)
+{
+	int i;
+	PPC_DEVICE *dev;
+#define did dev->DeviceId
+	
+	/* make sure we have residual data first */
+	if ( res->ResidualLength == 0 )
+		return;
+	
+	printk("Residual: %ld devices\n", res->ActualNumDevices);
+	for ( i = 0;
+	      i < res->ActualNumDevices ;
+	      i++)
+	{
+	  	char decomp[4], sn[20];
+		const char * s;
+		dev = &res->Devices[i];
+		s = PnP_INTERFACE_STR(did.BaseType, did.SubType, 
+				      did.Interface);
+		if(!s) {
+			sprintf(sn, "interface %d", did.Interface);
+			s=sn;
+		}
+		if ( did.BusId & PCIDEVICE ) 
+		  printk("PCI Device, Bus %d, DevFunc 0x%x:",
+			 dev->BusAccess.PCIAccess.BusNumber,
+			 dev->BusAccess.PCIAccess.DevFuncNumber);
+	       	if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:");
+		if ( did.BusId & ISADEVICE ) 
+		  printk("ISA Device, Slot %d, LogicalDev %d:",
+			 dev->BusAccess.ISAAccess.SlotNumber,
+			 dev->BusAccess.ISAAccess.LogicalDevNumber);
+		if ( did.BusId & EISADEVICE ) printk("EISA Device:");
+		if ( did.BusId & PROCESSORDEVICE ) 
+		  printk("ProcBus Device, Bus %d, BUID %d: ",
+			 dev->BusAccess.ProcBusAccess.BusNumber,
+			 dev->BusAccess.ProcBusAccess.BUID);
+		if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA ");
+		if ( did.BusId & VMEDEVICE ) printk("VME ");
+		if ( did.BusId & MCADEVICE ) printk("MCA ");
+		if ( did.BusId & MXDEVICE ) printk("MX ");
+		/* Decompress first 3 chars */
+		decomp[0]='A'-1+((did.DevId>>26)&0x1F);
+		decomp[1]='A'-1+((did.DevId>>21)&0x1F);
+		decomp[2]='A'-1+((did.DevId>>16)&0x1F);
+		decomp[3]=0;
+		printk(" %s%4.4lX, %s, %s, %s\n", 
+		       decomp, did.DevId&0xffff,
+		       PnP_BASE_TYPES[did.BaseType],
+		       PnP_SUB_TYPE_STR(did.BaseType,did.SubType),
+		       s);
+		if ( dev->AllocatedOffset )
+			printpackets( (union _PnP_TAG_PACKET *)
+				      &res->DevicePnPHeap[dev->AllocatedOffset],
+				      "allocated");
+		if ( dev->PossibleOffset )
+			printpackets( (union _PnP_TAG_PACKET *)
+				      &res->DevicePnPHeap[dev->PossibleOffset],
+				      "possible");
+		if ( dev->CompatibleOffset )
+			printpackets( (union _PnP_TAG_PACKET *)
+				      &res->DevicePnPHeap[dev->CompatibleOffset],
+				      "compatible");
+	}
+}
+
+
+#if 0
+static void __init printVPD(void) {
+#define vpd res->VitalProductData
+	int ps=vpd.PageSize, i, j;
+	static const char* Usage[]={
+	  "FirmwareStack",  "FirmwareHeap",  "FirmwareCode", "BootImage",
+	  "Free", "Unpopulated", "ISAAddr", "PCIConfig",
+	  "IOMemory", "SystemIO", "SystemRegs", "PCIAddr", 
+	  "UnPopSystemRom", "SystemROM", "ResumeBlock", "Other" 
+	};
+	static const unsigned char *FWMan[]={
+	  "IBM", "Motorola", "FirmWorks", "Bull"
+	};
+	static const unsigned char *FWFlags[]={
+	  "Conventional", "OpenFirmware", "Diagnostics", "LowDebug",
+	  "MultiBoot", "LowClient", "Hex41", "FAT", 
+	  "ISO9660", "SCSI_ID_Override", "Tape_Boot", "FW_Boot_Path"
+	};
+	static const unsigned char *ESM[]={
+	  "Port92", "PCIConfigA8", "FF001030", "????????"
+	};
+	static const unsigned char *SIOM[]={
+	  "Port850", "????????", "PCIConfigA8", "????????"
+	};
+
+	printk("Model: %s\n",vpd.PrintableModel);
+	printk("Serial: %s\n", vpd.Serial);
+	printk("FirmwareSupplier: %s\n", FWMan[vpd.FirmwareSupplier]);
+	printk("FirmwareFlags:");
+	for(j=0; j<12; j++) {
+	  	if (vpd.FirmwareSupports & (1<<j)) {
+			printk(" %s%c", FWFlags[j], 
+			       vpd.FirmwareSupports&(-2<<j) ? ',' : '\n');
+		}
+	}
+	printk("NVRamSize: %ld\n", vpd.NvramSize);
+	printk("SIMMslots: %ld\n", vpd.NumSIMMSlots);
+	printk("EndianSwitchMethod: %s\n", 
+	       ESM[vpd.EndianSwitchMethod>2 ? 2 : vpd.EndianSwitchMethod]);
+	printk("SpreadIOMethod: %s\n", 
+	       SIOM[vpd.SpreadIOMethod>3 ? 3 : vpd.SpreadIOMethod]);
+	printk("Processor/Bus frequencies (Hz): %ld/%ld\n",
+	       vpd.ProcessorHz, vpd.ProcessorBusHz);
+	printk("Time Base Divisor: %ld\n", vpd.TimeBaseDivisor);
+	printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps);
+	printk("Cache sector size, Lock granularity: %ld, %ld\n",
+	       vpd.CoherenceBlockSize, vpd.GranuleSize);
+	for (i=0; i<res->ActualNumMemSegs; i++) {
+		int mask=res->Segs[i].Usage, first, j;
+		printk("%8.8lx-%8.8lx ", 
+		       res->Segs[i].BasePage*ps,
+		       (res->Segs[i].PageCount+res->Segs[i].BasePage)*ps-1);
+		for(j=15, first=1; j>=0; j--) {
+			if (mask&(1<<j)) {
+				if (first) first=0;
+				else printk(", ");
+				printk("%s", Usage[j]);
+			}
+		}
+		printk("\n");
+	}
+}
+
+/*
+ * Spit out some info about residual data
+ */
+void print_residual_device_info(void)
+{
+	int i;
+	union _PnP_TAG_PACKET *pkt;
+	PPC_DEVICE *dev;
+#define did dev->DeviceId
+	
+	/* make sure we have residual data first */
+	if ( res->ResidualLength == 0 )
+		return;
+	printk("Residual: %ld devices\n", res->ActualNumDevices);
+	for ( i = 0;
+	      i < res->ActualNumDevices ;
+	      i++)
+	{
+		dev = &res->Devices[i];
+		/*
+		 * pci devices
+		 */
+		if ( did.BusId & PCIDEVICE )
+		{
+			printk("PCI Device:");
+			/* unknown vendor */
+			if ( !strncmp( "Unknown", pci_strvendor(did.DevId>>16), 7) )
+				printk(" id %08lx types %d/%d", did.DevId,
+				       did.BaseType, did.SubType);
+			/* known vendor */
+			else
+				printk(" %s %s",
+				       pci_strvendor(did.DevId>>16),
+				       pci_strdev(did.DevId>>16,
+						  did.DevId&0xffff)
+					);
+			
+			if ( did.BusId & PNPISADEVICE )
+			{
+				printk(" pnp:");
+				/* get pnp info on the device */
+				pkt = (union _PnP_TAG_PACKET *)
+					&res->DevicePnPHeap[dev->AllocatedOffset];
+				for (; pkt->S1_Pack.Tag != DF_END_TAG;
+				     pkt++ )
+				{
+					if ( (pkt->S1_Pack.Tag == S4_Packet) ||
+					     (pkt->S1_Pack.Tag == S4_Packet_flags) )
+						printk(" irq %02x%02x",
+						       pkt->S4_Pack.IRQMask[0],
+						       pkt->S4_Pack.IRQMask[1]);
+				}
+			}
+			printk("\n");
+			continue;
+		}
+		/*
+		 * isa devices
+		 */
+		if ( did.BusId & ISADEVICE )
+		{
+			printk("ISA Device: basetype: %d subtype: %d",
+			       did.BaseType, did.SubType);
+			printk("\n");
+			continue;
+		}		
+		/*
+		 * eisa devices
+		 */
+		if ( did.BusId & EISADEVICE )
+		{
+			printk("EISA Device: basetype: %d subtype: %d",
+			       did.BaseType, did.SubType);
+			printk("\n");
+			continue;
+		}		
+		/*
+		 * proc bus devices
+		 */
+		if ( did.BusId & PROCESSORDEVICE )
+		{
+			printk("ProcBus Device: basetype: %d subtype: %d",
+			       did.BaseType, did.SubType);
+			printk("\n");
+			continue;
+		}
+		/*
+		 * pcmcia devices
+		 */
+		if ( did.BusId & PCMCIADEVICE )
+		{
+			printk("PCMCIA Device: basetype: %d subtype: %d",
+			       did.BaseType, did.SubType);
+			printk("\n");
+			continue;
+		}		
+		printk("Unknown bus access device: busid %lx\n",
+		       did.BusId);
+	}
+}
+#endif	
+
+/* Returns the device index in the residual data, 
+   any of the search items may be set as -1 for wildcard,
+   DevID number field (second halfword) is big endian ! 
+
+   Examples:
+   - search for the Interrupt controller (8259 type), 2 methods:
+     1) i8259 = residual_find_device(~0, 
+                                     NULL, 
+				     SystemPeripheral, 
+				     ProgrammableInterruptController, 
+				     ISA_PIC, 
+				     0);
+     2) i8259 = residual_find_device(~0, "PNP0000", -1, -1, -1, 0) 
+
+   - search for the first two serial devices, whatever their type)
+     iserial1 = residual_find_device(~0,NULL,
+                                     CommunicationsDevice,
+				     RS232Device,
+				     -1, 0)
+     iserial2 = residual_find_device(~0,NULL,
+                                     CommunicationsDevice,
+				     RS232Device,
+				     -1, 1)
+   - but search for typical COM1 and COM2 is not easy due to the
+     fact that the interface may be anything and the name "PNP0500" or 
+     "PNP0501". Quite bad. 
+
+*/
+
+/* devid are easier to uncompress than to compress, so to minimize bloat
+in this rarely used area we unencode and compare */
+
+/* in residual data number is big endian in the device table and
+little endian in the heap, so we use two parameters to avoid writing
+two very similar functions */
+
+static int __init same_DevID(unsigned short vendor,
+	       unsigned short Number,
+	       char * str) 
+{
+	static unsigned const char hexdigit[]="0123456789ABCDEF";
+	if (strlen(str)!=7) return 0;
+	if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0])  &&
+	     ( ((vendor>>5)&0x1f)+'A'-1 == str[1])   &&
+	     ( (vendor&0x1f)+'A'-1 == str[2])        &&
+	     (hexdigit[(Number>>12)&0x0f] == str[3]) &&
+	     (hexdigit[(Number>>8)&0x0f] == str[4])  &&
+	     (hexdigit[(Number>>4)&0x0f] == str[5])  &&
+	     (hexdigit[Number&0x0f] == str[6]) ) return 1;
+	return 0;
+}
+
+PPC_DEVICE __init *residual_find_device(unsigned long BusMask,
+			 unsigned char * DevID,
+			 int BaseType,
+			 int SubType,
+			 int Interface,
+			 int n)
+{
+	int i;
+	if ( !res->ResidualLength ) return NULL;
+	for (i=0; i<res->ActualNumDevices; i++) {
+#define Dev res->Devices[i].DeviceId
+		if ( (Dev.BusId&BusMask)                                  &&
+		     (BaseType==-1 || Dev.BaseType==BaseType)             &&
+		     (SubType==-1 || Dev.SubType==SubType)                &&
+		     (Interface==-1 || Dev.Interface==Interface)          &&
+		     (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
+						Dev.DevId&0xffff, DevID)) &&
+		     !(n--) ) return res->Devices+i;
+#undef Dev
+	}
+	return 0;
+}
+
+PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask,
+			 unsigned short DevID,
+			 int BaseType,
+			 int SubType,
+			 int Interface,
+			 int n)
+{
+	int i;
+	if ( !res->ResidualLength ) return NULL;
+	for (i=0; i<res->ActualNumDevices; i++) {
+#define Dev res->Devices[i].DeviceId
+		if ( (Dev.BusId&BusMask)                                  &&
+		     (BaseType==-1 || Dev.BaseType==BaseType)             &&
+		     (SubType==-1 || Dev.SubType==SubType)                &&
+		     (Interface==-1 || Dev.Interface==Interface)          &&
+		     (DevID==0xffff || (Dev.DevId&0xffff) == DevID)	  &&
+		     !(n--) ) return res->Devices+i;
+#undef Dev
+	}
+	return 0;
+}
+
+PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
+				unsigned packet_tag,
+				int n)
+{
+	unsigned mask, masked_tag, size;
+	if(!p) return 0;
+	if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
+	masked_tag = packet_tag&mask;
+	for(; *p != END_TAG; p+=size) {
+		if ((*p & mask) == masked_tag && !(n--)) 
+			return (PnP_TAG_PACKET *) p;
+		if (tag_type(*p))
+			size=ld_le16((unsigned short *)(p+1))+3;
+		else 
+			size=tag_small_count(*p)+1;
+	}
+	return 0; /* not found */
+}
+
+PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p,
+					     unsigned packet_type,
+					     int n)
+{
+	int next=0;
+	while (p) {
+		p = (unsigned char *) PnP_find_packet(p, 0x70, next);
+		if (p && p[1]==packet_type && !(n--)) 
+			return (PnP_TAG_PACKET *) p;
+		next = 1;
+	};
+	return 0; /* not found */
+}
+
+PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p,
+					   unsigned packet_type,
+					   int n)
+{
+	int next=0;
+	while (p) {
+		p = (unsigned char *) PnP_find_packet(p, 0x84, next);
+		if (p && p[3]==packet_type && !(n--)) 
+			return (PnP_TAG_PACKET *) p;
+		next = 1;
+	};
+	return 0; /* not found */
+}
+
+#ifdef CONFIG_PROC_PREPRESIDUAL
+static int proc_prep_residual_read(char * buf, char ** start, off_t off,
+		int count, int *eof, void *data)
+{
+	int n;
+
+	n = res->ResidualLength - off;
+	if (n < 0) {
+		*eof = 1;
+		n = 0;
+	}
+	else {
+		if (n > count)
+			n = count;
+		else
+			*eof = 1;
+
+		memcpy(buf, (char *)res + off, n);
+		*start = buf;
+	}
+
+	return n;
+}
+
+void __init
+proc_prep_residual_init(void)
+{
+	if (res->ResidualLength)
+		create_proc_read_entry("residual", S_IRUGO, NULL,
+					proc_prep_residual_read, NULL);
+}
+
+__initcall(proc_prep_residual_init);
+#endif
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/rpxclassic.h linux-2.4.20-pre2/arch/ppc/platforms/rpxclassic.h
--- linux-2.4.20-pre1/arch/ppc/platforms/rpxclassic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/rpxclassic.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,104 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the RPCG RPX-Classic board.  Copied from the RPX-Lite stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_RPX_DEFS
+#define __MACH_RPX_DEFS
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need.  The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
+#define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
+#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
+#define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
+#define RPX_CSR_ADDR		((uint)0xfa400000)
+#define RPX_CSR_SIZE		((uint)(4 * 1024))
+#define IMAP_ADDR		((uint)0xfa200000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCI_CSR_ADDR		((uint)0x80000000)
+#define PCI_CSR_SIZE		((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0xe0000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+#define PCMCIA_IO_ADDR		((uint)0xe4000000)
+#define PCMCIA_IO_SIZE		((uint)(4 * 1024))
+#define PCMCIA_ATTRB_ADDR	((uint)0xe8000000)
+#define PCMCIA_ATTRB_SIZE	((uint)(4 * 1024))
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ETHEN		((uint)0x80000000)
+#define BCSR0_ETHLPBK		((uint)0x40000000)
+#define BCSR0_COLTESTDIS	((uint)0x20000000)
+#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
+#define BCSR0_ENFLSHSEL		((uint)0x04000000)
+#define BCSR0_FLASH_SEL		((uint)0x02000000)
+#define BCSR0_ENMONXCVR		((uint)0x01000000)
+
+#define BCSR0_PCMCIAVOLT	((uint)0x000f0000)	/* CLLF */
+#define BCSR0_PCMCIA3VOLT	((uint)0x000a0000)	/* CLLF */
+#define BCSR0_PCMCIA5VOLT	((uint)0x00060000)	/* CLLF */
+
+#define BCSR1_IPB5SEL           ((uint)0x00100000)
+#define BCSR1_PCVCTL4           ((uint)0x00080000)
+#define BCSR1_PCVCTL5           ((uint)0x00040000)
+#define BCSR1_PCVCTL6           ((uint)0x00020000)
+#define BCSR1_PCVCTL7           ((uint)0x00010000)
+
+#define BCSR2_EN232XCVR		((uint)0x00008000)
+#define BCSR2_QSPACESEL		((uint)0x00004000)
+#define BCSR2_FETHLEDMODE	((uint)0x00000800)	/* CLLF */
+
+#if defined(CONFIG_HTDMSOUND)
+#include <platforms/rpxhiox.h>
+#endif
+
+/* define IO_BASE for pcmcia, CLLF only */
+#if !defined(CONFIG_PCI)
+#define _IO_BASE 0x80000000
+#define _IO_BASE_SIZE 0x1000
+
+/* for pcmcia sandisk */
+#ifdef CONFIG_IDE
+#define MAX_HWIFS 1
+#define ide_request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
+#endif
+#endif
+
+/* Interrupt level assignments.
+*/
+#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
+
+#endif /* !__ASSEMBLY__ */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/rpxhiox.h linux-2.4.20-pre2/arch/ppc/platforms/rpxhiox.h
--- linux-2.4.20-pre1/arch/ppc/platforms/rpxhiox.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/rpxhiox.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,45 @@
+/*
+ * BK Id: SCCS/s.rpxhiox.h 1.3 05/17/01 18:14:25 cort
+ */
+
+/*
+ * The Embedded Planet HIOX expansion card definitions.
+ * There were a few different versions of these cards, but only
+ * the one that escaped real production is defined here.
+ *
+ * Copyright (c) 2000 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_RPX_HIOX_DEFS
+#define __MACH_RPX_HIOX_DEFS
+
+#define HIOX_CSR_ADDR		((uint)0xfac00000)
+#define HIOX_CSR_SIZE		((uint)(4 * 1024))
+#define HIOX_CSR0_ADDR		HIOX_CSR_ADDR
+#define HIOX_CSR4_ADDR		((uint)0xfac00004)
+
+#define HIOX_CSR0_DEFAULT	((uint)0x380f3c00)
+#define HIOX_CSR0_ENSCC2	((uint)0x80000000)
+#define HIOX_CSR0_ENSMC2	((uint)0x04000000)
+#define HIOX_CSR0_ENVDOCLK	((uint)0x02000000)
+#define HIOX_CSR0_VDORST_HL	((uint)0x01000000)
+#define HIOX_CSR0_RS232SEL	((uint)0x0000c000)
+#define HIOX_CSR0_SCC3SEL	((uint)0x0000c000)
+#define HIOX_CSR0_SMC1SEL	((uint)0x00008000)
+#define HIOX_CSR0_SCC1SEL	((uint)0x00004000)
+#define HIOX_CSR0_ENTOUCH	((uint)0x00000080)
+#define HIOX_CSR0_PDOWN100	((uint)0x00000060)
+#define HIOX_CSR0_PDOWN10	((uint)0x00000040)
+#define HIOX_CSR0_PDOWN1	((uint)0x00000020)
+#define HIOX_CSR0_TSELSPI	((uint)0x00000010)
+#define HIOX_CSR0_TIRQSTAT	((uint)0x00000008)
+#define HIOX_CSR4_DEFAULT	((uint)0x00000000)
+#define HIOX_CSR4_ENTIRQ2	((uint)0x20000000)
+#define HIOX_CSR4_ENTIRQ3	((uint)0x10000000)
+#define HIOX_CSR4_ENAUDIO	((uint)0x00000080)
+#define HIOX_CSR4_RSTAUDIO	((uint)0x00000040)	/* 0 == reset */
+#define HIOX_CSR4_AUDCLKHI	((uint)0x00000020)
+#define HIOX_CSR4_AUDSPISEL	((uint)0x00000010)
+#define HIOX_CSR4_AUDIRQSTAT	((uint)0x00000008)
+#define HIOX_CSR4_AUDCLKSEL	((uint)0x00000007)
+
+#endif
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/rpxlite.h linux-2.4.20-pre2/arch/ppc/platforms/rpxlite.h
--- linux-2.4.20-pre1/arch/ppc/platforms/rpxlite.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/rpxlite.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,84 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+
+/*
+ * A collection of structures, addresses, and values associated with
+ * the RPCG RPX-Lite board.  Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_RPX_DEFS
+#define __MACH_RPX_DEFS
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+	unsigned int	bi_memstart;	/* Memory start address */
+	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
+	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
+	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
+	unsigned char	bi_enetaddr[6];
+	unsigned int	bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need.  The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define RPX_CSR_ADDR		((uint)0xfa400000)
+#define RPX_CSR_SIZE		((uint)(4 * 1024))
+#define IMAP_ADDR		((uint)0xfa200000)
+#define IMAP_SIZE		((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR		((uint)0x04000000)
+#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
+#define PCMCIA_IO_ADDR		((uint)0x04400000)
+#define PCMCIA_IO_SIZE		((uint)(4 * 1024))
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ETHEN		((uint)0x80000000)
+#define BCSR0_ETHLPBK		((uint)0x40000000)
+#define BCSR0_COLTESTDIS	((uint)0x20000000)
+#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
+#define BCSR0_LEDOFF		((uint)0x08000000)
+#define BCSR0_USBDISABLE	((uint)0x04000000)
+#define BCSR0_USBHISPEED	((uint)0x02000000)
+#define BCSR0_USBPWREN		((uint)0x01000000)
+#define BCSR0_PCMCIAVOLT	((uint)0x000f0000)
+#define BCSR0_PCMCIA3VOLT	((uint)0x000a0000)
+#define BCSR0_PCMCIA5VOLT	((uint)0x00060000)
+
+#define BCSR1_IPB5SEL          ((uint)0x00100000)
+#define BCSR1_PCVCTL4          ((uint)0x00080000)
+#define BCSR1_PCVCTL5          ((uint)0x00040000)
+#define BCSR1_PCVCTL6          ((uint)0x00020000)
+#define BCSR1_PCVCTL7          ((uint)0x00010000)
+
+#if defined(CONFIG_HTDMSOUND)
+#include <platforms/rpxhiox.h>
+#endif
+#endif /* !__ASSEMBLY__ */
+
+/* define IO_BASE for pcmcia */
+#define _IO_BASE 0x80000000
+#define _IO_BASE_SIZE 0x1000
+
+#ifdef CONFIG_IDE
+#define MAX_HWIFS 1
+#define ide_request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
+#endif
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/sleep.S linux-2.4.20-pre2/arch/ppc/platforms/sleep.S
--- linux-2.4.20-pre1/arch/ppc/platforms/sleep.S	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/sleep.S	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,452 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * This file contains sleep low-level functions for PowerBook G3.
+ *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *    and 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.
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+
+#define MAGIC	0x4c617273	/* 'Lars' */
+
+/*
+ * Structure for storing CPU registers on the stack.
+ */
+#define SL_SP		0
+#define SL_PC		4
+#define SL_MSR		8
+#define SL_SDR1		0xc
+#define SL_SPRG0	0x10	/* 4 sprg's */
+#define SL_DBAT0	0x20
+#define SL_IBAT0	0x28
+#define SL_DBAT1	0x30
+#define SL_IBAT1	0x38
+#define SL_DBAT2	0x40
+#define SL_IBAT2	0x48
+#define SL_DBAT3	0x50
+#define SL_IBAT3	0x58
+#define SL_TB		0x60
+#define SL_HID0		0x68
+#define SL_HID1		0x6c
+#define SL_MSSCR0	0x70
+#define SL_MSSSR0	0x74
+#define SL_ICTRL	0x78
+#define SL_LDSTCR	0x7c
+#define SL_LDSTDB	0x80
+#define SL_R2		0x84
+#define SL_CR		0x88
+#define SL_R12		0x8c	/* r12 to r31 */
+#define SL_SIZE		(SL_R12 + 80)
+
+	.text
+	.align	5
+
+/* This gets called by via-pmu.c late during the sleep process.
+ * The PMU was already send the sleep command and will shut us down
+ * soon. We need to save all that is needed and setup the wakeup
+ * vector that will be called by the ROM on wakeup
+ */
+_GLOBAL(low_sleep_handler)
+	mflr	r0
+	stw	r0,4(r1)
+	stwu	r1,-SL_SIZE(r1)
+	mfcr	r0
+	stw	r0,SL_CR(r1)
+	stw	r2,SL_R2(r1)
+	stmw	r12,SL_R12(r1)
+
+	/* Save MSR & SDR1 */
+	mfmsr	r4
+	stw	r4,SL_MSR(r1)
+	mfsdr1	r4
+	stw	r4,SL_SDR1(r1)
+
+	/* Get a stable timebase and save it */
+1:	mftbu	r4
+	stw	r4,SL_TB(r1)
+	mftb	r5
+	stw	r5,SL_TB+4(r1)
+	mftbu	r3
+	cmpw	r3,r4
+	bne	1b
+	
+	/* Save SPRGs */
+	mfsprg	r4,0
+	stw	r4,SL_SPRG0(r1)
+	mfsprg	r4,1
+	stw	r4,SL_SPRG0+4(r1)
+	mfsprg	r4,2
+	stw	r4,SL_SPRG0+8(r1)
+	mfsprg	r4,3
+	stw	r4,SL_SPRG0+12(r1)
+
+	/* Save BATs */
+	mfdbatu	r4,0
+	stw	r4,SL_DBAT0(r1)
+	mfdbatl	r4,0
+	stw	r4,SL_DBAT0+4(r1)
+	mfdbatu	r4,1
+	stw	r4,SL_DBAT1(r1)
+	mfdbatl	r4,1
+	stw	r4,SL_DBAT1+4(r1)
+	mfdbatu	r4,2
+	stw	r4,SL_DBAT2(r1)
+	mfdbatl	r4,2
+	stw	r4,SL_DBAT2+4(r1)
+	mfdbatu	r4,3
+	stw	r4,SL_DBAT3(r1)
+	mfdbatl	r4,3
+	stw	r4,SL_DBAT3+4(r1)
+	mfibatu	r4,0
+	stw	r4,SL_IBAT0(r1)
+	mfibatl	r4,0
+	stw	r4,SL_IBAT0+4(r1)
+	mfibatu	r4,1
+	stw	r4,SL_IBAT1(r1)
+	mfibatl	r4,1
+	stw	r4,SL_IBAT1+4(r1)
+	mfibatu	r4,2
+	stw	r4,SL_IBAT2(r1)
+	mfibatl	r4,2
+	stw	r4,SL_IBAT2+4(r1)
+	mfibatu	r4,3
+	stw	r4,SL_IBAT3(r1)
+	mfibatl	r4,3
+	stw	r4,SL_IBAT3+4(r1)
+
+	/* Save HID0 */
+	mfspr	r4,HID0
+	stw	r4,SL_HID0(r1)
+
+	/* Save 7400/7410/7450 specific registers */
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpli	cr0,r3,0x8000
+	cmpli	cr1,r3,0x000c
+	cmpli	cr2,r3,0x800c
+	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	bne	1f
+	mfspr	r4,SPRN_MSSCR0
+	stw	r4,SL_MSSCR0(r1)
+	mfspr	r4,SPRN_MSSSR0
+	stw	r4,SL_MSSSR0(r1)
+	/* Save 7450 specific registers */
+	beq	cr1,1f
+	mfspr	r4,HID1
+	stw	r4,SL_HID1(r1)
+	mfspr	r4,SPRN_ICTRL
+	stw	r4,SL_ICTRL(r1)
+	mfspr	r4,SPRN_LDSTCR
+	stw	r4,SL_LDSTCR(r1)
+	mfspr	r4,SPRN_LDSTDB
+	stw	r4,SL_LDSTDB(r1)
+1:
+	/* The ROM can wake us up via 2 different vectors:
+	 *  - On wallstreet & lombard, we must write a magic
+	 *    value 'Lars' at address 4 and a pointer to a
+	 *    memory location containing the PC to resume from
+	 *    at address 0.
+	 *  - On Core99, we must store the wakeup vector at
+	 *    address 0x80 and eventually it's parameters
+	 *    at address 0x84. I've have some trouble with those
+	 *    parameters however and I no longer use them.
+	 */
+	lis	r5,grackle_wake_up@ha
+	addi	r5,r5,grackle_wake_up@l
+	tophys(r5,r5)
+	stw	r5,SL_PC(r1)
+	lis	r4,KERNELBASE@h
+	tophys(r5,r1)
+	addi	r5,r5,SL_PC
+	lis	r6,MAGIC@ha
+	addi	r6,r6,MAGIC@l
+	stw	r5,0(r4)
+	stw	r6,4(r4)
+	/* Setup stuffs at 0x80-0x84 for Core99 */
+	lis	r3,core99_wake_up@ha
+	addi	r3,r3,core99_wake_up@l
+	tophys(r3,r3)
+	stw	r3,0x80(r4)
+	stw	r5,0x84(r4)
+	/* Store a pointer to our backup storage into
+	 * a kernel global
+	 */
+	lis r3,sleep_storage@ha
+	addi r3,r3,sleep_storage@l
+	stw r5,0(r3)
+
+	BEGIN_FTR_SECTION
+	DSSALL
+	sync
+	END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+
+/*
+ * Flush the L1 data cache by reading the first 128kB of RAM
+ * and then flushing the same area with the dcbf instruction.
+ * The L2 cache has already been disabled.
+ */
+	li	r4,0x1000	/* 128kB / 32B */
+	mtctr	r4
+	lis	r4,KERNELBASE@h
+1:
+	lwz	r0,0(r4)
+	addi	r4,r4,0x0020	/* Go to start of next cache line */
+	bdnz	1b
+	sync
+	
+	li	r4,0x1000	/* 128kB / 32B */
+	mtctr	r4
+	lis	r4,KERNELBASE@h
+1:
+	dcbf	r0,r4
+	addi	r4,r4,0x0020	/* Go to start of next cache line */
+	bdnz	1b
+	sync
+
+/*
+ * Set the HID0 and MSR for sleep.
+ */
+	mfspr	r2,HID0
+	rlwinm	r2,r2,0,10,7	/* clear doze, nap */
+	oris	r2,r2,HID0_SLEEP@h
+	sync
+	mtspr	HID0,r2
+	sync
+
+/* This loop puts us back to sleep in case we have a spurrious
+ * wakeup so that the host bridge properly stays asleep. The
+ * CPU will be turned off, either after a known time (about 1
+ * second) on wallstreet & lombard, or as soon as the CPU enters
+ * SLEEP mode on core99
+ */
+	mfmsr	r2
+	oris	r2,r2,MSR_POW@h
+1:	sync
+	mtmsr	r2
+	isync
+	b	1b
+
+/* 
+ * Here is the resume code.
+ */
+
+
+/*
+ * Core99 machines resume here
+ * r4 has the physical address of SL_PC(sp) (unused)
+ */
+_GLOBAL(core99_wake_up)
+	/* Make sure HID0 no longer contains any sleep bit */
+	mfspr	r3,HID0
+	rlwinm	r3,r3,0,11,7		/* clear SLEEP, NAP, DOZE bits */
+	mtspr	HID0,r3
+	sync
+	isync
+
+	/* Won't that cause problems on CPU that doesn't support it ? */
+	lis	r3, 0
+	mtspr	SPRN_MMCR0, r3
+	
+	/* sanitize MSR */
+	mfmsr	r3
+	ori	r3,r3,MSR_EE|MSR_IP
+	xori	r3,r3,MSR_EE|MSR_IP
+	sync
+	isync
+	mtmsr	r3
+	sync
+	isync
+
+	/* Recover sleep storage */
+	lis	r3,sleep_storage@ha
+	addi	r3,r3,sleep_storage@l
+	tophys(r3,r3)
+	lwz	r1,0(r3)
+
+	/* Pass thru to older resume code ... */
+/* 
+ * Here is the resume code for older machines.
+ * r1 has the physical address of SL_PC(sp).
+ */
+	
+grackle_wake_up:
+	/* Enable and then Flash inval the instruction & data cache */
+	mfspr	r3,HID0
+	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
+	sync
+	isync
+	mtspr	HID0,r3
+	xori	r3,r3, HID0_ICFI|HID0_DCI
+	mtspr	HID0,r3
+	sync
+	
+	/* Restore the kernel's segment registers before
+	 * we do any r1 memory access as we are not sure they
+	 * are in a sane state above the first 256Mb region
+	 */
+	li	r0,16		/* load up segment register values */
+	mtctr	r0		/* for context 0 */
+	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
+	li	r4,0
+3:	mtsrin	r3,r4
+	addi	r3,r3,0x111	/* increment VSID */
+	addis	r4,r4,0x1000	/* address of next segment */
+	bdnz	3b
+	
+	/* Restore the remaining bits of the HID0 register. */
+	subi	r1,r1,SL_PC
+	lwz	r3,SL_HID0(r1)
+	sync
+	isync
+	mtspr	HID0,r3
+	sync
+	isync
+
+	/* Restore 7400/7410/7450 specific registers */
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpli	cr0,r3,0x8000
+	cmpli	cr1,r3,0x000c
+	cmpli	cr2,r3,0x800c
+	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	bne	1f
+	lwz	r4,SL_MSSCR0(r1)
+	sync
+	mtspr	SPRN_MSSCR0,r4
+	sync
+	isync
+	lwz	r4,SL_MSSSR0(r1)
+	sync
+	mtspr	SPRN_MSSSR0,r4
+	sync
+	isync
+	bne	cr2,1f
+	li	r4,0
+	mtspr	SPRN_L2CR2,r4
+	/* Restore 7450 specific registers */
+	beq	cr1,1f
+	lwz	r4,SL_HID1(r1)
+	sync
+	mtspr	HID1,r4
+	isync
+	sync
+	lwz	r4,SPRN_ICTRL(r1)
+	sync
+	mtspr	SPRN_ICTRL,r4
+	isync
+	sync
+	lwz	r4,SPRN_LDSTCR(r1)
+	sync
+	mtspr	SPRN_LDSTCR,r4
+	isync
+	sync
+	lwz	r4,SL_LDSTDB(r1)
+	sync
+	mtspr	SPRN_LDSTDB,r4
+	isync
+	sync
+1:
+	/* Restore the BATs, and SDR1.  Then we can turn on the MMU. */
+	lwz	r4,SL_SDR1(r1)
+	mtsdr1	r4
+	lwz	r4,SL_SPRG0(r1)
+	mtsprg	0,r4
+	lwz	r4,SL_SPRG0+4(r1)
+	mtsprg	1,r4
+	lwz	r4,SL_SPRG0+8(r1)
+	mtsprg	2,r4
+	lwz	r4,SL_SPRG0+12(r1)
+	mtsprg	3,r4
+
+	lwz	r4,SL_DBAT0(r1)
+	mtdbatu	0,r4
+	lwz	r4,SL_DBAT0+4(r1)
+	mtdbatl	0,r4
+	lwz	r4,SL_DBAT1(r1)
+	mtdbatu	1,r4
+	lwz	r4,SL_DBAT1+4(r1)
+	mtdbatl	1,r4
+	lwz	r4,SL_DBAT2(r1)
+	mtdbatu	2,r4
+	lwz	r4,SL_DBAT2+4(r1)
+	mtdbatl	2,r4
+	lwz	r4,SL_DBAT3(r1)
+	mtdbatu	3,r4
+	lwz	r4,SL_DBAT3+4(r1)
+	mtdbatl	3,r4
+	lwz	r4,SL_IBAT0(r1)
+	mtibatu	0,r4
+	lwz	r4,SL_IBAT0+4(r1)
+	mtibatl	0,r4
+	lwz	r4,SL_IBAT1(r1)
+	mtibatu	1,r4
+	lwz	r4,SL_IBAT1+4(r1)
+	mtibatl	1,r4
+	lwz	r4,SL_IBAT2(r1)
+	mtibatu	2,r4
+	lwz	r4,SL_IBAT2+4(r1)
+	mtibatl	2,r4
+	lwz	r4,SL_IBAT3(r1)
+	mtibatu	3,r4
+	lwz	r4,SL_IBAT3+4(r1)
+	mtibatl	3,r4
+
+	/* Flush all TLBs */
+	lis	r4,0x1000
+1:	addic.	r4,r4,-0x1000
+	tlbie	r4
+	blt	1b
+	sync
+
+	/* restore the MSR and turn on the MMU */
+	lwz	r3,SL_MSR(r1)
+	bl	turn_on_mmu	
+
+	/* get back the stack pointer */
+	tovirt(r1,r1)
+
+	/* Restore TB */
+	li	r3,0
+	mttbl	r3
+	lwz	r3,SL_TB(r1)
+	lwz	r4,SL_TB+4(r1)
+	mttbu	r3
+	mttbl	r4
+
+	/* Restore the callee-saved registers and return */
+	lwz	r0,SL_CR(r1)
+	mtcr	r0
+	lwz	r2,SL_R2(r1)
+	lmw	r12,SL_R12(r1)
+	addi	r1,r1,SL_SIZE
+	lwz	r0,4(r1)
+	mtlr	r0
+	blr
+
+turn_on_mmu:
+	mflr	r4
+	tovirt(r4,r4)
+	mtsrr0	r4
+	mtsrr1	r3
+	sync
+	isync
+	rfi
+
+	.data
+	.globl sleep_storage
+sleep_storage:
+	.long 0
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/spd8xx.h linux-2.4.20-pre2/arch/ppc/platforms/spd8xx.h
--- linux-2.4.20-pre1/arch/ppc/platforms/spd8xx.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/spd8xx.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,69 @@
+/*
+ * BK Id: SCCS/s.spd8xx.h 1.8 10/27/01 13:39:41 trini
+ */
+/*
+ * Speech Design SPD8xxTS board specific definitions
+ * 
+ * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_SPD8XX_H__
+#define __ASM_SPD8XX_H__
+
+#include <linux/config.h>
+ 
+#include <asm/ppcboot.h>
+
+#define SPD_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
+#define SPD_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
+
+#define IMAP_ADDR	SPD_IMMR_BASE	/* physical base address of IMMR area */
+#define IMAP_SIZE	SPD_IMAP_SIZE	/* mapped size of IMMR area */
+
+#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
+#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
+
+#define IDE0_INTERRUPT	10		/* = IRQ5 */
+#define IDE1_INTERRUPT	12		/* = IRQ6 */
+#define CPM_INTERRUPT	13		/* = SIU_LEVEL6 (was: SIU_LEVEL2) */
+
+/* override the default number of IDE hardware interfaces */
+#define MAX_HWIFS	2
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory */
+#define IDE0_DATA_REG_OFFSET		0x0000
+#define IDE0_ERROR_REG_OFFSET		0x0081
+#define IDE0_NSECTOR_REG_OFFSET		0x0082
+#define IDE0_SECTOR_REG_OFFSET		0x0083
+#define IDE0_LCYL_REG_OFFSET		0x0084
+#define IDE0_HCYL_REG_OFFSET		0x0085
+#define IDE0_SELECT_REG_OFFSET		0x0086
+#define IDE0_STATUS_REG_OFFSET		0x0087
+#define IDE0_CONTROL_REG_OFFSET		0x0106
+#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
+
+/*
+ * Definitions for IDE1 Interface
+ */
+#define IDE1_BASE_OFFSET		0x0C00	/* Offset in PCMCIA memory */
+#define IDE1_DATA_REG_OFFSET		0x0000
+#define IDE1_ERROR_REG_OFFSET		0x0081
+#define IDE1_NSECTOR_REG_OFFSET		0x0082
+#define IDE1_SECTOR_REG_OFFSET		0x0083
+#define IDE1_LCYL_REG_OFFSET		0x0084
+#define IDE1_HCYL_REG_OFFSET		0x0085
+#define IDE1_SELECT_REG_OFFSET		0x0086
+#define IDE1_STATUS_REG_OFFSET		0x0087
+#define IDE1_CONTROL_REG_OFFSET		0x0106
+#define IDE1_IRQ_REG_OFFSET		0x000A	/* not used */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif /* __ASM_SPD8XX_H__ */
+#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/tqm8xx.h linux-2.4.20-pre2/arch/ppc/platforms/tqm8xx.h
--- linux-2.4.20-pre1/arch/ppc/platforms/tqm8xx.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/tqm8xx.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,54 @@
+/*
+ * BK Id: SCCS/s.tqm8xx.h 1.8 08/30/01 09:01:04 trini
+ */
+/*
+ * TQM8xx(L) board specific definitions
+ * 
+ * Copyright (c) 1999,2000,2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifndef __MACH_TQM8xx_H
+#define __MACH_TQM8xx_H
+
+#include <linux/config.h>
+ 
+#include <asm/ppcboot.h>
+
+#define	TQM_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
+#define	TQM_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
+
+#define	IMAP_ADDR	TQM_IMMR_BASE	/* physical base address of IMMR area */
+#define IMAP_SIZE	TQM_IMAP_SIZE	/* mapped size of IMMR area */
+
+/*-----------------------------------------------------------------------
+ * PCMCIA stuff
+ *-----------------------------------------------------------------------
+ *
+ */
+#define PCMCIA_MEM_SIZE		( 64 << 20 )
+
+#define	MAX_HWIFS	1	/* overwrite default in include/asm-ppc/ide.h */
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET		0
+#define IDE0_DATA_REG_OFFSET		(PCMCIA_MEM_SIZE + 0x320)
+#define IDE0_ERROR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 1)
+#define IDE0_NSECTOR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 2)
+#define IDE0_SECTOR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 3)
+#define IDE0_LCYL_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 4)
+#define IDE0_HCYL_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 5)
+#define IDE0_SELECT_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 6)
+#define IDE0_STATUS_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 7)
+#define IDE0_CONTROL_REG_OFFSET		0x0106
+#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
+
+#define	IDE0_INTERRUPT			13
+
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+#endif	/* __MACH_TQM8xx_H */
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/walnut.c linux-2.4.20-pre2/arch/ppc/platforms/walnut.c
--- linux-2.4.20-pre1/arch/ppc/platforms/walnut.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/walnut.c	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,291 @@
+/*
+ * BK Id: SCCS/s.walnut_setup.c 1.10 11/13/01 21:26:07 paulus
+ */
+/*
+ *
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: walnut_setup.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM PowerPC 403GP "Walnut" evaluation board. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/seq_file.h>
+
+#include <asm/processor.h>
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+
+#include "ppc4xx_pic.h"
+#include <asm/time.h>
+#include "walnut_setup.h"
+
+
+/* Function Prototypes */
+
+extern void abort(void);
+
+/* Global Variables */
+
+unsigned char __res[sizeof(bd_t)];
+
+
+/*
+ * void __init walnut_init()
+ *
+ * Description:
+ *   This routine...
+ *
+ * Input(s):
+ *   r3 - Optional pointer to a board information structure.
+ *   r4 - Optional pointer to the physical starting address of the init RAM
+ *        disk.
+ *   r5 - Optional pointer to the physical ending address of the init RAM
+ *        disk.
+ *   r6 - Optional pointer to the physical starting address of any kernel
+ *        command-line parameters.
+ *   r7 - Optional pointer to the physical ending address of any kernel
+ *        command-line parameters.
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+void __init
+walnut_init(unsigned long r3, unsigned long r4, unsigned long r5, 
+	    unsigned long r6, unsigned long r7)
+{
+	/*
+	 * If we were passed in a board information, copy it into the
+	 * residual data area.
+	 */
+	if (r3) {
+		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+	}
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+	/*
+	 * If the init RAM disk has been configured in, and there's a valid
+	 * starting address for it, set it up.
+	 */
+	if (r4) {
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* Copy the kernel command line arguments to a safe place. */
+
+	if (r6) {
+ 		*(char *)(r7 + KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
+	}
+
+	/* Initialize machine-dependency vectors */
+
+	ppc_md.setup_arch	 	= walnut_setup_arch;
+	ppc_md.show_percpuinfo	 	= walnut_show_percpuinfo;
+	ppc_md.irq_cannonicalize 	= NULL;
+	ppc_md.init_IRQ		 	= walnut_init_IRQ;
+	ppc_md.get_irq		 	= walnut_get_irq;
+	ppc_md.init		 	= NULL;
+
+	ppc_md.restart		 	= walnut_restart;
+	ppc_md.power_off	 	= walnut_power_off;
+	ppc_md.halt		 	= walnut_halt;
+
+	ppc_md.time_init	 	= walnut_time_init;
+	ppc_md.set_rtc_time	 	= walnut_set_rtc_time;
+	ppc_md.get_rtc_time	 	= walnut_get_rtc_time;
+	ppc_md.calibrate_decr	 	= walnut_calibrate_decr;
+
+	ppc_md.kbd_setkeycode    	= NULL;
+	ppc_md.kbd_getkeycode    	= NULL;
+	ppc_md.kbd_translate     	= NULL;
+	ppc_md.kbd_unexpected_up 	= NULL;
+	ppc_md.kbd_leds          	= NULL;
+	ppc_md.kbd_init_hw       	= NULL;
+	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
+}
+
+/*
+ * Document me.
+ */
+void __init
+walnut_setup_arch(void)
+{
+	/* XXX - Implement me */
+}
+
+/*
+ * int walnut_show_percpuinfo()
+ *
+ * Description:
+ *   This routine pretty-prints the platform's internal CPU and bus clock
+ *   frequencies into the buffer for usage in /proc/cpuinfo.
+ *
+ * Input(s):
+ *  *buffer - Buffer into which CPU and bus clock frequencies are to be
+ *            printed.
+ *
+ * Output(s):
+ *  *buffer - Buffer with the CPU and bus clock frequencies.
+ *
+ * Returns:
+ *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
+ *   on error.
+ */
+int
+walnut_show_percpuinfo(struct seq_file *m)
+{
+	bd_t *bp = (bd_t *)__res;
+
+	seq_printf(m, "clock\t\t: %dMHz\n"
+		   "bus clock\t\t: %dMHz\n",
+		   bp->bi_intfreq / 1000000,
+		   bp->bi_busfreq / 1000000);
+
+	return 0;
+}
+
+/*
+ * Document me.
+ */
+void __init
+walnut_init_IRQ(void)
+{
+	int i;
+
+	ppc4xx_pic_init();
+
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].handler = ppc4xx_pic;
+	}
+
+	return;
+}
+
+/*
+ * Document me.
+ */
+int
+walnut_get_irq(struct pt_regs *regs)
+{
+	return (ppc4xx_pic_get_irq(regs));
+}
+
+/*
+ * Document me.
+ */
+void
+walnut_restart(char *cmd)
+{
+	abort();
+}
+
+/*
+ * Document me.
+ */
+void
+walnut_power_off(void)
+{
+	walnut_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void
+walnut_halt(void)
+{
+	walnut_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+long __init
+walnut_time_init(void)
+{
+	/* XXX - Implement me */
+	return 0;
+}
+
+/*
+ * Document me.
+ */
+int __init
+walnut_set_rtc_time(unsigned long time)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * Document me.
+ */
+unsigned long __init
+walnut_get_rtc_time(void)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * void __init walnut_calibrate_decr()
+ *
+ * Description:
+ *   This routine retrieves the internal processor frequency from the board
+ *   information structure, sets up the kernel timer decrementer based on
+ *   that value, enables the 403 programmable interval timer (PIT) and sets
+ *   it up for auto-reload.
+ *
+ * Input(s):
+ *   N/A
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+void __init
+walnut_calibrate_decr(void)
+{
+	unsigned int freq;
+	bd_t *bip = (bd_t *)__res;
+
+	freq = bip->bi_intfreq;
+
+	decrementer_count = freq / HZ;
+	count_period_num = 1;
+	count_period_den = freq;
+
+	/* Enable the PIT and set auto-reload of its value */
+
+	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
+
+	/* Clear any pending timer interrupts */
+
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
+}
diff -urN linux-2.4.20-pre1/arch/ppc/platforms/walnut.h linux-2.4.20-pre2/arch/ppc/platforms/walnut.h
--- linux-2.4.20-pre1/arch/ppc/platforms/walnut.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/arch/ppc/platforms/walnut.h	Mon Aug 12 16:34:15 2002
@@ -0,0 +1,53 @@
+/*
+ * BK Id: SCCS/s.walnut_setup.h 1.5 05/17/01 18:14:22 cort
+ */
+/*
+ *
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: walnut_setup.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      the IBM PowerPC 405GP "Walnut" evaluation board. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
+ *      <dan@netx4.com>.
+ *
+ */
+
+#ifndef	__WALNUT_SETUP_H__
+#define	__WALNUT_SETUP_H__
+
+#include <asm/ptrace.h>
+#include <asm/board.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned char	 __res[sizeof(bd_t)];
+
+extern void		 walnut_init(unsigned long r3,
+				  unsigned long ird_start,
+				  unsigned long ird_end,
+				  unsigned long cline_start,
+				  unsigned long cline_end);
+extern void		 walnut_setup_arch(void);
+extern int		 walnut_setup_residual(char *buffer);
+extern void		 walnut_init_IRQ(void);
+extern int		 walnut_get_irq(struct pt_regs *regs);
+extern void		 walnut_restart(char *cmd);
+extern void		 walnut_power_off(void);
+extern void		 walnut_halt(void);
+extern void		 walnut_time_init(void);
+extern int		 walnut_set_rtc_time(unsigned long now);
+extern unsigned long	 walnut_get_rtc_time(void);
+extern void		 walnut_calibrate_decr(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WALNUT_SETUP_H__ */
diff -urN linux-2.4.20-pre1/arch/ppc64/config.in linux-2.4.20-pre2/arch/ppc64/config.in
--- linux-2.4.20-pre1/arch/ppc64/config.in	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc64/config.in	Mon Aug 12 16:34:15 2002
@@ -70,9 +70,9 @@
    define_bool CONFIG_KCORE_ELF y
 fi
 
-bool 'Kernel Support for 64 bit ELF binaries' CONFIG_BINFMT_ELF
+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 32-bit ELF binaries' CONFIG_BINFMT_ELF32
 
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
diff -urN linux-2.4.20-pre1/arch/ppc64/kernel/htab.c linux-2.4.20-pre2/arch/ppc64/kernel/htab.c
--- linux-2.4.20-pre1/arch/ppc64/kernel/htab.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc64/kernel/htab.c	Mon Aug 12 16:34:15 2002
@@ -38,7 +38,6 @@
 #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>
diff -urN linux-2.4.20-pre1/arch/ppc64/kernel/pSeries_pci.c linux-2.4.20-pre2/arch/ppc64/kernel/pSeries_pci.c
--- linux-2.4.20-pre1/arch/ppc64/kernel/pSeries_pci.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/ppc64/kernel/pSeries_pci.c	Mon Aug 12 16:34:15 2002
@@ -491,7 +491,7 @@
 					 0x100000); 
 
 		/* 
-		 * Firmware doesnt always clear this bit which is critical
+		 * Firmware doesn't always clear this bit which is critical
 		 * for good performance - Anton
 		 */
 		{
diff -urN linux-2.4.20-pre1/arch/s390/config.in linux-2.4.20-pre2/arch/s390/config.in
--- linux-2.4.20-pre1/arch/s390/config.in	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/config.in	Mon Aug 12 16:34:15 2002
@@ -75,3 +75,4 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/s390/defconfig linux-2.4.20-pre2/arch/s390/defconfig
--- linux-2.4.20-pre1/arch/s390/defconfig	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/defconfig	Mon Aug 12 16:34:15 2002
@@ -32,6 +32,8 @@
 # General setup
 #
 CONFIG_FAST_IRQ=y
+CONFIG_MACHCHK_WARNING=y
+CONFIG_CHSC=y
 CONFIG_IPL=y
 # CONFIG_IPL_TAPE is not set
 CONFIG_IPL_VM=y
@@ -146,9 +148,10 @@
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
+CONFIG_SHARED_IPV6_CARDS=y
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
+CONFIG_VLAN_8021Q=m
 
 #
 #  
@@ -163,7 +166,7 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-CONFIG_NET_FASTROUTE=y
+# CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
diff -urN linux-2.4.20-pre1/arch/s390/kernel/debug.c linux-2.4.20-pre2/arch/s390/kernel/debug.c
--- linux-2.4.20-pre1/arch/s390/kernel/debug.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/kernel/debug.c	Mon Aug 12 16:34:15 2002
@@ -443,6 +443,7 @@
 {
 	size_t count = 0;
 	size_t entry_offset, size = 0;
+	int rc;
 	file_private_info_t *p_info;
 
 	p_info = ((file_private_info_t *) file->private_data);
@@ -458,9 +459,9 @@
 		size = MIN((len - count), (size - entry_offset));
 
 		if(size){
-			if (copy_to_user(user_buf + count, 
-					p_info->temp_buf + entry_offset, size))
-				return count ? count: -EFAULT;
+			if ((rc = copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size)))
+			return rc;
 		}
 		count += size;
 		entry_offset = 0;
diff -urN linux-2.4.20-pre1/arch/s390/kernel/entry.S linux-2.4.20-pre2/arch/s390/kernel/entry.S
--- linux-2.4.20-pre1/arch/s390/kernel/entry.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/kernel/entry.S	Mon Aug 12 16:34:15 2002
@@ -221,11 +221,11 @@
 # call trace before and after sys_call
 #
 sysc_tracesys:
-	la	%r12,BASED(sysc_return)
+	la	%r11,BASED(sysc_return)
 
 #
 # call syscall_trace before and after system call
-# special linkage: %r12 contains the return address for trace_svc
+# special linkage: %r11 contains the return address for trace_svc
 #
 trace_svc:
         l       %r1,BASED(.Ltrace)
@@ -244,7 +244,7 @@
         basr    %r14,%r8          # call sys_xxx
         st      %r2,SP_R2(%r15)   # store return value
         l       %r1,BASED(.Ltrace)
-	lr	%r14,%r12	  # return point is in %r12
+	lr	%r14,%r11	  # return point is in %r11
         br      %r1
 
 #
@@ -678,7 +678,7 @@
 # call trace before and after sys_call
 #
 pgm_tracesys:
-	la	%r12,BASED(pgm_svcret)
+	la	%r11,BASED(pgm_svcret)
 	b	BASED(trace_svc)
 
 /*
@@ -758,25 +758,25 @@
 	SAVE_ALL_BASE
         SAVE_ALL __LC_EXT_OLD_PSW,0
         GET_CURRENT                    # load pointer to task_struct to R9
-        la      %r2,SP_PTREGS(%r15)    # address of register-save area
-        lh      %r3,__LC_EXT_INT_CODE  # error code
-        lr      %r1,%r3                # calculate index = code & 0xff
-        n       %r1,BASED(.Lc0xff)
-        sll     %r1,2
-        l       %r4,BASED(.Lext_hash)
-        l       %r4,0(%r1,%r4)         # get first list entry for hash value
-        ltr     %r4,%r4                # == NULL ?
-        bz      BASED(io_return)       # yes, nothing to do, exit
+	lh	%r6,__LC_EXT_INT_CODE  # get interruption code
+	lr	%r1,%r6		       # calculate index = code & 0xff
+	n	%r1,BASED(.Lc0xff)
+	sll	%r1,2
+	l	%r7,BASED(.Lext_hash)
+	l	%r7,0(%r1,%r7)	       # get first list entry for hash value
+	ltr	%r7,%r7		       # == NULL ?
+	bz	BASED(io_return)       # yes, nothing to do, exit
 ext_int_loop:
-        ch      %r3,8(%r4)             # compare external interrupt code
-        be      BASED(ext_int_found)
-        icm     %r4,15,0(%r4)          # next list entry
-        bnz     BASED(ext_int_loop)
-        b       BASED(io_return)
-ext_int_found:
-        l       %r4,4(%r4)             # get handler address
-        la      %r14,BASED(io_return)
-        br      %r4                    # branch to ext call handler
+	ch	%r6,8(%r7)	       # compare external interrupt code
+	bne	BASED(ext_int_next)
+	l	%r1,4(%r7)	       # get handler address
+	la	%r2,SP_PTREGS(%r15)    # address of register-save area
+	lr	%r3,%r6		       # interruption code
+	basr	%r14,%r1	       # call handler
+ext_int_next:
+	icm	%r7,15,0(%r7)	       # next list entry
+	bnz	BASED(ext_int_loop)
+	b	BASED(io_return)
 
 /*
  * Machine check handler routines
diff -urN linux-2.4.20-pre1/arch/s390/kernel/ieee.h linux-2.4.20-pre2/arch/s390/kernel/ieee.h
--- linux-2.4.20-pre1/arch/s390/kernel/ieee.h	Fri May 12 11:41:44 2000
+++ linux-2.4.20-pre2/arch/s390/kernel/ieee.h	Wed Dec 31 16:00:00 1969
@@ -1,90 +0,0 @@
-/*
- *  arch/s390/kernel/ieee.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- */
-
-#include <linux/sched.h>
-
-static    inline void _adddf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd +
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _subdf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd -
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _muldf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd *
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _divdf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd /
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _negdf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = -current->tss.fprs[R1].fd;
-}
-
-static    inline void _fixdfsi(int R1,int R2)
-{
-  current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].fd;
-}
-
-static    inline void _extendsidf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = (double) current->tss.regs->gprs[R2];
-}
-
-
-static    inline  void _addsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff +
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline  void _subsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff -
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline void _mulsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff *
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline void _divsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff /
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline void _negsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = -current->tss.fprs[R1].ff;
-}
-
-static    inline void _fixsfsi(int R1,int R2)
-{
-  current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].ff;
-}
-
-static    inline void _extendsisf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = (double) current->tss.regs->gprs[R2];
-}
-
-
diff -urN linux-2.4.20-pre1/arch/s390/kernel/ptrace.c linux-2.4.20-pre2/arch/s390/kernel/ptrace.c
--- linux-2.4.20-pre1/arch/s390/kernel/ptrace.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/kernel/ptrace.c	Mon Aug 12 16:34:15 2002
@@ -121,10 +121,11 @@
 		else
 		{
 			if(realuseraddr==(addr_t)NULL)
-				retval=(clear_user((void *)copyaddr,len)==-EFAULT ? -EIO:0);
+				retval=clear_user((void *)copyaddr,len);
 			else
-				retval=(copy_to_user((void *)copyaddr,(void *)realuseraddr,len)==-EFAULT ? -EIO:0);
+				retval=copy_to_user((void *)copyaddr,(void *)realuseraddr,len);
 		}      
+		retval = retval ? -EFAULT : 0;
 	}
 	else
 	{
@@ -235,16 +236,18 @@
 	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;
+		goto out_tsk;
 	if (request == PTRACE_ATTACH) 
 	{
 		ret = ptrace_attach(child);
-		goto out;
+		goto out_tsk;
 	}
 	ret = -ESRCH;
 	// printk("child=%lX child->flags=%lX",child,child->flags);
@@ -253,14 +256,14 @@
 	if(child!=current)
 	{
 		if (!(child->ptrace & PT_PTRACED))
-			goto out;
+			goto out_tsk;
 		if (child->state != TASK_STOPPED) 
 		{
 			if (request != PTRACE_KILL)
-				goto out;
+				goto out_tsk;
 		}
 		if (child->p_pptr != current)
-			goto out;
+			goto out_tsk;
 	}
 	switch (request) 
 	{
@@ -270,9 +273,9 @@
 		copied = access_process_vm(child,ADDR_BITS_REMOVE(addr), &tmp, sizeof(tmp), 0);
 		ret = -EIO;
 		if (copied != sizeof(tmp))
-			goto out;
+			break;
 		ret = put_user(tmp,(unsigned long *) data);
-		goto out;
+		break;
 
 		/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR:
@@ -284,9 +287,8 @@
 	case PTRACE_POKEDATA:
 		ret = 0;
 		if (access_process_vm(child,ADDR_BITS_REMOVE(addr), &data, sizeof(data), 1) == sizeof(data))
-			goto out;
+			break;
 		ret = -EIO;
-		goto out;
 		break;
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
@@ -343,14 +345,15 @@
 	case PTRACE_POKEUSR_AREA:
 		if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)  
 			ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
-		else
-			ret = -EFAULT;
+				      parea.len,1,(request==PTRACE_POKEUSR_AREA));
+		else ret = -EFAULT;
 		break;
 	default:
 		ret = -EIO;
 		break;
 	}
+ out_tsk:
+	free_task_struct(child);
  out:
 	unlock_kernel();
 	return ret;
diff -urN linux-2.4.20-pre1/arch/s390/kernel/s390_ext.c linux-2.4.20-pre2/arch/s390/kernel/s390_ext.c
--- linux-2.4.20-pre1/arch/s390/kernel/s390_ext.c	Wed Jul 25 14:12:01 2001
+++ linux-2.4.20-pre2/arch/s390/kernel/s390_ext.c	Mon Aug 12 16:34:15 2002
@@ -21,34 +21,31 @@
  * iucv and 0x2603 pfault) this is always the first element. 
  */
 ext_int_info_t *ext_int_hash[256] = { 0, };
-ext_int_info_t ext_int_info_timer;
-ext_int_info_t ext_int_info_hwc;
-ext_int_info_t ext_int_pfault;
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
         ext_int_info_t *p;
         int index;
 
-        index = code & 0xff;
-        p = ext_int_hash[index];
-        while (p != NULL) {
-                if (p->code == code)
-                        return -EBUSY;
-                p = p->next;
-        }
-        if (code == 0x1004) /* time_init is done before kmalloc works :-/ */
-                p = &ext_int_info_timer;
-        else if (code == 0x2401) /* hwc_init is done too early too */
-                p = &ext_int_info_hwc;
-        else if (code == 0x2603) /* pfault_init is done too early too */
-		p = &ext_int_pfault;
-	else
-                p = (ext_int_info_t *)
-                          kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
+	p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
         if (p == NULL)
                 return -ENOMEM;
         p->code = code;
         p->handler = handler;
+        index = code & 0xff;
+        p->next = ext_int_hash[index];
+        ext_int_hash[index] = p;
+        return 0;
+}
+
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *p) {
+        int index;
+
+        if (p == NULL)
+                return -EINVAL;
+        p->code = code;
+        p->handler = handler;
+        index = code & 0xff;
         p->next = ext_int_hash[index];
         ext_int_hash[index] = p;
         return 0;
@@ -73,11 +70,33 @@
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
-                kfree(p);
+	kfree(p);
         return 0;
 }
 
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *p) {
+	ext_int_info_t *q;
+	int index;
+
+	if (p == NULL || p->code != code || p->handler != handler)
+		return -EINVAL;
+	index = code & 0xff;
+	q = ext_int_hash[index];
+	if (p != q) {
+		while (q != NULL) {
+			if (q->next == p)
+				break;
+			q = q->next;
+		}
+		if (q == NULL)
+			return -ENOENT;
+		q->next = p->next;
+	} else
+		ext_int_hash[index] = p->next;
+	return 0;
+}
+
 EXPORT_SYMBOL(register_external_interrupt);
 EXPORT_SYMBOL(unregister_external_interrupt);
 
diff -urN linux-2.4.20-pre1/arch/s390/kernel/s390_ksyms.c linux-2.4.20-pre2/arch/s390/kernel/s390_ksyms.c
--- linux-2.4.20-pre1/arch/s390/kernel/s390_ksyms.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/kernel/s390_ksyms.c	Mon Aug 12 16:34:15 2002
@@ -9,6 +9,7 @@
 #include <asm/checksum.h>
 #include <asm/delay.h>
 #include <asm/setup.h>
+#include <asm/softirq.h>
 #if CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
diff -urN linux-2.4.20-pre1/arch/s390/kernel/setup.c linux-2.4.20-pre2/arch/s390/kernel/setup.c
--- linux-2.4.20-pre1/arch/s390/kernel/setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/kernel/setup.c	Mon Aug 12 16:34:15 2002
@@ -165,15 +165,15 @@
 static int __init conmode_setup(char *str)
 {
 #if defined(CONFIG_HWC_CONSOLE)
-	if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+	if (strncmp(str, "hwc", 4) == 0)
                 SET_CONSOLE_HWC;
 #endif
 #if defined(CONFIG_TN3215_CONSOLE)
-	if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3215", 5) == 0)
 		SET_CONSOLE_3215;
 #endif
 #if defined(CONFIG_TN3270_CONSOLE)
-	if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3270", 5) == 0)
 		SET_CONSOLE_3270;
 #endif
         return 1;
@@ -233,32 +233,63 @@
 	}
 }
 
+#ifdef CONFIG_SMP
+extern void machine_restart_smp(char *);
+extern void machine_halt_smp(void);
+extern void machine_power_off_smp(void);
+
+void (*_machine_restart)(char *command) = machine_restart_smp;
+void (*_machine_halt)(void) = machine_halt_smp;
+void (*_machine_power_off)(void) = machine_power_off_smp;
+#else
 /*
  * Reboot, halt and power_off routines for non SMP.
  */
-
-#ifndef CONFIG_SMP
-void machine_restart(char * __unused)
+static void do_machine_restart_nonsmp(char * __unused)
 {
 	reipl(S390_lowcore.ipl_device);
 }
 
-void machine_halt(void)
+static void do_machine_halt_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
                 cpcmd(vmhalt_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
-void machine_power_off(void)
+static void do_machine_power_off_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
+
+void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
+void (*_machine_halt)(void) = do_machine_halt_nonsmp;
+void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
 #endif
 
 /*
+ * Reboot, halt and power_off stubs. They just call _machine_restart,
+ * _machine_halt or _machine_power_off. 
+ */
+
+void machine_restart(char *command)
+{
+	_machine_restart(command);
+}
+
+void machine_halt(void)
+{
+	_machine_halt();
+}
+
+void machine_power_off(void)
+{
+	_machine_power_off();
+}
+
+/*
  * Setup function called from init/main.c just after the banner
  * was printed.
  */
@@ -497,7 +528,7 @@
 	}
 	if (cpu_online_map & (1 << n)) {
 		cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
-		seq_printf(m, "processor %i: "
+		seq_printf(m, "processor %li: "
 			       "version = %02X,  "
 			       "identification = %06X,  "
 			       "machine = %04X\n",
diff -urN linux-2.4.20-pre1/arch/s390/kernel/signal.c linux-2.4.20-pre2/arch/s390/kernel/signal.c
--- linux-2.4.20-pre1/arch/s390/kernel/signal.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/kernel/signal.c	Mon Aug 12 16:34:15 2002
@@ -335,6 +335,10 @@
 			goto give_sigsegv;
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -388,6 +392,10 @@
 	                          (u16 *)(frame->retcode));
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
diff -urN linux-2.4.20-pre1/arch/s390/kernel/smp.c linux-2.4.20-pre2/arch/s390/kernel/smp.c
--- linux-2.4.20-pre1/arch/s390/kernel/smp.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/kernel/smp.c	Mon Aug 12 16:34:15 2002
@@ -176,61 +176,132 @@
 	return 0;
 }
 
+static inline void do_send_stop(void)
+{
+        u32 dummy;
+        int i;
+
+        /* stop all processors */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   0,
+                                   i,
+                                   sigp_stop);
+                        } while(ccode == sigp_busy);
+                }
+        }
+}
+
+static inline void do_store_status(void)
+{
+        unsigned long low_core_addr;
+        u32 dummy;
+        int i;
+
+        /* store status of all processors in their lowcores (real 0) */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   low_core_addr,
+                                   i,
+                                   sigp_store_status_at_address);
+                        } while(ccode == sigp_busy);
+                }
+        }
+}
 
 /*
- * Various special callbacks
+ * this function sends a 'stop' sigp to all other CPUs in the system.
+ * it goes straight through.
  */
+void smp_send_stop(void)
+{
+        /* write magic number to zero page (absolute 0) */
+        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
+
+	/* stop other processors. */
+	do_send_stop();
+
+	/* store status of other processors. */
+	do_store_status();
+}
 
-void do_machine_restart(void)
+/*
+ * Reboot, halt and power_off routines for SMP.
+ */
+static volatile unsigned long cpu_restart_map;
+
+static void do_machine_restart(void * __unused)
 {
-        smp_send_stop();
-	reipl(S390_lowcore.ipl_device);
+	clear_bit(smp_processor_id(), &cpu_restart_map);
+	if (smp_processor_id() == 0) {
+		/* Wait for all other cpus to enter do_machine_restart. */
+		while (cpu_restart_map != 0);
+		/* Store status of other cpus. */
+		do_store_status();
+		/*
+		 * Finally call reipl. Because we waited for all other
+		 * cpus to enter this function we know that they do
+		 * not hold any s390irq-locks (the cpus have been
+		 * interrupted by an external interrupt and s390irq
+		 * locks are always held disabled).
+		 */
+		reipl(S390_lowcore.ipl_device);
+	}
+	signal_processor(smp_processor_id(), sigp_stop);
 }
 
-void machine_restart(char * __unused) 
+void machine_restart_smp(char * __unused) 
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_restart);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_restart();
+	cpu_restart_map = cpu_online_map;
+        smp_call_function(do_machine_restart, NULL, 0, 0);
+	do_machine_restart(NULL);
 }
 
-void do_machine_halt(void)
+static void do_machine_halt(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-                cpcmd(vmhalt_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+			cpcmd(vmhalt_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_halt(void)
+void machine_halt_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_halt);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_halt();
+        smp_call_function(do_machine_halt, NULL, 0, 0);
+	do_machine_halt(NULL);
 }
 
-void do_machine_power_off(void)
+static void do_machine_power_off(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-                cpcmd(vmpoff_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+			cpcmd(vmpoff_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_power_off(void)
+void machine_power_off_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_power_off);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_power_off();
+        smp_call_function(do_machine_power_off, NULL, 0, 0);
+	do_machine_power_off(NULL);
 }
 
 /*
@@ -247,19 +318,11 @@
          *
          * For the ec_schedule signal we have to do nothing. All the work
          * is done automatically when we return from the interrupt.
-	 * For the ec_restart, ec_halt and ec_power_off we call the
-         * appropriate routine.
          */
         do {
                 bits = atomic_read(&S390_lowcore.ext_call_fast);
         } while (atomic_compare_and_swap(bits,0,&S390_lowcore.ext_call_fast));
 
-        if (test_bit(ec_restart, &bits))
-		do_machine_restart();
-        if (test_bit(ec_halt, &bits))
-		do_machine_halt();
-        if (test_bit(ec_power_off, &bits))
-		do_machine_power_off();
 	if (test_bit(ec_call_function, &bits)) 
 		do_call_function();
 }
@@ -288,7 +351,6 @@
 static void smp_ext_bitcall_others(ec_bit_sig sig)
 {
         struct _lowcore *lowcore;
-        sigp_ccode ccode;
         int i;
 
         for (i = 0; i < smp_num_cpus; i++) {
@@ -304,53 +366,6 @@
         }
 }
 
-/*
- * this function sends a 'stop' sigp to all other CPUs in the system.
- * it goes straight through.
- */
-
-void smp_send_stop(void)
-{
-        int i;
-        u32 dummy;
-        unsigned long low_core_addr;
-
-        /* write magic number to zero page (absolute 0) */
-
-        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
-
-        /* stop all processors */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   0,
-                                   i,
-                                   sigp_stop);
-                        } while(ccode == sigp_busy);
-                }
-        }
-
-        /* store status of all processors in their lowcores (real 0) */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   low_core_addr,
-                                   i,
-                                   sigp_store_status_at_address);
-                        } while(ccode == sigp_busy);
-                }
-        }
-}
-
 /*
  * this function sends a 'purge tlb' signal to another CPU.
  */
diff -urN linux-2.4.20-pre1/arch/s390/kernel/time.c linux-2.4.20-pre2/arch/s390/kernel/time.c
--- linux-2.4.20-pre1/arch/s390/kernel/time.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/kernel/time.c	Mon Aug 12 16:34:15 2002
@@ -39,6 +39,7 @@
 
 #define TICK_SIZE tick
 
+static ext_int_info_t ext_int_info_timer;
 static uint64_t init_timer_cc;
 
 extern rwlock_t xtime_lock;
@@ -224,7 +225,8 @@
         tod_to_timeval(set_time_cc, &xtime);
 
         /* request the 0x1004 external interrupt */
-        if (register_external_interrupt(0x1004, do_comparator_interrupt) != 0)
+        if (register_early_external_interrupt(0x1004, do_comparator_interrupt,
+					      &ext_int_info_timer) != 0)
                 panic("Couldn't request external interrupt 0x1004");
 
         /* init CPU timer */
diff -urN linux-2.4.20-pre1/arch/s390/kernel/traps.c linux-2.4.20-pre2/arch/s390/kernel/traps.c
--- linux-2.4.20-pre1/arch/s390/kernel/traps.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390/kernel/traps.c	Mon Aug 12 16:34:15 2002
@@ -58,6 +58,7 @@
 extern int pfault_init(void);
 extern void pfault_fini(void);
 extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+static ext_int_info_t ext_int_pfault;
 #endif
 
 int kstack_depth_to_print = 12;
@@ -646,7 +647,8 @@
 #ifdef CONFIG_PFAULT
 	if (MACHINE_IS_VM) {
 		/* request the 0x2603 external interrupt */
-		if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+		if (register_early_external_interrupt(0x2603, pfault_interrupt,
+						      &ext_int_pfault) != 0)
 			panic("Couldn't request external interrupt 0x2603");
 		/*
 		 * First try to get pfault pseudo page faults going.
@@ -654,8 +656,9 @@
 		 */
 		if (pfault_init() != 0) {
 			/* Tough luck, no pfault. */
-			unregister_external_interrupt(0x2603,
-						      pfault_interrupt);
+			unregister_early_external_interrupt(0x2603,
+							    pfault_interrupt,
+							    &ext_int_pfault);
 			cpcmd("SET PAGEX ON", NULL, 0);
 		}
 	}
diff -urN linux-2.4.20-pre1/arch/s390x/config.in linux-2.4.20-pre2/arch/s390x/config.in
--- linux-2.4.20-pre1/arch/s390x/config.in	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/config.in	Mon Aug 12 16:34:15 2002
@@ -40,6 +40,8 @@
 mainmenu_option next_comment
 comment 'General setup'
 bool 'Fast IRQ handling' CONFIG_FAST_IRQ
+bool 'Process warning machine checks' CONFIG_MACHCHK_WARNING
+bool 'Use chscs for Common I/O' CONFIG_CHSC
 bool 'Builtin IPL record support' CONFIG_IPL
 if [ "$CONFIG_IPL" = "y" ]; then
   choice 'IPL method generated into head.S' \
@@ -77,3 +79,4 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/s390x/defconfig linux-2.4.20-pre2/arch/s390x/defconfig
--- linux-2.4.20-pre1/arch/s390x/defconfig	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/defconfig	Mon Aug 12 16:34:15 2002
@@ -33,6 +33,8 @@
 # General setup
 #
 CONFIG_FAST_IRQ=y
+CONFIG_MACHCHK_WARNING=y
+CONFIG_CHSC=y
 CONFIG_IPL=y
 # CONFIG_IPL_TAPE is not set
 CONFIG_IPL_VM=y
@@ -146,9 +148,10 @@
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
+CONFIG_SHARED_IPV6_CARDS=y
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
+CONFIG_VLAN_8021Q=m
 
 #
 #  
@@ -163,7 +166,7 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-CONFIG_NET_FASTROUTE=y
+# CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/Makefile linux-2.4.20-pre2/arch/s390x/kernel/Makefile
--- linux-2.4.20-pre1/arch/s390x/kernel/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/Makefile	Mon Aug 12 16:34:15 2002
@@ -34,6 +34,7 @@
 
 .PHONY: asm-offsets.h
 
+entry.S: asm-offsets.h
 #
 # This is just to get the dependencies...
 #
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/debug.c linux-2.4.20-pre2/arch/s390x/kernel/debug.c
--- linux-2.4.20-pre1/arch/s390x/kernel/debug.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/debug.c	Mon Aug 12 16:34:15 2002
@@ -443,6 +443,7 @@
 {
 	size_t count = 0;
 	size_t entry_offset, size = 0;
+	int rc;
 	file_private_info_t *p_info;
 
 	p_info = ((file_private_info_t *) file->private_data);
@@ -458,9 +459,9 @@
 		size = MIN((len - count), (size - entry_offset));
 
 		if(size){
-			if (copy_to_user(user_buf + count, 
-					p_info->temp_buf + entry_offset, size))
-				return count ? count : -EFAULT;
+			if ((rc = copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size)))
+			return rc;
 		}
 		count += size;
 		entry_offset = 0;
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/entry.S linux-2.4.20-pre2/arch/s390x/kernel/entry.S
--- linux-2.4.20-pre1/arch/s390x/kernel/entry.S	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/entry.S	Mon Aug 12 16:34:15 2002
@@ -207,15 +207,15 @@
 # call trace before and after sys_call
 #
 sysc_tracesys:
-	larl	%r12,sysc_return
+	larl	%r11,sysc_return
 
 #
 # call syscall_trace before and after system call
-# special linkage: %r12 contains the return address for trace_svc
+# special linkage: %r11 contains the return address for trace_svc
 #
 trace_svc:
-	lghi    %r7,-ENOSYS
-	stg     %r7,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
+	lghi    %r0,-ENOSYS
+	stg     %r0,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
         brasl   %r14,syscall_trace
 	lg      %r2,SP_R2(%r15)
 	cghi    %r2,-ENOSYS
@@ -232,7 +232,7 @@
 	lg      %r2,SP_ORIG_R2(%r15)
         basr    %r14,%r8            # call sys_xxx
         stg     %r2,SP_R2(%r15)     # store return value
-	lgr	%r14,%r12	    # return point is in %r12
+	lgr	%r14,%r11	    # return point is in %r11
         jg      syscall_trace       # return point is sysc_return
 
 #
@@ -712,7 +712,7 @@
 # call trace before and after sys_call
 #
 pgm_tracesys:
-	larl	%r12,pgm_svcret
+	larl	%r11,pgm_svcret
 	j	trace_svc
 
 /*
@@ -786,26 +786,26 @@
 ext_int_handler:
         SAVE_ALL __LC_EXT_OLD_PSW,0
         GET_CURRENT                    # load pointer to task_struct to R9
-        la      %r2,SP_PTREGS(%r15)    # address of register-save area
-        llgh    %r3,__LC_EXT_INT_CODE  # error code
-        lgr     %r1,%r3                # calculate index = code & 0xff
-	nill    %r1,0xff
-        sll     %r1,3
-        larl    %r4,ext_int_hash
-        lg      %r4,0(%r1,%r4)         # get first list entry for hash value
-        ltgr    %r4,%r4                # == NULL ?
-        jz      io_return              # yes, nothing to do, exit
+	llgh	%r6,__LC_EXT_INT_CODE  # get interruption code
+	lgr	%r1,%r6		       # calculate index = code & 0xff
+	nill	%r1,0xff
+	sll	%r1,3
+	larl	%r7,ext_int_hash
+	lg	%r7,0(%r1,%r7)	       # get first list entry for hash value
+	ltgr	%r7,%r7		       # == NULL ?
+	jz	io_return	       # yes, nothing to do, exit
 ext_int_loop:
-        ch      %r3,16(%r4)            # compare external interrupt code
-        je      ext_int_found
-        lg      %r4,0(%r4)             # next list entry
-	ltgr    %r4,%r4
-        jnz     ext_int_loop
-        j       io_return
-ext_int_found:
-        lg      %r4,8(%r4)             # get handler address
-        larl    %r14,io_return
-        br      %r4                    # branch to ext call handler
+	ch	%r6,16(%r7)	       # compare external interrupt code
+	jne	ext_int_next
+	lg	%r1,8(%r7)	       # get handler address
+	la	%r2,SP_PTREGS(%r15)    # address of register-save area
+	lgr	%r3,%r6		       # interruption code
+	basr	%r14,%r1	       # call handler
+ext_int_next:
+	lg	%r7,0(%r7)	       # next list entry
+	ltgr	%r7,%r7
+	jnz	ext_int_loop
+	j	io_return
 
 /*
  * Machine check handler routines
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/head.S linux-2.4.20-pre2/arch/s390x/kernel/head.S
--- linux-2.4.20-pre1/arch/s390x/kernel/head.S	Fri Nov  9 13:58:02 2001
+++ linux-2.4.20-pre2/arch/s390x/kernel/head.S	Mon Aug 12 16:34:15 2002
@@ -326,7 +326,7 @@
         bnz   .Lrdcont
         st    %r2,INITRD_START+4-PARMAREA(%r12)# no ramdisk found, null it
 .Lrdcont:
-	l     %r2,INITRD_START-PARMAREA(%r12)
+	l     %r2,INITRD_START+4-PARMAREA(%r12)
 	clc   0(3,%r2),.L_hdr		       # skip HDRx and EOFx 
 	bz    .Lagain2
 	clc   0(3,%r2),.L_eof
@@ -555,6 +555,17 @@
 	oi     7(%r12),16               # set MVPG flag
 0:
 
+#
+# find out if the diag 0x44 works in 64 bit mode
+#
+	la     %r1,0f-.LPG1(%r13)	# set program check address
+	stg    %r1,__LC_PGM_NEW_PSW+8
+	mvc    __LC_DIAG44_OPCODE(8),.Lnop-.LPG1(%r13)
+	diag   0,0,0x44			# test diag 0x44
+	oi     7(%r12),32		# set diag44 flag
+	mvc    __LC_DIAG44_OPCODE(8),.Ldiag44-.LPG1(%r13)
+0:	
+
         lpswe .Lentry-.LPG1(13)         # jump to _stext in primary-space,
                                         # virtual and never return ...
         .align 16
@@ -578,6 +589,8 @@
 .Lpcmsk:.quad  0x0000000180000000
 .L4malign:.quad 0xffffffffffc00000
 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
+.Lnop:	.long  0x07000700
+.Ldiag44:.long 0x83000044
 
 	.org PARMAREA-64
 .Lduct:	.long 0,0,0,0,0,0,0,0
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/process.c linux-2.4.20-pre2/arch/s390x/kernel/process.c
--- linux-2.4.20-pre1/arch/s390x/kernel/process.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/process.c	Mon Aug 12 16:34:15 2002
@@ -183,6 +183,43 @@
         return 0;
 }
 
+/* 
+ * Allocation and freeing of basic task resources. 
+ * The task struct and the stack go together.
+ *
+ * NOTE: An order-2 allocation can easily fail.  If this
+ *       happens we fall back to using vmalloc ...
+ */
+
+struct task_struct *alloc_task_struct(void)
+{
+	struct task_struct *tsk = __get_free_pages(GFP_KERNEL, 2);
+	if (!tsk)
+		tsk = vmalloc(16384);
+	if (!tsk)
+		return NULL;
+
+        atomic_set((atomic_t *)(tsk + 1), 1);
+        return tsk;
+}
+
+void free_task_struct(struct task_struct *tsk)
+{
+	if (atomic_dec_and_test((atomic_t *)(tsk + 1)))
+	{
+		if ((unsigned long)tsk < VMALLOC_START)
+			free_pages((unsigned long)tsk, 2);
+		else
+			vfree(tsk);
+	}
+}
+
+void get_task_struct(struct task_struct *tsk)
+{
+	atomic_inc((atomic_t *)(tsk + 1));
+}
+
+
 asmlinkage int sys_fork(struct pt_regs regs)
 {
         return do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/ptrace.c linux-2.4.20-pre2/arch/s390x/kernel/ptrace.c
--- linux-2.4.20-pre1/arch/s390x/kernel/ptrace.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/ptrace.c	Mon Aug 12 16:34:15 2002
@@ -38,6 +38,12 @@
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_S390_SUPPORT
+#include "linux32.h"
+#else
+#define parent_31bit 0
+#endif
+
 
 void FixPerRegisters(struct task_struct *task)
 {
@@ -122,8 +128,8 @@
 				retval = clear_user(copyptr, len);
 			else
 				retval = copy_to_user(copyptr,realuserptr,len);
-                        retval = (retval == -EFAULT) ? -EIO : 0;
 		}      
+		retval = retval ? -EFAULT : 0;
 	} else {
 		if (writeuser)
 			memcpy(realuserptr, copyptr, len);
@@ -135,48 +141,180 @@
 	return retval;
 }
 
+#ifdef CONFIG_S390_SUPPORT
+
+typedef struct
+{
+	__u32 cr[3];
+} per_cr_words32  __attribute__((packed));
+
+typedef struct
+{
+	__u16          perc_atmid;          /* 0x096 */
+	__u32          address;             /* 0x098 */
+	__u8           access_id;           /* 0x0a1 */
+} per_lowcore_words32  __attribute__((packed));
+
+typedef struct
+{
+	union {
+		per_cr_words32   words;
+	} control_regs  __attribute__((packed));
+	/*
+	 * Use these flags instead of setting em_instruction_fetch
+	 * directly they are used so that single stepping can be
+	 * switched on & off while not affecting other tracing
+	 */
+	unsigned  single_step       : 1;
+	unsigned  instruction_fetch : 1;
+	unsigned                    : 30;
+	/*
+	 * These addresses are copied into cr10 & cr11 if single
+	 * stepping is switched off
+	 */
+	__u32     starting_addr;
+	__u32     ending_addr;
+	union {
+		per_lowcore_words32 words;
+	} lowcore; 
+} per_struct32 __attribute__((packed));
+
+struct user_regs_struct32
+{
+	_psw_t32 psw;
+	u32 gprs[NUM_GPRS];
+	u32 acrs[NUM_ACRS];
+	u32 orig_gpr2;
+	s390_fp_regs fp_regs;
+	/*
+	 * These per registers are in here so that gdb can modify them
+	 * itself as there is no "official" ptrace interface for hardware
+	 * watchpoints. This is the way intel does it.
+	 */
+	per_struct32 per_info;
+	u32  ieee_instruction_pointer; 
+	/* Used to give failing instruction back to user for ieee exceptions */
+};
+
+struct user32 {
+                                  /* We start with the registers, to mimic the way that "memory" is returned
+                                   from the ptrace(3,...) function.  */
+  struct user_regs_struct32 regs; /* Where the registers are actually stored */
+                                  /* The rest of this junk is to help gdb figure out what goes where */
+  u32 u_tsize;	                  /* Text segment size (pages). */
+  u32 u_dsize;	                  /* Data segment size (pages). */
+  u32 u_ssize;	                  /* Stack segment size (pages). */
+  u32 start_code;                 /* Starting virtual address of text. */
+  u32 start_stack;	          /* Starting virtual address of stack area.
+				   This is actually the bottom of the stack,
+				   the top of the stack is always found in the
+				   esp register.  */
+  s32 signal;     		  /* Signal that caused the core dump. */
+  u32 u_ar0;                      /* Used by gdb to help find the values for */
+				  /* the registers. */
+  u32 magic;		          /* To uniquely identify a core file */
+  char u_comm[32];		  /* User command that was responsible */
+};
+
+
+#define PT32_PSWMASK  0x0
+#define PT32_PSWADDR  0x04
+#define PT32_GPR0     0x08
+#define PT32_GPR15    0x44
+#define PT32_ACR0     0x48
+#define PT32_ACR15    0x84
+#define PT32_ORIGGPR2 0x88
+#define PT32_FPC      0x90
+#define PT32_FPR0_HI  0x98
+#define PT32_FPR15_LO 0x114
+#define PT32_CR_9     0x118
+#define PT32_CR_11    0x120
+#define PT32_IEEE_IP  0x13C
+#define PT32_LASTOFF  PT32_IEEE_IP
+#define PT32_ENDREGS  0x140-1
+#define U32OFFSETOF(member) offsetof(struct user32,regs.member)
+#define U64OFFSETOF(member) offsetof(struct user,regs.member)
+#define U6432DIFF(member) (U64OFFSETOF(member) - U32OFFSETOF(member))
+#define PT_SINGLE_STEP   (PT_CR_11+8)
+#define PT32_SINGLE_STEP (PT32_CR_11+4)
+
+#endif /* CONFIG_S390_SUPPORT */
+
 int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr,
               int len, int tofromuser, int writingtouser)
 {
 	int copylen=0,copymax;
 	addr_t  realuseraddr;
 	saddr_t enduseraddr;
-	
 	unsigned long mask;
-
 #ifdef CONFIG_S390_SUPPORT
-	if (current->thread.flags & S390_FLAG_31BIT) {
-	/* adjust user offsets to 64 bit structure */
-		if (useraddr < PT_PSWADDR / 2)
-			useraddr = 2 * useraddr;
-		else if(useraddr < PT_ACR0 / 2)
-			useraddr = 2 * useraddr + sizeof(addr_t) / 2;
-		else if(useraddr < PT_ACR0 / 2 + (PT_ORIGGPR2 - PT_ACR0))
-			useraddr = useraddr + PT_ACR0 / 2;
-		else if(useraddr < PT_ACR0 / 2 + (sizeof(struct user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0))
-			useraddr = useraddr + PT_ACR0 / 2 + sizeof(addr_t) / 2; 
-        }
-#endif  
-    
+	int     parent_31bit=current->thread.flags & S390_FLAG_31BIT;
+	int     skip;
+#endif
 	enduseraddr=useraddr+len;
-
-	if (useraddr < 0 || enduseraddr > sizeof(struct user)||
-	   (useraddr < PT_ENDREGS && (useraddr&3))||
-	   (enduseraddr < PT_ENDREGS && (enduseraddr&3)))
+	if ((useraddr<0||useraddr&3||enduseraddr&3)||
+#ifdef CONFIG_S390_SUPPORT
+	    (parent_31bit && enduseraddr > sizeof(struct user32)) ||
+#endif
+	    enduseraddr > sizeof(struct user))
 		return (-EIO);
+
+#ifdef CONFIG_S390_SUPPORT
+	if(parent_31bit)
+	{
+		if(useraddr != PT32_PSWMASK)
+		{
+			if (useraddr == PT32_PSWADDR)
+				useraddr = PT_PSWADDR+4;
+			else if(useraddr <= PT32_GPR15)
+				useraddr = ((useraddr-PT32_GPR0)*2) + PT_GPR0+4;
+			else if(useraddr <= PT32_ACR15)
+				useraddr += PT_ACR0-PT32_ACR0;
+			else if(useraddr == PT32_ORIGGPR2)
+				useraddr = PT_ORIGGPR2+4;
+			else if(useraddr <= PT32_FPR15_LO)
+				useraddr += PT_FPR0-PT32_FPR0_HI;
+			else if(useraddr <= PT32_CR_11)
+				useraddr = ((useraddr-PT32_CR_9)*2) + PT_CR_9+4;
+			else if(useraddr ==  PT32_SINGLE_STEP)
+				useraddr = PT_SINGLE_STEP; 
+			else if(useraddr <= U32OFFSETOF(per_info.ending_addr))	
+				useraddr = (((useraddr-U32OFFSETOF(per_info.starting_addr)))*2) + 
+					U64OFFSETOF(per_info.starting_addr)+4;
+			else if( useraddr == U32OFFSETOF(per_info.lowcore.words.perc_atmid))
+				useraddr = U64OFFSETOF(per_info.lowcore.words.perc_atmid);
+			else if( useraddr == U32OFFSETOF(per_info.lowcore.words.address))
+				useraddr = U64OFFSETOF(per_info.lowcore.words.address)+4;
+			else if(useraddr == U32OFFSETOF(per_info.lowcore.words.access_id))
+				useraddr = U64OFFSETOF(per_info.lowcore.words.access_id);
+			else if(useraddr == PT32_IEEE_IP)
+				useraddr = PT_IEEE_IP+4;
+		}
+	}
+#endif /* CONFIG_S390_SUPPORT */
+
 	while(len>0)
 	{
+#ifdef CONFIG_S390_SUPPORT
+		skip=0;
+#endif
 		mask=PSW_ADDR_MASK;
 		if(useraddr<PT_FPC)
 		{
 			realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr;
-			if(useraddr<PT_PSWMASK)
-			{
-				copymax=PT_PSWMASK;
-			}
-			else if(useraddr<(PT_PSWMASK+8))
+			if(useraddr<(PT_PSWMASK+8))
 			{
-				copymax=(PT_PSWMASK+8);
+				if(parent_31bit)
+				{
+					copymax=PT_PSWMASK+4;
+#ifdef CONFIG_S390_SUPPORT
+					skip=8;
+#endif
+				}
+				else
+				{
+					copymax=PT_PSWMASK+8;
+				}
 				if(writingtouser)
 					mask=PSW_MASK_DEBUGCHANGE;
 			}
@@ -184,10 +322,25 @@
 			{
 				copymax=PT_PSWADDR+8;
 				mask=PSW_ADDR_DEBUGCHANGE;
+#ifdef CONFIG_S390_SUPPORT
+				if(parent_31bit)
+					skip=4;
+#endif
+
 			}
 			else
-				copymax=PT_FPC;
-			
+			{
+#ifdef CONFIG_S390_SUPPORT
+				if(parent_31bit && useraddr <= PT_GPR15+4)
+				{
+					copymax=useraddr+4;
+					if(useraddr<PT_GPR15+4)
+						skip=4;
+				}
+				else
+#endif
+					copymax=PT_FPC;
+			}
 		}
 		else if(useraddr<(PT_FPR15+sizeof(freg_t)))
 		{
@@ -196,7 +349,33 @@
 		}
 		else if(useraddr<sizeof(struct user_regs_struct))
 		{
-			copymax=sizeof(struct user_regs_struct);
+#ifdef CONFIG_S390_SUPPORT
+			if( parent_31bit && useraddr <= PT_IEEE_IP+4)
+			{
+				switch(useraddr)
+				{
+				case PT_CR_11+4:
+				case U64OFFSETOF(per_info.ending_addr)+4:
+				case U64OFFSETOF(per_info.lowcore.words.address)+4:
+					copymax=useraddr+4;
+					break;
+				case  PT_SINGLE_STEP:
+				case  U64OFFSETOF(per_info.lowcore.words.perc_atmid):
+					/* We copy 2 bytes in excess for the atmid member this also gets around */
+					/* alignment for this member in 32 bit */
+					skip=8;
+					copymax=useraddr+4;
+					break;
+				default: 
+					copymax=useraddr+4;
+					skip=4;
+				}
+			}
+			else
+#endif
+			{
+				copymax=sizeof(struct user_regs_struct);
+			}
 			realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
 		}
 		else 
@@ -210,7 +389,11 @@
 			return (-EIO);
 		copyaddr+=copylen;
 		len-=copylen;
-		useraddr+=copylen;
+		useraddr+=copylen
+#if CONFIG_S390_SUPPORT
+			+skip
+#endif
+			;
 	}
 	FixPerRegisters(task);
 	return(0);
@@ -227,150 +410,6 @@
 	clear_single_step(child);
 }
 
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
-{
-	struct task_struct *child;
-	int ret = -EPERM;
-	unsigned long flags;
-	unsigned long tmp;
-	int copied;
-	ptrace_area   parea; 
-
-	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);
-	read_unlock(&tasklist_lock);
-	if (!child)
-		goto out;
-	ret = -EPERM;
-	if (pid == 1)		/* you may not mess with init */
-		goto out;
-	if (request == PTRACE_ATTACH) 
-	{
-		ret = ptrace_attach(child);
-		goto out;
-	}
-	ret = -ESRCH;
-	// printk("child=%lX child->flags=%lX",child,child->flags);
-	/* I added child!=current line so we can get the */
-	/* ieee_instruction_pointer from the user structure DJB */
-	if(child!=current)
-	{
-		if (!(child->ptrace & PT_PTRACED))
-			goto out;
-		if (child->state != TASK_STOPPED) 
-		{
-			if (request != PTRACE_KILL)
-				goto out;
-		}
-		if (child->p_pptr != current)
-			goto out;
-	}
-	switch (request) 
-	{
-		/* If I and D space are separate, these will need to be fixed. */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-	case PTRACE_PEEKDATA: 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-		ret = -EIO;
-		if (copied != sizeof(tmp))
-			goto out;
-		ret = put_user(tmp,(unsigned long *) data);
-		goto out;
-
-		/* read the word at location addr in the USER area. */
-	case PTRACE_PEEKUSR:
-		ret=copy_user(child,addr,data,sizeof(unsigned long),1,0);
-		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))
-			goto out;
-		ret = -EIO;
-		goto out;
-		break;
-
-	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-		ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned long),0,1);
-		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;
-		clear_single_step(child);
-		wake_up_process(child);
-		/* make sure the single step bit is not set. */
-		break;
-
-	case PTRACE_SINGLESTEP:  /* set the trap flag. */
-		ret = -EIO;
-		if ((unsigned long) data >= _NSIG)
-			break;
-		child->ptrace &= ~PT_TRACESYS;
-		child->exit_code = data;
-		set_single_step(child);
-		/* give it a chance to run. */
-		wake_up_process(child);
-		ret = 0;
-		break;
-
-	case PTRACE_DETACH:  /* detach a process that was attached. */
-		ret = ptrace_detach(child, data);
-		break;
-
-	case PTRACE_PEEKUSR_AREA:
-	case PTRACE_POKEUSR_AREA:
-		if(copy_from_user(&parea,(void *)addr,sizeof(parea)) == 0)  
-			ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
-		else ret = -EFAULT;
-		break;
-	default:
-		ret = -EIO;
-		break;
-	}
- out:
-	unlock_kernel();
-	return ret;
-}
-
 typedef struct
 {
 __u32	len;
@@ -378,15 +417,20 @@
 __u32	process_addr;
 } ptrace_area_emu31;
 
-asmlinkage int sys32_ptrace(long request, long pid, long addr, s32 data)
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
 	int ret = -EPERM;
-	unsigned long flags;
-	u32 tmp;
 	int copied;
-	ptrace_area   parea; 
-
+#ifdef CONFIG_S390_SUPPORT
+	int           parent_31bit;
+	int           sizeof_parent_long;
+	u8            *dataptr;
+#else
+#define sizeof_parent_long 8
+#define dataptr (u8 *)&data
+#endif
 	lock_kernel();
 	if (request == PTRACE_TRACEME) 
 	{
@@ -401,16 +445,18 @@
 	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;
+		goto out_tsk;
 	if (request == PTRACE_ATTACH) 
 	{
 		ret = ptrace_attach(child);
-		goto out;
+		goto out_tsk;
 	}
 	ret = -ESRCH;
 	// printk("child=%lX child->flags=%lX",child,child->flags);
@@ -419,44 +465,52 @@
 	if(child!=current)
 	{
 		if (!(child->ptrace & PT_PTRACED))
-			goto out;
+			goto out_tsk;
 		if (child->state != TASK_STOPPED) 
 		{
 			if (request != PTRACE_KILL)
-				goto out;
+				goto out_tsk;
 		}
 		if (child->p_pptr != current)
-			goto out;
+			goto out_tsk;
 	}
+#ifdef CONFIG_S390_SUPPORT
+	parent_31bit=(current->thread.flags & S390_FLAG_31BIT);
+	sizeof_parent_long=(parent_31bit ? 4:8);
+	dataptr=&(((u8 *)&data)[parent_31bit ? 4:0]);
+#endif
 	switch (request) 
 	{
 		/* If I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 	case PTRACE_PEEKDATA: 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+	{
+		u8 tmp[8];
+		copied = access_process_vm(child, addr, tmp, sizeof_parent_long, 0);
 		ret = -EIO;
-		if (copied != sizeof(tmp))
-			goto out;
-		ret = put_user(tmp,(u32 *)(unsigned long)data);
-		goto out;
-
+		if (copied != sizeof_parent_long)
+			break;
+		ret = copy_to_user((void *)data,tmp,sizeof_parent_long);
+		ret = ret ? -EFAULT : 0;
+		break;
+	
+	}
 		/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR:
-		ret=copy_user(child,addr,data,sizeof(u32),1,0);
+		ret=copy_user(child,addr,data,sizeof_parent_long,1,0);
 		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))
-			goto out;
+		if (access_process_vm(child, addr,dataptr, sizeof_parent_long, 1) == sizeof_parent_long)
+			break;
 		ret = -EIO;
-		goto out;
 		break;
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-		ret=copy_user(child,addr,(addr_t)&data,sizeof(u32),0,1);
+		ret=copy_user(child,addr,(addr_t)dataptr,sizeof_parent_long,0,1);
 		break;
 
 	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
@@ -503,44 +557,41 @@
 		break;
 
 	case PTRACE_DETACH:  /* detach a process that was attached. */
-		ret = -EIO;
-		if ((unsigned long) data >= _NSIG)
-			break;
-		child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-		child->exit_code = data;
-		write_lock_irqsave(&tasklist_lock, flags);
-		REMOVE_LINKS(child);
-		child->p_pptr = child->p_opptr;
-		SET_LINKS(child);
-		write_unlock_irqrestore(&tasklist_lock, flags);
-		/* make sure the single step bit is not set. */
-		clear_single_step(child);
-		wake_up_process(child);
-		ret = 0;
+		ret = ptrace_detach(child, data);
 		break;
+
 	case PTRACE_PEEKUSR_AREA:
 	case PTRACE_POKEUSR_AREA:
+		if(parent_31bit)
 		{
-		ptrace_area_emu31 * parea31 = (void *)addr;
-		if (!access_ok(VERIFY_READ, parea31, sizeof(*parea31)))
-			return(-EFAULT);
-		ret = __get_user(parea.len, &parea31->len);
-		ret |= __get_user(parea.kernel_addr, &parea31->kernel_addr);
-		ret |= __get_user(parea.process_addr, &parea31->process_addr);
-		if(ret==0)  
-		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
-		break;
+			ptrace_area_emu31   parea; 
+			if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)
+				ret=copy_user(child,parea.kernel_addr,parea.process_addr,
+					      parea.len,1,(request==PTRACE_POKEUSR_AREA));
+			else ret = -EFAULT;
 		}
+		else
+		{
+			ptrace_area   parea; 
+			if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)
+				ret=copy_user(child,parea.kernel_addr,parea.process_addr,
+					      parea.len,1,(request==PTRACE_POKEUSR_AREA));
+			else ret = -EFAULT;
+		}
+		break;
 	default:
 		ret = -EIO;
 		break;
 	}
+ out_tsk:
+	free_task_struct(child);
  out:
 	unlock_kernel();
 	return ret;
 }
 
+
+
 asmlinkage void syscall_trace(void)
 {
 	lock_kernel();
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/s390_ext.c linux-2.4.20-pre2/arch/s390x/kernel/s390_ext.c
--- linux-2.4.20-pre1/arch/s390x/kernel/s390_ext.c	Wed Jul 25 14:12:01 2001
+++ linux-2.4.20-pre2/arch/s390x/kernel/s390_ext.c	Mon Aug 12 16:34:15 2002
@@ -21,34 +21,31 @@
  * iucv and 0x2603 pfault) this is always the first element. 
  */
 ext_int_info_t *ext_int_hash[256] = { 0, };
-ext_int_info_t ext_int_info_timer;
-ext_int_info_t ext_int_info_hwc;
-ext_int_info_t ext_int_pfault;
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
         ext_int_info_t *p;
         int index;
 
-        index = code & 0xff;
-        p = ext_int_hash[index];
-        while (p != NULL) {
-                if (p->code == code)
-                        return -EBUSY;
-                p = p->next;
-        }
-        if (code == 0x1004) /* time_init is done before kmalloc works :-/ */
-                p = &ext_int_info_timer;
-        else if (code == 0x2401) /* hwc_init is done too early too */
-                p = &ext_int_info_hwc;
-        else if (code == 0x2603) /* pfault_init is done too early too */
-                p = &ext_int_pfault;
-        else
-                p = (ext_int_info_t *)
-                          kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
+	p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
         if (p == NULL)
                 return -ENOMEM;
         p->code = code;
         p->handler = handler;
+        index = code & 0xff;
+        p->next = ext_int_hash[index];
+        ext_int_hash[index] = p;
+        return 0;
+}
+
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *p) {
+        int index;
+
+        if (p == NULL)
+                return -EINVAL;
+        p->code = code;
+        p->handler = handler;
+        index = code & 0xff;
         p->next = ext_int_hash[index];
         ext_int_hash[index] = p;
         return 0;
@@ -73,11 +70,33 @@
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
-                kfree(p);
+	kfree(p);
         return 0;
 }
 
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *p) {
+	ext_int_info_t *q;
+	int index;
+
+	if (p == NULL || p->code != code || p->handler != handler)
+		return -EINVAL;
+	index = code & 0xff;
+	q = ext_int_hash[index];
+	if (p != q) {
+		while (q != NULL) {
+			if (q->next == p)
+				break;
+			q = q->next;
+		}
+		if (q == NULL)
+			return -ENOENT;
+		q->next = p->next;
+	} else
+		ext_int_hash[index] = p->next;
+	return 0;
+}
+
 EXPORT_SYMBOL(register_external_interrupt);
 EXPORT_SYMBOL(unregister_external_interrupt);
 
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/s390_ksyms.c linux-2.4.20-pre2/arch/s390x/kernel/s390_ksyms.c
--- linux-2.4.20-pre1/arch/s390x/kernel/s390_ksyms.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/s390_ksyms.c	Mon Aug 12 16:34:15 2002
@@ -12,6 +12,7 @@
 #include <asm/delay.h>
 #include <asm/pgalloc.h>
 #include <asm/setup.h>
+#include <asm/softirq.h>
 #if CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/setup.c linux-2.4.20-pre2/arch/s390x/kernel/setup.c
--- linux-2.4.20-pre1/arch/s390x/kernel/setup.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/setup.c	Mon Aug 12 16:34:15 2002
@@ -165,15 +165,15 @@
 static int __init conmode_setup(char *str)
 {
 #if defined(CONFIG_HWC_CONSOLE)
-	if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+	if (strncmp(str, "hwc", 4) == 0)
                 SET_CONSOLE_HWC;
 #endif
 #if defined(CONFIG_TN3215_CONSOLE)
-	if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3215", 5) == 0)
 		SET_CONSOLE_3215;
 #endif
 #if defined(CONFIG_TN3270_CONSOLE)
-	if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3270", 5) == 0)
 		SET_CONSOLE_3270;
 #endif
         return 1;
@@ -233,31 +233,63 @@
 	}
 }
 
+#ifdef CONFIG_SMP
+extern void machine_restart_smp(char *);
+extern void machine_halt_smp(void);
+extern void machine_power_off_smp(void);
+
+void (*_machine_restart)(char *command) = machine_restart_smp;
+void (*_machine_halt)(void) = machine_halt_smp;
+void (*_machine_power_off)(void) = machine_power_off_smp;
+#else
 /*
  * Reboot, halt and power_off routines for non SMP.
  */
-#ifndef CONFIG_SMP
-void machine_restart(char * __unused)
+static void do_machine_restart_nonsmp(char * __unused)
 {
 	reipl(S390_lowcore.ipl_device);
 }
 
-void machine_halt(void)
+static void do_machine_halt_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
                 cpcmd(vmhalt_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
-void machine_power_off(void)
+static void do_machine_power_off_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
+
+void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
+void (*_machine_halt)(void) = do_machine_halt_nonsmp;
+void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
 #endif
 
 /*
+ * Reboot, halt and power_off stubs. They just call _machine_restart,
+ * _machine_halt or _machine_power_off. 
+ */
+
+void machine_restart(char *command)
+{
+	_machine_restart(command);
+}
+
+void machine_halt(void)
+{
+	_machine_halt();
+}
+
+void machine_power_off(void)
+{
+	_machine_power_off();
+}
+
+/*
  * Setup function called from init/main.c just after the banner
  * was printed.
  */
@@ -429,6 +461,10 @@
 	lowcore->async_stack = (__u64)
 		__alloc_bootmem(4*PAGE_SIZE, 4*PAGE_SIZE, 0) + 16384;
 	lowcore->jiffy_timer = -1LL;
+	if (MACHINE_HAS_DIAG44)
+		lowcore->diag44_opcode = 0x83000044;
+	else
+		lowcore->diag44_opcode = 0x07000700;
 	set_prefix((__u32)(__u64) lowcore);
         cpu_init();
         boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
@@ -486,7 +522,7 @@
 	}
 	if (cpu_online_map & (1 << n)) {
 		cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
-		seq_printf(m, "processor %i: "
+		seq_printf(m, "processor %li: "
 				"version = %02X,  "
 				"identification = %06X,  "
 				"machine = %04X\n",
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/signal.c linux-2.4.20-pre2/arch/s390x/kernel/signal.c
--- linux-2.4.20-pre1/arch/s390x/kernel/signal.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/signal.c	Mon Aug 12 16:34:15 2002
@@ -333,6 +333,10 @@
 			goto give_sigsegv;
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -386,6 +390,10 @@
 	                          (u16 *)(frame->retcode));
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -567,7 +575,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.20-pre1/arch/s390x/kernel/smp.c linux-2.4.20-pre2/arch/s390x/kernel/smp.c
--- linux-2.4.20-pre1/arch/s390x/kernel/smp.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/smp.c	Mon Aug 12 16:34:15 2002
@@ -176,61 +176,137 @@
 	return 0;
 }
 
+static inline void do_send_stop(void)
+{
+        u32 dummy;
+        int i;
+
+        /* stop all processors */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   0,
+                                   i,
+                                   sigp_stop);
+                        } while(ccode == sigp_busy);
+                }
+        }
+}
+
+static inline void do_store_status(void)
+{
+        unsigned long low_core_addr;
+        u32 dummy;
+        int i;
+
+        /* store status of all processors in their lowcores (real 0) */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() != i) {
+                        int ccode;
+                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
+                        do {
+                                ccode = signal_processor_ps(
+                                   &dummy,
+                                   low_core_addr,
+                                   i,
+                                   sigp_store_status_at_address);
+                        } while(ccode == sigp_busy);
+                }
+        }
+}
 
 /*
- * Various special callbacks
+ * this function sends a 'stop' sigp to all other CPUs in the system.
+ * it goes straight through.
  */
+void smp_send_stop(void)
+{
+        int i;
+        u32 dummy;
+        unsigned long low_core_addr;
+
+        /* write magic number to zero page (absolute 0) */
+        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
+
+	/* stop other processors. */
+	do_send_stop();
+
+	/* store status of other processors. */
+	do_store_status();
+}
 
-void do_machine_restart(void)
+
+/*
+ * Reboot, halt and power_off routines for SMP.
+ */
+static volatile unsigned long cpu_restart_map;
+
+static void do_machine_restart(void * __unused)
 {
-        smp_send_stop();
-	reipl(S390_lowcore.ipl_device);
+	clear_bit(smp_processor_id(), &cpu_restart_map);
+	if (smp_processor_id() == 0) {
+		/* Wait for all other cpus to enter do_machine_restart. */
+		while (cpu_restart_map != 0);
+		/* Store status of other cpus. */
+		do_store_status();
+		/*
+		 * Finally call reipl. Because we waited for all other
+		 * cpus to enter this function we know that they do
+		 * not hold any s390irq-locks (the cpus have been
+		 * interrupted by an external interrupt and s390irq
+		 * locks are always held disabled).
+		 */
+		reipl(S390_lowcore.ipl_device);
+	}
+	signal_processor(smp_processor_id(), sigp_stop);
 }
 
-void machine_restart(char * __unused) 
+void machine_restart_smp(char * __unused) 
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_restart);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_restart();
+	cpu_restart_map = cpu_online_map;
+        smp_call_function(do_machine_restart, NULL, 0, 0);
+	do_machine_restart(NULL);
 }
 
-void do_machine_halt(void)
+static void do_machine_halt(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-                cpcmd(vmhalt_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+			cpcmd(vmhalt_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_halt(void)
+void machine_halt_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_halt);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_halt();
+        smp_call_function(do_machine_halt, NULL, 0, 0);
+	do_machine_halt(NULL);
 }
 
-void do_machine_power_off(void)
+static void do_machine_power_off(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-                cpcmd(vmpoff_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+			cpcmd(vmpoff_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_power_off(void)
+void machine_power_off_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_power_off);
-		for (;;)
-			enabled_wait();
-        } else
-                do_machine_power_off();
+        smp_call_function(do_machine_power_off, NULL, 0, 0);
+	do_machine_power_off(NULL);
 }
 
 /*
@@ -247,17 +323,9 @@
          *
          * For the ec_schedule signal we have to do nothing. All the work
          * is done automatically when we return from the interrupt.
-	 * For the ec_restart, ec_halt and ec_power_off we call the
-         * appropriate routine.
          */
 	bits = xchg(&S390_lowcore.ext_call_fast, 0);
 
-        if (test_bit(ec_restart, &bits))
-		do_machine_restart();
-        if (test_bit(ec_halt, &bits))
-		do_machine_halt();
-        if (test_bit(ec_power_off, &bits))
-		do_machine_power_off();
         if (test_bit(ec_call_function, &bits))
 		do_call_function();
 }
@@ -299,53 +367,6 @@
         }
 }
 
-/*
- * this function sends a 'stop' sigp to all other CPUs in the system.
- * it goes straight through.
- */
-
-void smp_send_stop(void)
-{
-        int i;
-        u32 dummy;
-        unsigned long low_core_addr;
-
-        /* write magic number to zero page (absolute 0) */
-
-        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
-
-        /* stop all processors */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   0,
-                                   i,
-                                   sigp_stop);
-                        } while(ccode == sigp_busy);
-                }
-        }
-
-        /* store status of all processors in their lowcores (real 0) */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        low_core_addr = (unsigned long)get_cpu_lowcore(i);
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   low_core_addr,
-                                   i,
-                                   sigp_store_status_at_address);
-                        } while(ccode == sigp_busy);
-                }
-        }
-}
-
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/sys_s390.c linux-2.4.20-pre2/arch/s390x/kernel/sys_s390.c
--- linux-2.4.20-pre1/arch/s390x/kernel/sys_s390.c	Wed Apr 11 19:02:29 2001
+++ linux-2.4.20-pre2/arch/s390x/kernel/sys_s390.c	Mon Aug 12 16:34:15 2002
@@ -24,6 +24,7 @@
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
+#include <linux/personality.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -203,3 +204,30 @@
 	return -ERESTARTNOHAND;
 }
 
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+
+asmlinkage int s390x_newuname(struct new_utsname * name)
+{
+	int ret = sys_newuname(name);
+
+	if (current->personality == PER_LINUX32 && !ret) {
+		ret = copy_to_user(name->machine, "s390\0\0\0\0", 8);
+		if (ret) ret = -EFAULT;
+	}
+	return ret;
+}
+
+extern asmlinkage long sys_personality(unsigned long);
+
+asmlinkage int s390x_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;
+}
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/time.c linux-2.4.20-pre2/arch/s390x/kernel/time.c
--- linux-2.4.20-pre1/arch/s390x/kernel/time.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/time.c	Mon Aug 12 16:34:15 2002
@@ -39,6 +39,7 @@
 
 #define TICK_SIZE tick
 
+static ext_int_info_t ext_int_info_timer;
 static uint64_t init_timer_cc;
 
 extern rwlock_t xtime_lock;
@@ -197,7 +198,8 @@
         tod_to_timeval(set_time_cc, &xtime);
 
         /* request the 0x1004 external interrupt */
-        if (register_external_interrupt(0x1004, do_comparator_interrupt) != 0)
+        if (register_early_external_interrupt(0x1004, do_comparator_interrupt,
+					      &ext_int_info_timer) != 0)
                 panic("Couldn't request external interrupt 0x1004");
 
         /* init CPU timer */
diff -urN linux-2.4.20-pre1/arch/s390x/kernel/traps.c linux-2.4.20-pre2/arch/s390x/kernel/traps.c
--- linux-2.4.20-pre1/arch/s390x/kernel/traps.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/kernel/traps.c	Mon Aug 12 16:34:15 2002
@@ -60,6 +60,7 @@
 extern int pfault_init(void);
 extern void pfault_fini(void);
 extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+static ext_int_info_t ext_int_pfault;
 #endif
 
 int kstack_depth_to_print = 20;
@@ -499,15 +500,17 @@
 #ifdef CONFIG_PFAULT
 	if (MACHINE_IS_VM) {
 		/* request the 0x2603 external interrupt */
-		if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+		if (register_early_external_interrupt(0x2603, pfault_interrupt,
+						      &ext_int_pfault) != 0)
 			panic("Couldn't request external interrupt 0x2603");
 		/*
 		 * Try to get pfault pseudo page faults going.
 		 */
 		if (pfault_init() != 0) {
 			/* Tough luck, no pfault. */
-			unregister_external_interrupt(0x2603,
-						      pfault_interrupt);
+			unregister_early_external_interrupt(0x2603,
+							    pfault_interrupt,
+							    &ext_int_pfault);
 		}
 	}
 #endif
diff -urN linux-2.4.20-pre1/arch/s390x/mm/init.c linux-2.4.20-pre2/arch/s390x/mm/init.c
--- linux-2.4.20-pre1/arch/s390x/mm/init.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/s390x/mm/init.c	Mon Aug 12 16:34:15 2002
@@ -44,6 +44,74 @@
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
+pmd_t *pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+{
+        unsigned long addr = (unsigned long) pgd;
+        unsigned long *pgd_slot =  (unsigned long *) (addr & -8);
+        unsigned long offset = addr & 4;
+	pmd_t *new, *pmd2;
+	int i;
+ 
+        if (offset == 0 && 
+	    ((*pgd_slot & _PGD_ENTRY_INV) != 0 ||
+	     (*pgd_slot & _PGD_ENTRY_LEN(2)) == 0)) {
+                /* Set lower pmd, upper pmd is empty. */
+                *pgd_slot = __pa(pmd) | _PGD_ENTRY_MASK |
+                                _PGD_ENTRY_OFF(0) | _PGD_ENTRY_LEN(1);
+                return pmd;
+        }
+        if (offset == 4 &&
+	    ((*pgd_slot & _PGD_ENTRY_INV) != 0 ||
+	     (*pgd_slot & _PGD_ENTRY_OFF(2)) != 0)) {
+                /* Lower pmd empty, set upper pmd. */
+                *pgd_slot = (__pa(pmd) - 0x2000) | _PGD_ENTRY_MASK |
+                                _PGD_ENTRY_OFF(2) | _PGD_ENTRY_LEN(3);
+                return pmd;
+        }
+        /* We have to enlarge the pmd to 16K if we arrive here. */
+	new = (pmd_t *) __get_free_pages(GFP_KERNEL, 2);
+	if (new == NULL) {
+		pmd_free(pmd);
+		return NULL;
+	}
+	/* Set the PG_arch_1 bit on the first and the third pmd page
+           so that pmd_free_fast can recognize pmds that have been
+           allocated with an order 2 allocation.  */
+	set_bit(PG_arch_1, &virt_to_page(new)->flags);
+	set_bit(PG_arch_1, &virt_to_page(new+PTRS_PER_PMD)->flags);
+	/* Now copy the two pmds to the new memory area. */
+	if (offset == 0) {
+		pmd2 = (pmd_t *)(*pgd_slot & PAGE_MASK) + PTRS_PER_PMD;
+		memcpy(new, pmd, sizeof(pmd_t)*PTRS_PER_PMD);
+		memcpy(new + PTRS_PER_PMD, pmd2, sizeof(pmd_t)*PTRS_PER_PMD);
+	} else {
+		pmd2 = (pmd_t *)(*pgd_slot & PAGE_MASK);
+		memcpy(new, pmd2, sizeof(pmd_t)*PTRS_PER_PMD);
+		memcpy(new + PTRS_PER_PMD, pmd, sizeof(pmd_t)*PTRS_PER_PMD);
+	}
+	*pgd_slot = __pa(new) | _PGD_ENTRY_MASK |
+			_PGD_ENTRY_OFF(0) | _PGD_ENTRY_LEN(3);
+	for (i = 0; i < PTRS_PER_PMD; i++) {
+		pmd_clear(pmd + i);
+		pmd_clear(pmd2 + i);
+	}
+	pmd_free(pmd);
+	pmd_free(pmd2);
+	return new;
+}
+
+void pmd_free_order2(pmd_t *pmd)
+{
+	pmd_t *pmd2 = (pmd_t *) ((unsigned long) pmd ^ 8192);
+
+	clear_bit(PG_arch_1, &virt_to_page(pmd)->flags);
+	if (test_bit(PG_arch_1, &virt_to_page(pmd2)->flags) == 0) {
+		/* The other pmd of the order 2 allocation has already
+		   been freed. Now we can release the order 2 allocation.  */
+		free_pages((unsigned long) pmd & ~8192, 2);
+	}
+}
+
 int do_check_pgt_cache(int low, int high)
 {
         int freed = 0;
@@ -51,11 +119,11 @@
                 do {
                         if(pgd_quicklist) {
 				free_pgd_slow(get_pgd_fast());
-				freed += 4;
+				freed += 2;
 			}
                         if(pmd_quicklist) {
 				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
-				freed += 4;
+				freed += 2;
 			}
                         if(pte_quicklist) {
 				pte_free_slow(pte_alloc_one_fast(NULL, 0));
@@ -111,51 +179,45 @@
 
 void __init paging_init(void)
 {
+	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+	static const int ssm_mask = 0x04000000L;
+	unsigned long dma_pfn, address, end_mem;
         pgd_t * pg_dir;
-	pmd_t * pm_dir;
-        pte_t * pt_dir;
-        pte_t   pte;
 	int     i,j,k;
-        unsigned long address=0;
-        unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) |
-          _KERN_REGION_TABLE;
-	unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE);
-	static const int ssm_mask = 0x04000000L;
-
-	unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
-	unsigned long dma_pfn, high_pfn;
 
 	dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
-	high_pfn = max_low_pfn;
 
-	if (dma_pfn > high_pfn)
-		zones_size[ZONE_DMA] = high_pfn;
+	if (dma_pfn > max_low_pfn)
+		zones_size[ZONE_DMA] = max_low_pfn;
 	else {
 		zones_size[ZONE_DMA] = dma_pfn;
-		zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
+		zones_size[ZONE_NORMAL] = max_low_pfn - dma_pfn;
 	}
 
 	/* Initialize mem_map[].  */
 	free_area_init(zones_size);
 
-
 	/*
 	 * map whole physical memory to virtual memory (identity mapping) 
 	 */
-
         pg_dir = swapper_pg_dir;
-	
-        for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) {
+	address = 0;
+	end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE);
+        for (i = 0 ; i < PTRS_PER_PGD/2 ; i++, pg_dir += 2) {
+		pmd_t *pm_dir;
 
                 if (address >= end_mem) {
                         pgd_clear(pg_dir);
                         continue;
-                }          
+                }
         
 	        pm_dir = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE*4);
-                pgd_populate(&init_mm, pg_dir, pm_dir);
+		*((unsigned long *) pg_dir) = __pa(pm_dir) | _PGD_ENTRY_MASK |
+			_PGD_ENTRY_LEN(3) | _PGD_ENTRY_OFF(0);
+
+                for (j = 0 ; j < PTRS_PER_PMD*2 ; j++, pm_dir++) {
+			pte_t *pt_dir;
 
-                for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) {
                         if (address >= end_mem) {
                                 pmd_clear(pm_dir);
                                 continue; 
@@ -165,7 +227,7 @@
                         pmd_populate(&init_mm, pm_dir, pt_dir);
 	
                         for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
-                                pte = mk_pte_phys(address, PAGE_KERNEL);
+                                pte_t pte = mk_pte_phys(address, PAGE_KERNEL);
                                 if (address >= end_mem) {
                                         pte_clear(&pte); 
                                         continue;
@@ -181,8 +243,8 @@
                              "lctlg 7,7,%0\n\t"
                              "lctlg 13,13,%0\n\t"
                              "ssm   %1"
-			     : :"m" (pgdir_k), "m" (ssm_mask));
-
+			     : :"m" (__pa(swapper_pg_dir) | _KERN_REGION_TABLE),
+			        "m" (ssm_mask));
         local_flush_tlb();
 
         return;
diff -urN linux-2.4.20-pre1/arch/sh/config.in linux-2.4.20-pre2/arch/sh/config.in
--- linux-2.4.20-pre1/arch/sh/config.in	Mon Feb 25 11:37:56 2002
+++ linux-2.4.20-pre2/arch/sh/config.in	Mon Aug 12 16:34:15 2002
@@ -386,3 +386,5 @@
    bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
 fi
 endmenu
+
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/sparc/config.in linux-2.4.20-pre2/arch/sparc/config.in
--- linux-2.4.20-pre1/arch/sparc/config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/arch/sparc/config.in	Mon Aug 12 16:34:15 2002
@@ -201,7 +201,7 @@
           tristate '  Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
         fi
       fi
-      tristate '  PPP (point-to-point) support' CONFIG_PPP
+      tristate '  PPP (point-to-point protocol) support' CONFIG_PPP
       if [ ! "$CONFIG_PPP" = "n" ]; then
         dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
         dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
@@ -266,3 +266,5 @@
 
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
+
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/sparc/mm/init.c linux-2.4.20-pre2/arch/sparc/mm/init.c
--- linux-2.4.20-pre1/arch/sparc/mm/init.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/arch/sparc/mm/init.c	Mon Aug 12 16:34:15 2002
@@ -61,7 +61,9 @@
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
 
-extern unsigned long fix_kmap_begin;	/* calculated in srmmu.c */
+/* These are set in {srmmu,sun4c}_paging_init() */
+unsigned long fix_kmap_begin;
+unsigned long fix_kmap_end;
 
 #define kmap_get_fixed_pte(vaddr) \
 	pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
diff -urN linux-2.4.20-pre1/arch/sparc/mm/srmmu.c linux-2.4.20-pre2/arch/sparc/mm/srmmu.c
--- linux-2.4.20-pre1/arch/sparc/mm/srmmu.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/arch/sparc/mm/srmmu.c	Mon Aug 12 16:34:15 2002
@@ -118,11 +118,11 @@
 int srmmu_nocache_npages;
 unsigned long srmmu_nocache_size;
 unsigned long srmmu_nocache_end;
-unsigned long fix_kmap_begin;
-unsigned long fix_kmap_end;
 unsigned long pkmap_base;
 unsigned long pkmap_base_end;
 unsigned long srmmu_nocache_bitmap_size;
+extern unsigned long fix_kmap_begin;
+extern unsigned long fix_kmap_end;
 
 #define SRMMU_NOCACHE_BITMAP_SHIFT (PAGE_SHIFT - 4)
 
diff -urN linux-2.4.20-pre1/arch/sparc/mm/sun4c.c linux-2.4.20-pre2/arch/sparc/mm/sun4c.c
--- linux-2.4.20-pre1/arch/sparc/mm/sun4c.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/arch/sparc/mm/sun4c.c	Mon Aug 12 16:34:15 2002
@@ -1971,6 +1971,9 @@
 extern unsigned long last_valid_pfn;
 extern void sun_serial_setup(void);
 
+extern unsigned long fix_kmap_begin;
+extern unsigned long fix_kmap_end;
+
 void __init sun4c_paging_init(void)
 {
 	int i, cnt;
@@ -1978,6 +1981,9 @@
 	extern struct resource sparc_iomap;
 	unsigned long end_pfn, pages_avail;
 
+	fix_kmap_begin = KERNBASE + SRMMU_MAXMEM; /* Why bother with SRMMU_MAXMEM? */
+	fix_kmap_end = fix_kmap_begin + ((KM_TYPE_NR*NR_CPUS)-1)*PAGE_SIZE;
+
 	kernel_end = (unsigned long) &end;
 	kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4);
 	kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
diff -urN linux-2.4.20-pre1/arch/sparc64/config.in linux-2.4.20-pre2/arch/sparc64/config.in
--- linux-2.4.20-pre1/arch/sparc64/config.in	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/sparc64/config.in	Mon Aug 12 16:34:15 2002
@@ -308,3 +308,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -urN linux-2.4.20-pre1/arch/sparc64/kernel/time.c linux-2.4.20-pre2/arch/sparc64/kernel/time.c
--- linux-2.4.20-pre1/arch/sparc64/kernel/time.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/arch/sparc64/kernel/time.c	Mon Aug 12 16:34:15 2002
@@ -686,7 +686,7 @@
 
 	/* 
 	 * Not having a register set can lead to trouble.
-	 * Also starfire doesnt have a tod clock.
+	 * Also starfire doesn't have a tod clock.
 	 */
 	if (!mregs && !dregs) 
 		return -1;
diff -urN linux-2.4.20-pre1/drivers/Makefile linux-2.4.20-pre2/drivers/Makefile
--- linux-2.4.20-pre1/drivers/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/Makefile	Mon Aug 12 16:34:15 2002
@@ -6,7 +6,7 @@
 #
 
 
-mod-subdirs :=	dio mtd sbus video macintosh usb input telephony sgi ide \
+mod-subdirs :=	dio hil mtd sbus video macintosh usb input telephony sgi ide \
 		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
 		fc4 net/hamradio i2c acpi bluetooth
 
@@ -16,6 +16,8 @@
 
 subdir-$(CONFIG_DIO)		+= dio
 subdir-$(CONFIG_PCI)		+= pci
+subdir-$(CONFIG_GSC)		+= gsc
+subdir-$(CONFIG_HIL)		+= hil
 subdir-$(CONFIG_PCMCIA)		+= pcmcia
 subdir-$(CONFIG_MTD)		+= mtd
 subdir-$(CONFIG_SBUS)		+= sbus
@@ -24,7 +26,7 @@
 subdir-$(CONFIG_TC)		+= tc
 subdir-$(CONFIG_VT)		+= video
 subdir-$(CONFIG_MAC)		+= macintosh
-subdir-$(CONFIG_PPC)		+= macintosh
+subdir-$(CONFIG_PPC32)		+= macintosh
 subdir-$(CONFIG_USB)		+= usb
 subdir-$(CONFIG_INPUT)		+= input
 subdir-$(CONFIG_PHONE)		+= telephony
diff -urN linux-2.4.20-pre1/drivers/acorn/scsi/Config.in linux-2.4.20-pre2/drivers/acorn/scsi/Config.in
--- linux-2.4.20-pre1/drivers/acorn/scsi/Config.in	Thu Jan 13 13:30:31 2000
+++ linux-2.4.20-pre2/drivers/acorn/scsi/Config.in	Mon Aug 12 16:34:15 2002
@@ -14,10 +14,10 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    comment 'The following drivers are not fully supported'
 
-   dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
+   dep_tristate 'CumanaSCSI I support (EXPERIMENTAL)' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
    if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
-      dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
+      dep_tristate 'EcoScsi support (EXPERIMENTAL)' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
    fi
-   dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI
+   dep_tristate 'Oak SCSI support (EXPERIMENTAL)' CONFIG_SCSI_OAK1 $CONFIG_SCSI
 fi
 
diff -urN linux-2.4.20-pre1/drivers/atm/atmtcp.c linux-2.4.20-pre2/drivers/atm/atmtcp.c
--- linux-2.4.20-pre1/drivers/atm/atmtcp.c	Thu Sep 13 15:21:32 2001
+++ linux-2.4.20-pre2/drivers/atm/atmtcp.c	Mon Aug 12 16:34:15 2002
@@ -173,7 +173,7 @@
 static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
 	struct atmtcp_dev_data *dev_data;
-	struct atm_vcc *out_vcc;
+	struct atm_vcc *out_vcc=NULL; /* Initializer quietens GCC warning */
 	struct sk_buff *new_skb;
 	struct atmtcp_hdr *hdr;
 	int size;
diff -urN linux-2.4.20-pre1/drivers/atm/iphase.c linux-2.4.20-pre2/drivers/atm/iphase.c
--- linux-2.4.20-pre1/drivers/atm/iphase.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.20-pre2/drivers/atm/iphase.c	Mon Aug 12 16:34:16 2002
@@ -208,8 +208,7 @@
         ltimeout = dev->desc_tbl[i].iavcc->ltimeout; 
         delta = jiffies - dev->desc_tbl[i].timestamp;
         if (delta >= ltimeout) {
-           IF_ABR(printk("RECOVER run!! desc_tbl %d = %d  delta = %ld, 
-               time = %ld\n", i,dev->desc_tbl[i].timestamp, delta, jiffies);)
+           IF_ABR(printk("RECOVER run!! desc_tbl %d = %d  delta = %ld,  time = %ld\n", i,dev->desc_tbl[i].timestamp, delta, jiffies);)
            if (dev->ffL.tcq_rd == dev->ffL.tcq_st) 
               dev->ffL.tcq_rd =  dev->ffL.tcq_ed;
            else 
diff -urN linux-2.4.20-pre1/drivers/atm/lanai.c linux-2.4.20-pre2/drivers/atm/lanai.c
--- linux-2.4.20-pre1/drivers/atm/lanai.c	Thu Oct 25 13:53:46 2001
+++ linux-2.4.20-pre2/drivers/atm/lanai.c	Mon Aug 12 16:34:16 2002
@@ -2108,8 +2108,8 @@
 	}
 	result = pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &w);
 	if (result != PCIBIOS_SUCCESSFUL) {
-		printk(KERN_ERR DEV_LABEL "(itf %d): can't read ""
-		    PCI_SUBSYSTEM_ID: %d\n", lanai->number, result);
+		printk(KERN_ERR DEV_LABEL "(itf %d): can't read "
+		    "PCI_SUBSYSTEM_ID: %d\n", lanai->number, result);
 		return -EINVAL;
 	}
 	if ((result = check_board_id_and_rev("PCI", w, NULL)) != 0)
diff -urN linux-2.4.20-pre1/drivers/block/Config.in linux-2.4.20-pre2/drivers/block/Config.in
--- linux-2.4.20-pre1/drivers/block/Config.in	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/block/Config.in	Mon Aug 12 16:34:16 2002
@@ -4,7 +4,7 @@
 mainmenu_option next_comment
 comment 'Block devices'
 
-tristate 'Normal PC floppy disk support' CONFIG_BLK_DEV_FD
+tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
 if [ "$CONFIG_AMIGA" = "y" ]; then
    tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
 fi
@@ -37,7 +37,7 @@
 dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI 
 dep_mbool '       SCSI tape drive support for Smart Array 5xxx' CONFIG_CISS_SCSI_TAPE $CONFIG_BLK_CPQ_CISS_DA $CONFIG_SCSI
 dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
-dep_tristate 'Micro Memory MM5415 Battery Backed RAM support' CONFIG_BLK_DEV_UMEM $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate 'Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)' CONFIG_BLK_DEV_UMEM $CONFIG_PCI $CONFIG_EXPERIMENTAL
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
@@ -48,4 +48,6 @@
 fi
 dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
 
+bool 'Per partition statistics in /proc/partitions' CONFIG_BLK_STATS
+
 endmenu
diff -urN linux-2.4.20-pre1/drivers/block/cciss.c linux-2.4.20-pre2/drivers/block/cciss.c
--- linux-2.4.20-pre1/drivers/block/cciss.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/block/cciss.c	Mon Aug 12 16:34:16 2002
@@ -1166,20 +1166,22 @@
 static inline void complete_command( CommandList_struct *cmd, int timeout)
 {
 	int status = 1;
-	int i;
+	int i, ddir;
 	u64bit temp64;
 		
 	if (timeout)
 		status = 0; 
 	/* unmap the DMA mapping for all the scatter gather elements */
+	if (cmd->Request.Type.Direction == XFER_READ)
+		ddir = PCI_DMA_FROMDEVICE;
+	else
+		ddir = PCI_DMA_TODEVICE;
 	for(i=0; i<cmd->Header.SGList; i++)
 	{
 		temp64.val32.lower = cmd->SG[i].Addr.lower;
 		temp64.val32.upper = cmd->SG[i].Addr.upper;
-		pci_unmap_single(hba[cmd->ctlr]->pdev,
-			temp64.val, cmd->SG[i].Len, 
-			(cmd->Request.Type.Direction == XFER_READ) ? 
-				PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+		pci_unmap_page(hba[cmd->ctlr]->pdev,
+			temp64.val, cmd->SG[i].Len, ddir);
 	}
 
 	if(cmd->err_info->CommandStatus != 0) 
@@ -1287,7 +1289,7 @@
 static int cpq_back_merge_fn(request_queue_t *q, struct request *rq,
                              struct buffer_head *bh, int max_segments)
 {
-        if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data)
+	if (blk_seg_merge_ok(rq->bhtail, bh))
                 return 1;
         return cpq_new_segment(q, rq, max_segments);
 }
@@ -1295,7 +1297,7 @@
 static int cpq_front_merge_fn(request_queue_t *q, struct request *rq,
                              struct buffer_head *bh, int max_segments)
 {
-        if (bh->b_data + bh->b_size == rq->bh->b_data)
+	if (blk_seg_merge_ok(bh, rq->bh))
                 return 1;
         return cpq_new_segment(q, rq, max_segments);
 }
@@ -1305,7 +1307,7 @@
 {
         int total_segments = rq->nr_segments + nxt->nr_segments;
 
-        if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data)
+	if (blk_seg_merge_ok(rq->bhtail, nxt->bh))
                 total_segments--;
 
         if (total_segments > MAXSGENTRIES)
@@ -1326,18 +1328,18 @@
 	ctlr_info_t *h= q->queuedata; 
 	CommandList_struct *c;
 	int log_unit, start_blk, seg;
-	char *lastdataend;
+	unsigned long long lastdataend;
 	struct buffer_head *bh;
 	struct list_head *queue_head = &q->queue_head;
 	struct request *creq;
 	u64bit temp64;
-	struct my_sg tmp_sg[MAXSGENTRIES];
-	int i;
+	struct scatterlist tmp_sg[MAXSGENTRIES];
+	int i, ddir;
 
 	if (q->plugged)
 		goto startio;
 
-queue_next:
+next:
 	if (list_empty(queue_head))
 		goto startio;
 
@@ -1363,8 +1365,8 @@
 	spin_unlock_irq(&io_request_lock);
 
 	c->cmd_type = CMD_RWREQ;      
-	bh = creq->bh;
 	c->rq = creq;
+	bh = creq->bh;
 	
 	/* fill in the request */ 
 	log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; 
@@ -1386,34 +1388,36 @@
 	printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
 		(int) creq->nr_sectors);	
 #endif /* CCISS_DEBUG */
-	seg = 0; 
-	lastdataend = NULL;
+	seg = 0;
+	lastdataend = ~0ULL;
 	while(bh)
 	{
-		if (bh->b_data == lastdataend)
+		if (bh_phys(bh) == lastdataend)
 		{  // tack it on to the last segment 
-			tmp_sg[seg-1].len +=bh->b_size;
+			tmp_sg[seg-1].length +=bh->b_size;
 			lastdataend += bh->b_size;
 		} else
 		{
 			if (seg == MAXSGENTRIES)
 				BUG();
-			tmp_sg[seg].len = bh->b_size;
-			tmp_sg[seg].start_addr = bh->b_data;
-			lastdataend = bh->b_data + bh->b_size;
+			tmp_sg[seg].page = bh->b_page;
+			tmp_sg[seg].length = bh->b_size;
+			tmp_sg[seg].offset = bh_offset(bh);
+			lastdataend = bh_phys(bh) + bh->b_size;
 			seg++;
 		}
 		bh = bh->b_reqnext;
 	}
+
 	/* get the DMA records for the setup */ 
-	for (i=0; i<seg; i++)
-	{
-		c->SG[i].Len = tmp_sg[i].len;
-		temp64.val = (__u64) pci_map_single( h->pdev,
-			tmp_sg[i].start_addr,
-			tmp_sg[i].len,
-			(c->Request.Type.Direction == XFER_READ) ? 
-                                PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+	if (c->Request.Type.Direction == XFER_READ)
+		ddir = PCI_DMA_FROMDEVICE;
+	else
+		ddir = PCI_DMA_TODEVICE;
+	for (i=0; i<seg; i++) {
+		c->SG[i].Len = tmp_sg[i].length;
+		temp64.val = pci_map_page(h->pdev, tmp_sg[i].page,
+			    tmp_sg[i].offset, tmp_sg[i].length, ddir);
 		c->SG[i].Addr.lower = temp64.val32.lower;
                 c->SG[i].Addr.upper = temp64.val32.upper;
                 c->SG[i].Ext = 0;  // we are not chaining
@@ -1423,7 +1427,7 @@
 		h->maxSG = seg; 
 
 #ifdef CCISS_DEBUG
-	printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", creq->nr_sectors, seg);
+	printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", sect, seg);
 #endif /* CCISS_DEBUG */
 
 	c->Header.SGList = c->Header.SGTotal = seg;
@@ -1444,7 +1448,8 @@
 	if(h->Qdepth > h->maxQsinceinit)
 		h->maxQsinceinit = h->Qdepth; 
 
-	goto queue_next;
+	goto next;
+
 startio:
 	start_io(h);
 }
@@ -1969,7 +1974,18 @@
 	sprintf(hba[i]->devname, "cciss%d", i);
 	hba[i]->ctlr = i;
 	hba[i]->pdev = pdev;
-			
+
+	/* configure PCI DMA stuff */
+	if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff))
+		printk("cciss: using DAC cycles\n");
+	else if (!pci_set_dma_mask(pdev, (u64) 0xffffffff))
+		printk("cciss: not using DAC cycles\n");
+	else {
+		printk("cciss: no suitable DMA available\n");
+		free_hba(i);
+		return -ENODEV;
+	}
+		
 	if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops))
 	{
 		printk(KERN_ERR "cciss:  Unable to get major number "
@@ -2043,9 +2059,10 @@
 	cciss_procinit(i);
 
 	q = BLK_DEFAULT_QUEUE(MAJOR_NR + i);
-        q->queuedata = hba[i];
-        blk_init_queue(q, do_cciss_request);
-        blk_queue_headactive(q, 0);		
+	q->queuedata = hba[i];
+	blk_init_queue(q, do_cciss_request);
+	blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
+	blk_queue_headactive(q, 0);		
 
 	/* fill in the other Kernel structs */
 	blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
diff -urN linux-2.4.20-pre1/drivers/block/cciss.h linux-2.4.20-pre2/drivers/block/cciss.h
--- linux-2.4.20-pre1/drivers/block/cciss.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/block/cciss.h	Mon Aug 12 16:34:16 2002
@@ -15,11 +15,6 @@
 
 #define MAJOR_NR COMPAQ_CISS_MAJOR 
 
-struct my_sg {
-	int len;
-	char *start_addr;
-};
-
 struct ctlr_info;
 typedef struct ctlr_info ctlr_info_t;
 
diff -urN linux-2.4.20-pre1/drivers/block/cpqarray.c linux-2.4.20-pre2/drivers/block/cpqarray.c
--- linux-2.4.20-pre1/drivers/block/cpqarray.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/block/cpqarray.c	Mon Aug 12 16:34:16 2002
@@ -443,7 +443,7 @@
 static int cpq_back_merge_fn(request_queue_t *q, struct request *rq,
 			     struct buffer_head *bh, int max_segments)
 {
-	if (rq->bhtail->b_data + rq->bhtail->b_size == bh->b_data)
+	if (blk_seg_merge_ok(rq->bhtail, bh))
 		return 1;
 	return cpq_new_segment(q, rq, max_segments);
 }
@@ -451,7 +451,7 @@
 static int cpq_front_merge_fn(request_queue_t *q, struct request *rq,
 			     struct buffer_head *bh, int max_segments)
 {
-	if (bh->b_data + bh->b_size == rq->bh->b_data)
+	if (blk_seg_merge_ok(bh, rq->bh))
 		return 1;
 	return cpq_new_segment(q, rq, max_segments);
 }
@@ -461,7 +461,7 @@
 {
 	int total_segments = rq->nr_segments + nxt->nr_segments;
 
-	if (rq->bhtail->b_data + rq->bhtail->b_size == nxt->bh->b_data)
+	if (blk_seg_merge_ok(rq->bhtail, nxt->bh))
 		total_segments--;
 
 	if (total_segments > SG_MAX)
@@ -566,6 +566,7 @@
 	q = BLK_DEFAULT_QUEUE(MAJOR_NR + i);
 	q->queuedata = hba[i];
 	blk_init_queue(q, do_ida_request);
+	blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask);
 	blk_queue_headactive(q, 0);
 	blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
 	hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes;
@@ -966,17 +967,17 @@
 {
 	ctlr_info_t *h = q->queuedata;
 	cmdlist_t *c;
-	char *lastdataend;
+	unsigned long lastdataend;
 	struct list_head * queue_head = &q->queue_head;
 	struct buffer_head *bh;
 	struct request *creq;
-	struct my_sg tmp_sg[SG_MAX];
+	struct scatterlist tmp_sg[SG_MAX];
 	int i, seg;
 
 	if (q->plugged)
 		goto startio;
 
-queue_next:
+next:
 	if (list_empty(queue_head))
 		goto startio;
 
@@ -1017,17 +1018,19 @@
 	
 	printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors);
 );
-	seg = 0; lastdataend = NULL;
+	seg = 0;
+	lastdataend = ~0UL;
 	while(bh) {
-		if (bh->b_data == lastdataend) {
-			tmp_sg[seg-1].size += bh->b_size;
+		if (bh_phys(bh) == lastdataend) {
+			tmp_sg[seg-1].length += bh->b_size;
 			lastdataend += bh->b_size;
 		} else {
 			if (seg == SG_MAX)
 				BUG();
-			tmp_sg[seg].size = bh->b_size;
-			tmp_sg[seg].start_addr = bh->b_data;
-			lastdataend = bh->b_data + bh->b_size;
+			tmp_sg[seg].page = bh->b_page;
+			tmp_sg[seg].length = bh->b_size;
+			tmp_sg[seg].offset = bh_offset(bh);
+			lastdataend = bh_phys(bh) + bh->b_size;
 			seg++;
 		}
 		bh = bh->b_reqnext;
@@ -1035,10 +1038,10 @@
 	/* Now do all the DMA Mappings */
 	for( i=0; i < seg; i++)
 	{
-		c->req.sg[i].size = tmp_sg[i].size;
-		c->req.sg[i].addr = (__u32) pci_map_single(
-                		h->pci_dev, tmp_sg[i].start_addr, 
-				tmp_sg[i].size,
+		c->req.sg[i].size = tmp_sg[i].length;
+		c->req.sg[i].addr = (__u32) pci_map_page(
+                		h->pci_dev, tmp_sg[i].page, tmp_sg[i].offset,
+				tmp_sg[i].length,
                                 (creq->cmd == READ) ? 
 					PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
 	}
@@ -1056,7 +1059,7 @@
 	if (h->Qdepth > h->maxQsinceinit) 
 		h->maxQsinceinit = h->Qdepth;
 
-	goto queue_next;
+	goto next;
 
 startio:
 	start_io(h);
@@ -1132,17 +1135,14 @@
 	/* unmap the DMA mapping for all the scatter gather elements */
         for(i=0; i<cmd->req.hdr.sg_cnt; i++)
         {
-                pci_unmap_single(hba[cmd->ctlr]->pci_dev,
+                pci_unmap_page(hba[cmd->ctlr]->pci_dev,
                         cmd->req.sg[i].addr, cmd->req.sg[i].size,
                         (cmd->req.hdr.cmd == IDA_READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
         }
 
 	complete_buffers(cmd->rq->bh, ok);
-
 	DBGPX(printk("Done with %p\n", cmd->rq););
 	end_that_request_last(cmd->rq);
-
-
 }
 
 /*
@@ -1301,7 +1301,8 @@
 		if (error) return error;
 		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
 		if (error) return error;
-		error = copy_to_user(io, &my_io, sizeof(my_io));
+		if(copy_to_user(io, &my_io, sizeof(my_io)))
+			return -EFAULT;
 		return error;
 	case IDAGETCTLRSIG:
 		if (!arg) return -EINVAL;
@@ -1416,7 +1417,11 @@
 			cmd_free(h, c, 0); 
 			return(error);
 		}
-		copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
+		if (copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size)) {
+			kfree(p);
+			cmd_free(h, c, 0); 
+			return -EFAULT;
+		}
 		c->req.hdr.blk = pci_map_single(h->pci_dev, &(io->c), 
 				sizeof(ida_ioctl_t), 
 				PCI_DMA_BIDIRECTIONAL);
@@ -1453,7 +1458,11 @@
                         cmd_free(h, c, 0);
                         return(error);
                 }
-		copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);
+		if (copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size)) {
+			kfree(p);
+                        cmd_free(h, c, 0);
+			return -EFAULT;
+		}
 		c->req.sg[0].size = io->sg[0].size;
 		c->req.sg[0].addr = pci_map_single(h->pci_dev, p, 
 			c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL); 
@@ -1490,7 +1499,10 @@
 	case DIAG_PASS_THRU:
 	case SENSE_CONTROLLER_PERFORMANCE:
 	case READ_FLASH_ROM:
-		copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size);
+		if (copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size)) {
+			kfree(p);
+			return -EFAULT;
+		}
 		/* fall through and free p */
 	case IDA_WRITE:
 	case IDA_WRITE_MEDIA:
diff -urN linux-2.4.20-pre1/drivers/block/cpqarray.h linux-2.4.20-pre2/drivers/block/cpqarray.h
--- linux-2.4.20-pre1/drivers/block/cpqarray.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/block/cpqarray.h	Mon Aug 12 16:34:16 2002
@@ -57,11 +57,6 @@
 
 #ifdef __KERNEL__
 
-struct my_sg {
-	int size;
-	char *start_addr;
-};
-
 struct ctlr_info;
 typedef struct ctlr_info ctlr_info_t;
 
diff -urN linux-2.4.20-pre1/drivers/block/genhd.c linux-2.4.20-pre2/drivers/block/genhd.c
--- linux-2.4.20-pre1/drivers/block/genhd.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/block/genhd.c	Mon Aug 12 16:34:16 2002
@@ -22,10 +22,9 @@
 #include <linux/blk.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/seq_file.h>
 
 
-static rwlock_t gendisk_lock;
-
 /*
  * Global kernel list of partitioning information.
  *
@@ -34,6 +33,7 @@
  */
 /*static*/ struct gendisk *gendisk_head;
 static struct gendisk *gendisk_array[MAX_BLKDEV];
+static rwlock_t gendisk_lock = RW_LOCK_UNLOCKED;
 
 EXPORT_SYMBOL(gendisk_head);
 
@@ -153,46 +153,83 @@
 	return error;
 }
 
-
 #ifdef CONFIG_PROC_FS
-int
-get_partition_list(char *page, char **start, off_t offset, int count)
+/* iterator */
+static void *part_start(struct seq_file *s, loff_t *pos)
 {
 	struct gendisk *gp;
-	struct hd_struct *hd;
-	char buf[64];
-	int len, n;
 
-	len = sprintf(page, "major minor  #blocks  name\n\n");
-		
 	read_lock(&gendisk_lock);
-	for (gp = gendisk_head; gp; gp = gp->next) {
-		for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
-			if (gp->part[n].nr_sects == 0)
-				continue;
-
-			hd = &gp->part[n]; disk_round_stats(hd);
-			len += sprintf(page + len,
-				"%4d  %4d %10d %s\n", gp->major,
-				n, gp->sizes[n], disk_name(gp, n, buf));
-
-			if (len < offset)
-				offset -= len, len = 0;
-			else if (len >= offset + count)
-				goto out;
-		}
-	}
+	for (gp = gendisk_head; gp; gp = gp->next)
+		if (!*pos--)
+			return gp;
+	return NULL;
+}
 
-out:
+static void *part_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	++*pos;
+	return ((struct gendisk *)v)->next;
+}
+
+static void part_stop(struct seq_file *s, void *v)
+{
 	read_unlock(&gendisk_lock);
-	*start = page + offset;
-	len -= offset;
-	if (len < 0)
-		len = 0;
-	return len > count ? count : len;
 }
+
+static int part_show(struct seq_file *s, void *v)
+{
+	struct gendisk *gp = v;
+	char buf[64];
+	int n;
+
+	if (gp == gendisk_head) {
+		seq_puts(s, "major minor  #blocks  name"
+#ifdef CONFIG_BLK_STATS
+			    "     rio rmerge rsect ruse wio wmerge "
+			    "wsect wuse running use aveq"
 #endif
+			   "\n\n");
+	}
 
+	/* show the full disk and all non-0 size partitions of it */
+	for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
+		int mask = (1<<gp->minor_shift) - 1;
+
+		if (!(n & mask) || gp->part[n].nr_sects) {
+			struct hd_struct *hd = &gp->part[n];
+
+#ifdef CONFIG_BLK_STATS
+			disk_round_stats(hd);
+			seq_printf(s, "%4d  %4d %10d %s "
+				      "%d %d %d %d %d %d %d %d %d %d %d\n",
+				      gp->major, n, gp->sizes[n],
+				      disk_name(gp, n, buf),
+				      hd->rd_ios, hd->rd_merges,
+#define MSEC(x) ((x) * 1000 / HZ)
+				      hd->rd_sectors, MSEC(hd->rd_ticks),
+				      hd->wr_ios, hd->wr_merges,
+				      hd->wr_sectors, MSEC(hd->wr_ticks),
+				      hd->ios_in_flight, MSEC(hd->io_ticks),
+				      MSEC(hd->aveq));
+#else
+			seq_printf(s, "%4d  %4d %10d %s\n",
+				   gp->major, n, gp->sizes[n],
+				   disk_name(gp, n, buf));
+#endif /* CONFIG_BLK_STATS */
+		}
+	}
+
+	return 0;
+}
+
+struct seq_operations partitions_op = {
+	.start		= part_start,
+	.next		= part_next,
+	.stop		= part_stop,
+	.show		= part_show,
+};
+#endif
 
 extern int blk_dev_init(void);
 extern int net_dev_init(void);
@@ -201,7 +238,6 @@
 
 int __init device_init(void)
 {
-	rwlock_init(&gendisk_lock);
 	blk_dev_init();
 	sti();
 #ifdef CONFIG_NET
diff -urN linux-2.4.20-pre1/drivers/block/ll_rw_blk.c linux-2.4.20-pre2/drivers/block/ll_rw_blk.c
--- linux-2.4.20-pre1/drivers/block/ll_rw_blk.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/block/ll_rw_blk.c	Mon Aug 12 16:34:16 2002
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/bootmem.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -117,6 +118,9 @@
  */
 int * max_sectors[MAX_BLKDEV];
 
+unsigned long blk_max_low_pfn, blk_max_pfn;
+int blk_nohighio = 0;
+
 static inline int get_max_sectors(kdev_t dev)
 {
 	if (!max_sectors[MAJOR(dev)])
@@ -238,6 +242,54 @@
 	q->make_request_fn = mfn;
 }
 
+/**
+ * blk_queue_bounce_limit - set bounce buffer limit for queue
+ * @q:  the request queue for the device
+ * @dma_addr:   bus address limit
+ *
+ * Description:
+ *    Different hardware can have different requirements as to what pages
+ *    it can do I/O directly to. A low level driver can call
+ *    blk_queue_bounce_limit to have lower memory pages allocated as bounce
+ *    buffers for doing I/O to pages residing above @page. By default
+ *    the block layer sets this to the highest numbered "low" memory page.
+ **/
+void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr)
+{
+	unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT;
+	unsigned long mb = dma_addr >> 20;
+	static request_queue_t *old_q;
+
+	/*
+	 * keep this for debugging for now...
+	 */
+	if (dma_addr != BLK_BOUNCE_HIGH && q != old_q) {
+		old_q = q;
+		printk("blk: queue %p, ", q);
+		if (dma_addr == BLK_BOUNCE_ANY)
+			printk("no I/O memory limit\n");
+		else
+			printk("I/O limit %luMb (mask 0x%Lx)\n", mb, (u64) dma_addr);
+	}
+
+	q->bounce_pfn = bounce_pfn;
+}
+
+
+/*
+ * can we merge the two segments, or do we need to start a new one?
+ */
+inline int blk_seg_merge_ok(struct buffer_head *bh, struct buffer_head *nxt)
+{
+	/*
+	 * if bh and nxt are contigous and don't cross a 4g boundary, it's ok
+	 */
+	if (BH_CONTIG(bh, nxt) && BH_PHYS_4G(bh, nxt))
+		return 1;
+
+	return 0;
+}
+
 static inline int ll_new_segment(request_queue_t *q, struct request *req, int max_segments)
 {
 	if (req->nr_segments < max_segments) {
@@ -250,16 +302,18 @@
 static int ll_back_merge_fn(request_queue_t *q, struct request *req, 
 			    struct buffer_head *bh, int max_segments)
 {
-	if (req->bhtail->b_data + req->bhtail->b_size == bh->b_data)
+	if (blk_seg_merge_ok(req->bhtail, bh))
 		return 1;
+
 	return ll_new_segment(q, req, max_segments);
 }
 
 static int ll_front_merge_fn(request_queue_t *q, struct request *req, 
 			     struct buffer_head *bh, int max_segments)
 {
-	if (bh->b_data + bh->b_size == req->bh->b_data)
+	if (blk_seg_merge_ok(bh, req->bh))
 		return 1;
+
 	return ll_new_segment(q, req, max_segments);
 }
 
@@ -268,9 +322,9 @@
 {
 	int total_segments = req->nr_segments + next->nr_segments;
 
-	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
+	if (blk_seg_merge_ok(req->bhtail, next->bh))
 		total_segments--;
-    
+
 	if (total_segments > max_segments)
 		return 0;
 
@@ -444,6 +498,8 @@
 	 */
 	q->plug_device_fn 	= generic_plug_device;
 	q->head_active    	= 1;
+
+	blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
 }
 
 #define blkdev_free_rq(list) list_entry((list)->next, struct request, queue);
@@ -540,7 +596,7 @@
 		if (q->rq[rw].count == 0)
 			schedule();
 		spin_lock_irq(&io_request_lock);
-		rq = get_request(q,rw);
+		rq = get_request(q, rw);
 		spin_unlock_irq(&io_request_lock);
 	} while (rq == NULL);
 	remove_wait_queue(&q->wait_for_requests[rw], &wait);
@@ -594,9 +650,14 @@
 		printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
 }
 
-/* Return up to two hd_structs on which to do IO accounting for a given
- * request.  On a partitioned device, we want to account both against
- * the partition and against the whole disk.  */
+#ifdef CONFIG_BLK_STATS
+/*
+ * Return up to two hd_structs on which to do IO accounting for a given
+ * request.
+ *
+ * On a partitioned device, we want to account both against the partition
+ * and against the whole disk.
+ */
 static void locate_hd_struct(struct request *req, 
 			     struct hd_struct **hd1,
 			     struct hd_struct **hd2)
@@ -611,22 +672,26 @@
 		/* Mask out the partition bits: account for the entire disk */
 		int devnr = MINOR(req->rq_dev) >> gd->minor_shift;
 		int whole_minor = devnr << gd->minor_shift;
+
 		*hd1 = &gd->part[whole_minor];
 		if (whole_minor != MINOR(req->rq_dev))
 			*hd2= &gd->part[MINOR(req->rq_dev)];
 	}
 }
 
-/* Round off the performance stats on an hd_struct.  The average IO
- * queue length and utilisation statistics are maintained by observing
- * the current state of the queue length and the amount of time it has
- * been in this state for.  Normally, that accounting is done on IO
- * completion, but that can result in more than a second's worth of IO
- * being accounted for within any one second, leading to >100%
- * utilisation.  To deal with that, we do a round-off before returning
- * the results when reading /proc/partitions, accounting immediately for
- * all queue usage up to the current jiffies and restarting the counters
- * again. */
+/*
+ * Round off the performance stats on an hd_struct.
+ *
+ * The average IO queue length and utilisation statistics are maintained
+ * by observing the current state of the queue length and the amount of
+ * time it has been in this state for.
+ * Normally, that accounting is done on IO completion, but that can result
+ * in more than a second's worth of IO being accounted for within any one
+ * second, leading to >100% utilisation.  To deal with that, we do a
+ * round-off before returning the results when reading /proc/partitions,
+ * accounting immediately for all queue usage up to the current jiffies and
+ * restarting the counters again.
+ */
 void disk_round_stats(struct hd_struct *hd)
 {
 	unsigned long now = jiffies;
@@ -639,7 +704,6 @@
 	hd->last_idle_time = now;	
 }
 
-
 static inline void down_ios(struct hd_struct *hd)
 {
 	disk_round_stats(hd);	
@@ -690,6 +754,7 @@
 void req_new_io(struct request *req, int merge, int sectors)
 {
 	struct hd_struct *hd1, *hd2;
+
 	locate_hd_struct(req, &hd1, &hd2);
 	if (hd1)
 		account_io_start(hd1, req, merge, sectors);
@@ -697,15 +762,29 @@
 		account_io_start(hd2, req, merge, sectors);
 }
 
+void req_merged_io(struct request *req)
+{
+	struct hd_struct *hd1, *hd2;
+
+	locate_hd_struct(req, &hd1, &hd2);
+	if (hd1)
+		down_ios(hd1);
+	if (hd2)	
+		down_ios(hd2);
+}
+
 void req_finished_io(struct request *req)
 {
 	struct hd_struct *hd1, *hd2;
+
 	locate_hd_struct(req, &hd1, &hd2);
 	if (hd1)
 		account_io_end(hd1, req);
 	if (hd2)	
 		account_io_end(hd2, req);
 }
+EXPORT_SYMBOL(req_finished_io);
+#endif /* CONFIG_BLK_STATS */
 
 /*
  * add-request adds a request to the linked list.
@@ -764,7 +843,6 @@
 			  int max_segments)
 {
 	struct request *next;
-	struct hd_struct *hd1, *hd2;
   
 	next = blkdev_next_request(req);
 	if (req->sector + req->nr_sectors != next->sector)
@@ -791,12 +869,8 @@
 
 	/* One last thing: we have removed a request, so we now have one
 	   less expected IO to complete for accounting purposes. */
+	req_merged_io(req);
 
-	locate_hd_struct(req, &hd1, &hd2);
-	if (hd1)
-		down_ios(hd1);
-	if (hd2)	
-		down_ios(hd2);
 	blkdev_release_request(next);
 }
 
@@ -866,9 +940,7 @@
 	 * driver. Create a bounce buffer if the buffer data points into
 	 * high memory - keep the original buffer otherwise.
 	 */
-#if CONFIG_HIGHMEM
-	bh = create_bounce(rw, bh);
-#endif
+	bh = blk_queue_bounce(q, rw, bh);
 
 /* look for a free request. */
 	/*
@@ -918,8 +990,13 @@
 			elevator->elevator_merge_cleanup_fn(q, req, count);
 			bh->b_reqnext = req->bh;
 			req->bh = bh;
+			/*
+			 * may not be valid, but queues not having bounce
+			 * enabled for highmem pages must not look at
+			 * ->buffer anyway
+			 */
 			req->buffer = bh->b_data;
-			req->current_nr_sectors = count;
+			req->current_nr_sectors = req->hard_cur_sectors = count;
 			req->sector = req->hard_sector = sector;
 			req->nr_sectors = req->hard_nr_sectors += count;
 			blk_started_io(count);
@@ -978,7 +1055,7 @@
 	req->errors = 0;
 	req->hard_sector = req->sector = sector;
 	req->hard_nr_sectors = req->nr_sectors = count;
-	req->current_nr_sectors = count;
+	req->current_nr_sectors = req->hard_cur_sectors = count;
 	req->nr_segments = 1; /* Always 1 for a new request. */
 	req->nr_hw_segments = 1; /* Always 1 for a new request. */
 	req->buffer = bh->b_data;
@@ -1286,6 +1363,7 @@
 			req->nr_sectors = req->hard_nr_sectors;
 
 			req->current_nr_sectors = bh->b_size >> 9;
+			req->hard_cur_sectors = req->current_nr_sectors;
 			if (req->nr_sectors < req->current_nr_sectors) {
 				req->nr_sectors = req->current_nr_sectors;
 				printk("end_request: buffer-list destroyed\n");
@@ -1324,6 +1402,9 @@
 	memset(max_readahead, 0, sizeof(max_readahead));
 	memset(max_sectors, 0, sizeof(max_sectors));
 
+	blk_max_low_pfn = max_low_pfn - 1;
+	blk_max_pfn = max_pfn - 1;
+
 #ifdef CONFIG_AMIGA_Z2RAM
 	z2_init();
 #endif
@@ -1439,5 +1520,9 @@
 EXPORT_SYMBOL(blk_queue_make_request);
 EXPORT_SYMBOL(generic_make_request);
 EXPORT_SYMBOL(blkdev_release_request);
-EXPORT_SYMBOL(req_finished_io);
 EXPORT_SYMBOL(generic_unplug_device);
+EXPORT_SYMBOL(blk_queue_bounce_limit);
+EXPORT_SYMBOL(blk_max_low_pfn);
+EXPORT_SYMBOL(blk_max_pfn);
+EXPORT_SYMBOL(blk_seg_merge_ok);
+EXPORT_SYMBOL(blk_nohighio);
diff -urN linux-2.4.20-pre1/drivers/block/loop.c linux-2.4.20-pre2/drivers/block/loop.c
--- linux-2.4.20-pre1/drivers/block/loop.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/block/loop.c	Mon Aug 12 16:34:16 2002
@@ -154,7 +154,7 @@
 
 #define MAX_DISK_SIZE 1024*1024*1024
 
-static unsigned long compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev)
+static int compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev)
 {
 	if (S_ISREG(lo_dentry->d_inode->i_mode))
 		return (lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
@@ -483,9 +483,7 @@
 		goto err;
 	}
 
-#if CONFIG_HIGHMEM
-	rbh = create_bounce(rw, rbh);
-#endif
+	rbh = blk_queue_bounce(q, rw, rbh);
 
 	/*
 	 * file backed, queue for loop_thread to handle
diff -urN linux-2.4.20-pre1/drivers/bluetooth/hci_ldisc.c linux-2.4.20-pre2/drivers/bluetooth/hci_ldisc.c
--- linux-2.4.20-pre1/drivers/bluetooth/hci_ldisc.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/bluetooth/hci_ldisc.c	Mon Aug 12 16:34:16 2002
@@ -33,7 +33,6 @@
 #include <linux/module.h>
 
 #include <linux/version.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
diff -urN linux-2.4.20-pre1/drivers/bluetooth/hci_usb.c linux-2.4.20-pre2/drivers/bluetooth/hci_usb.c
--- linux-2.4.20-pre1/drivers/bluetooth/hci_usb.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/bluetooth/hci_usb.c	Mon Aug 12 16:34:16 2002
@@ -96,10 +96,10 @@
 static void hci_usb_rx_complete(struct urb *urb);
 static void hci_usb_tx_complete(struct urb *urb);
 
-static purb_t hci_usb_get_completed(struct hci_usb *husb)
+static struct urb *hci_usb_get_completed(struct hci_usb *husb)
 {
 	struct sk_buff *skb;
-	purb_t urb = NULL;
+	struct urb *urb = NULL;
 
 	skb = skb_dequeue(&husb->completed_q);
 	if (skb) {
@@ -240,7 +240,7 @@
 static inline void hci_usb_unlink_urbs(struct hci_usb *husb)
 {
 	struct sk_buff *skb;
-	purb_t urb;
+	struct urb *urb;
 
 	BT_DBG("%s", husb->hdev.name);
 
@@ -280,8 +280,8 @@
 static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
 {
 	struct hci_usb_scb *scb = (void *) skb->cb;
-	purb_t urb = hci_usb_get_completed(husb);
-	devrequest *dr;
+	struct urb *urb = hci_usb_get_completed(husb);
+	struct usb_ctrlrequest *dr;
 	int pipe, err;
 
 	if (!urb && !(urb = usb_alloc_urb(0)))
@@ -294,11 +294,11 @@
 	
 	pipe = usb_sndctrlpipe(husb->udev, 0);
 
-	dr->requesttype = HCI_CTRL_REQ;
-	dr->request = 0;
-	dr->index   = 0;
-	dr->value   = 0;
-	dr->length  = __cpu_to_le16(skb->len);
+	dr->bRequestType = HCI_CTRL_REQ;
+	dr->bRequest = 0;
+	dr->wIndex   = 0;
+	dr->wValue   = 0;
+	dr->wLength  = __cpu_to_le16(skb->len);
 
 	FILL_CONTROL_URB(urb, husb->udev, pipe, (void *) dr,
 			skb->data, skb->len, hci_usb_tx_complete, skb);
@@ -321,7 +321,7 @@
 static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
 {
 	struct hci_usb_scb *scb = (void *) skb->cb;
-	purb_t urb = hci_usb_get_completed(husb);
+	struct urb *urb = hci_usb_get_completed(husb);
 	int pipe, err;
 
 	if (!urb && !(urb = usb_alloc_urb(0)))
diff -urN linux-2.4.20-pre1/drivers/bluetooth/hci_usb.h linux-2.4.20-pre2/drivers/bluetooth/hci_usb.h
--- linux-2.4.20-pre1/drivers/bluetooth/hci_usb.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/bluetooth/hci_usb.h	Mon Aug 12 16:34:16 2002
@@ -55,7 +55,7 @@
 
 	__u8			intr_ep;
 	__u8			intr_interval;
-	purb_t			intr_urb;
+	struct urb		*intr_urb;
 	struct sk_buff *	intr_skb;
 
 	rwlock_t		completion_lock;
diff -urN linux-2.4.20-pre1/drivers/cdrom/cdu31a.c linux-2.4.20-pre2/drivers/cdrom/cdu31a.c
--- linux-2.4.20-pre1/drivers/cdrom/cdu31a.c	Thu Oct 25 13:58:35 2001
+++ linux-2.4.20-pre2/drivers/cdrom/cdu31a.c	Mon Aug 12 16:34:16 2002
@@ -3385,7 +3385,8 @@
 	if (drive_found) {
 		int deficiency = 0;
 
-		request_region(cdu31a_port, 4, "cdu31a");
+		if (!request_region(cdu31a_port, 4, "cdu31a"))
+			goto errout3;
 
 		if (devfs_register_blkdev(MAJOR_NR, "cdu31a", &scd_bdops)) {
 			printk("Unable to get major %d for CDU-31a\n",
diff -urN linux-2.4.20-pre1/drivers/char/Config.in linux-2.4.20-pre2/drivers/char/Config.in
--- linux-2.4.20-pre1/drivers/char/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/char/Config.in	Mon Aug 12 16:34:16 2002
@@ -7,10 +7,16 @@
 bool 'Virtual terminal' CONFIG_VT
 if [ "$CONFIG_VT" = "y" ]; then
    bool '  Support for console on virtual terminal' CONFIG_VT_CONSOLE
+   if [ "$CONFIG_GSC_LASI" = "y" ]; then
+      bool '    Support for Lasi/Dino PS2 port' CONFIG_GSC_PS2
+   fi
 fi
 tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL
 if [ "$CONFIG_SERIAL" = "y" ]; then
    bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   if [ "$CONFIG_GSC_LASI" = "y" ]; then
+      bool '   serial port on GSC support' CONFIG_SERIAL_GSC
+   fi
    if [ "$CONFIG_IA64" = "y" ]; then
       bool 'Support for serial console port described by EFI HCDP table' CONFIG_SERIAL_HCDP
    fi
@@ -36,10 +42,10 @@
       bool '    Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR
    fi
    if [ "$CONFIG_X86_64" != "y" ]; then
-   tristate '  Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
-   if [ "$CONFIG_DIGIEPCA" = "n" ]; then
-      tristate '  Digiboard PC/Xx Support' CONFIG_DIGI
-   fi
+      tristate '  Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
+      if [ "$CONFIG_DIGIEPCA" = "n" ]; then
+         tristate '  Digiboard PC/Xx Support' CONFIG_DIGI
+      fi
    fi
    dep_tristate '  Hayes ESP serial port support' CONFIG_ESPSERIAL $CONFIG_ISA
    tristate '  Moxa Intellio support' CONFIG_MOXA_INTELLIO
@@ -51,15 +57,15 @@
    tristate '  HDLC line discipline support' CONFIG_N_HDLC
    tristate '  SDL RISCom/8 card support' CONFIG_RISCOM8
    if [ "$CONFIG_X86_64" != "y" ]; then
-   tristate '  Specialix IO8+ card support' CONFIG_SPECIALIX
-   if [ "$CONFIG_SPECIALIX" != "n" ]; then
-      bool '  Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
-   fi 
-   tristate '  Specialix SX (and SI) card support' CONFIG_SX
-   tristate '  Specialix RIO system support' CONFIG_RIO
-   if [ "$CONFIG_RIO" != "n" ]; then
-     bool '    Support really old RIO/PCI cards' CONFIG_RIO_OLDPCI
-   fi
+      tristate '  Specialix IO8+ card support' CONFIG_SPECIALIX
+      if [ "$CONFIG_SPECIALIX" != "n" ]; then
+         bool '  Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
+      fi 
+      tristate '  Specialix SX (and SI) card support' CONFIG_SX
+      tristate '  Specialix RIO system support' CONFIG_RIO
+      if [ "$CONFIG_RIO" != "n" ]; then
+        bool '    Support really old RIO/PCI cards' CONFIG_RIO_OLDPCI
+      fi
    fi
    bool '  Stallion multiport serial support' CONFIG_STALDRV
    if [ "$CONFIG_STALDRV" = "y" ]; then
@@ -109,6 +115,9 @@
          bool '        Enable Au1000 serial console' CONFIG_AU1000_SERIAL_CONSOLE
      fi
    fi
+   if [ "$CONFIG_PARISC" = "y" ]; then
+     bool '  PDC software console support' CONFIG_PDC_CONSOLE
+   fi
 fi
 if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
    bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD
@@ -244,7 +253,7 @@
 tristate 'Siemens R3964 line discipline' CONFIG_R3964
 tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM
 if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X86" = "y" -a "$CONFIG_X86_64" != "y" ]; then
-   dep_tristate 'Sony Vaio Programmable I/O Control Device support' CONFIG_SONYPI $CONFIG_PCI
+   dep_tristate 'Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)' CONFIG_SONYPI $CONFIG_PCI
 fi
 
 mainmenu_option next_comment
diff -urN linux-2.4.20-pre1/drivers/char/Makefile linux-2.4.20-pre2/drivers/char/Makefile
--- linux-2.4.20-pre1/drivers/char/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/char/Makefile	Mon Aug 12 16:34:16 2002
@@ -24,7 +24,7 @@
 export-objs     :=	busmouse.o console.o keyboard.o sysrq.o \
 			misc.o pty.o random.o selection.o serial.o \
 			sonypi.o tty_io.o tty_ioctl.o generic_serial.o \
-			au1000_gpio.o
+			au1000_gpio.o hp_psaux.o
 
 mod-subdirs	:=	joystick ftape drm drm-4.0 pcmcia
 
@@ -71,6 +71,17 @@
   SERIAL = serial.o
 endif
 
+ifeq ($(ARCH),parisc)
+   ifdef CONFIG_GSC_PS2
+      KEYBD   = hp_psaux.o hp_keyb.o
+   else
+      KEYBD   =
+   endif
+   ifdef CONFIG_PDC_CONSOLE
+      CONSOLE += pdc_console.o
+   endif
+endif
+
 ifeq ($(ARCH),arm)
   ifneq ($(CONFIG_PC_KEYMAP),y)
     KEYMAP   =
@@ -150,6 +161,7 @@
   obj-$(CONFIG_PCI) += keyboard.o $(KEYMAP)
 endif
 
+obj-$(CONFIG_HIL) += hp_keyb.o
 obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
 obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
 obj-$(CONFIG_ROCKETPORT) += rocket.o
diff -urN linux-2.4.20-pre1/drivers/char/cyclades.c linux-2.4.20-pre2/drivers/char/cyclades.c
--- linux-2.4.20-pre1/drivers/char/cyclades.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/char/cyclades.c	Mon Aug 12 16:34:16 2002
@@ -3446,8 +3446,8 @@
 		}
 #ifdef CY_DEBUG_DTR
 		printk("cyc:set_line_char dropping DTR\n");
-		printk("     status: 0x%x,
-		    0x%x\n", cy_readb(base_addr+(CyMSVR1<<index)),
+		printk("     status: 0x%x, 0x%x\n", 
+		    cy_readb(base_addr+(CyMSVR1<<index)),
 		    cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
 	    }else{
diff -urN linux-2.4.20-pre1/drivers/char/drm/mga_drv.h linux-2.4.20-pre2/drivers/char/drm/mga_drv.h
--- linux-2.4.20-pre1/drivers/char/drm/mga_drv.h	Mon Aug 27 07:40:33 2001
+++ linux-2.4.20-pre2/drivers/char/drm/mga_drv.h	Mon Aug 12 16:34:16 2002
@@ -38,7 +38,7 @@
 
 	u32 tail;
 	int space;
-	volatile int wrapped;
+	volatile long wrapped;
 
 	volatile u32 *status;
 
diff -urN linux-2.4.20-pre1/drivers/char/ftape/Config.in linux-2.4.20-pre2/drivers/char/ftape/Config.in
--- linux-2.4.20-pre1/drivers/char/ftape/Config.in	Mon Jan 24 11:04:37 2000
+++ linux-2.4.20-pre2/drivers/char/ftape/Config.in	Mon Aug 12 16:34:16 2002
@@ -35,7 +35,7 @@
    int '  Maximal data rate to use (EXPERIMENTAL)' CONFIG_FT_FDC_MAX_RATE 2000
 fi
 
-if [ "$ARCH" = "alpha" ]; then
+if [ "$CONFIG_ALPHA" = "y" ]; then
    int '  CPU clock frequency of your DEC Alpha' CONFIG_FT_ALPHA_CLOCK 0
 else
    define_int CONFIG_FT_ALPHA_CLOCK 0
diff -urN linux-2.4.20-pre1/drivers/char/ip2main.c linux-2.4.20-pre2/drivers/char/ip2main.c
--- linux-2.4.20-pre1/drivers/char/ip2main.c	Fri Nov  2 17:26:17 2001
+++ linux-2.4.20-pre2/drivers/char/ip2main.c	Mon Aug 12 16:34:16 2002
@@ -1001,12 +1001,10 @@
 	printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
 	       ip2config.addr[boardnum], ip2config.irq[boardnum] );
 
-	if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) {
-		printk(KERN_ERR "IP2: bad addr=0x%x rc = %d\n",
-				ip2config.addr[boardnum], rc );
+	if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
+		printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
 		goto err_initialize;
 	}
-	request_region( ip2config.addr[boardnum], 8, pcName );
 
 	if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size )
 	    != II_DOWN_GOOD ) {
diff -urN linux-2.4.20-pre1/drivers/char/joystick/iforce.c linux-2.4.20-pre2/drivers/char/joystick/iforce.c
--- linux-2.4.20-pre1/drivers/char/joystick/iforce.c	Wed Sep 12 15:34:06 2001
+++ linux-2.4.20-pre2/drivers/char/joystick/iforce.c	Mon Aug 12 16:34:16 2002
@@ -134,7 +134,7 @@
 #ifdef IFORCE_USB
 	struct usb_device *usbdev;	/* USB transfer */
 	struct urb irq, out, ctrl;
-	devrequest dr;
+	struct usb_ctrlrequest dr;
 #endif
 					/* Force Feedback */
 	wait_queue_head_t wait;
@@ -283,7 +283,7 @@
 #ifdef IFORCE_USB
 		case IFORCE_USB:
 
-			iforce->dr.request = packet[0];
+			iforce->dr.bRequest = packet[0];
 			iforce->ctrl.dev = iforce->usbdev;
 
 			set_current_state(TASK_INTERRUPTIBLE);
@@ -1027,9 +1027,9 @@
 	iforce->bus = IFORCE_USB;
 	iforce->usbdev = dev;
 
-	iforce->dr.requesttype = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
-	iforce->dr.index = 0;
-	iforce->dr.length = 16;
+	iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
+	iforce->dr.wIndex = 0;
+	iforce->dr.wLength = 16;
 
 	FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
 			iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
diff -urN linux-2.4.20-pre1/drivers/char/nvram.c linux-2.4.20-pre2/drivers/char/nvram.c
--- linux-2.4.20-pre1/drivers/char/nvram.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/char/nvram.c	Mon Aug 12 16:34:16 2002
@@ -38,12 +38,12 @@
 #include <linux/smp_lock.h>
 
 #define PC		1
-#define ATARI	2
+#define ATARI		2
 
 /* select machine configuration */
 #if defined(CONFIG_ATARI)
 #define MACH ATARI
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and others?? */
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)  /* and others?? */
 #define MACH PC
 #else
 #error Cannot build nvram driver for this machine configuration.
@@ -52,12 +52,12 @@
 #if MACH == PC
 
 /* RTC in a PC */
-#define CHECK_DRIVER_INIT() 1
+#define CHECK_DRIVER_INIT()	1
 
 /* On PCs, the checksum is built only over bytes 2..31 */
 #define PC_CKS_RANGE_START	2
 #define PC_CKS_RANGE_END	31
-#define PC_CKS_LOC			32
+#define PC_CKS_LOC		32
 
 #define	mach_check_checksum	pc_check_checksum
 #define	mach_set_checksum	pc_set_checksum
@@ -70,14 +70,14 @@
 /* Special parameters for RTC in Atari machines */
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
-#define RTC_PORT(x)			(TT_RTC_BAS + 2*(x))
-#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
+#define RTC_PORT(x)		(TT_RTC_BAS + 2*(x))
+#define CHECK_DRIVER_INIT()	(MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
 
 /* On Ataris, the checksum is over all bytes except the checksum bytes
  * themselves; these are at the very end */
 #define ATARI_CKS_RANGE_START	0
-#define ATARI_CKS_RANGE_END		47
-#define ATARI_CKS_LOC			48
+#define ATARI_CKS_RANGE_END	47
+#define ATARI_CKS_LOC		48
 
 #define	mach_check_checksum	atari_check_checksum
 #define	mach_set_checksum	atari_set_checksum
@@ -108,44 +108,49 @@
 #include <asm/system.h>
 
 static int nvram_open_cnt;	/* #times opened */
-static int nvram_open_mode;		/* special open modes */
-#define	NVRAM_WRITE		1		/* opened for writing (exclusive) */
-#define	NVRAM_EXCL		2		/* opened with O_EXCL */
+static int nvram_open_mode;	/* special open modes */
 
-#define	RTC_FIRST_BYTE		14	/* RTC register number of first NVRAM byte */
-#define	NVRAM_BYTES			128-RTC_FIRST_BYTE	/* number of NVRAM bytes */
+#define	NVRAM_WRITE		1	/* opened for writing (exclusive) */
+#define	NVRAM_EXCL		2	/* opened with O_EXCL */
 
+#define	RTC_FIRST_BYTE		14	/* RTC register number of first
+					 * NVRAM byte */
+#define	NVRAM_BYTES		128-RTC_FIRST_BYTE /* number of NVRAM bytes */
+
+static int mach_check_checksum(void);
+static void mach_set_checksum(void);
 
-static int mach_check_checksum( void );
-static void mach_set_checksum( void );
 #ifdef CONFIG_PROC_FS
-static int mach_proc_infos( unsigned char *contents, char *buffer, int *len,
-							off_t *begin, off_t offset, int size );
+static int mach_proc_infos(unsigned char *contents, char *buffer, int *len,
+    off_t *begin, off_t offset, int size);
 #endif
 
-
 /*
  * These are the internal NVRAM access functions, which do NOT disable
  * interrupts and do not check the checksum. Both tasks are left to higher
  * level function, so they need to be done only once per syscall.
  */
 
-static __inline__ unsigned char nvram_read_int( int i )
+static __inline__ unsigned char
+nvram_read_int(int i)
 {
-	return( CMOS_READ( RTC_FIRST_BYTE+i ) );
+	return CMOS_READ(RTC_FIRST_BYTE + i);
 }
 
-static __inline__ void nvram_write_int( unsigned char c, int i )
+static __inline__ void
+nvram_write_int(unsigned char c, int i)
 {
-	CMOS_WRITE( c, RTC_FIRST_BYTE+i );
+	CMOS_WRITE(c, RTC_FIRST_BYTE + i);
 }
 
-static __inline__ int nvram_check_checksum_int( void )
+static __inline__ int
+nvram_check_checksum_int(void)
 {
-	return( mach_check_checksum() );
+	return mach_check_checksum();
 }
 
-static __inline__ void nvram_set_checksum_int( void )
+static __inline__ void
+nvram_set_checksum_int(void)
 {
 	mach_set_checksum();
 }
@@ -163,183 +168,190 @@
  * module), so they access config information themselves.
  */
 
-unsigned char nvram_read_byte( int i )
+unsigned char
+nvram_read_byte(int i)
 {
 	unsigned long flags;
 	unsigned char c;
 
-	spin_lock_irqsave (&rtc_lock, flags);
-	c = nvram_read_int( i );
-	spin_unlock_irqrestore (&rtc_lock, flags);
-	return( c );
+	spin_lock_irqsave(&rtc_lock, flags);
+	c = nvram_read_int(i);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+	return c;
 }
 
 /* This races nicely with trying to read with checksum checking (nvram_read) */
-void nvram_write_byte( unsigned char c, int i )
+void
+nvram_write_byte(unsigned char c, int i)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave (&rtc_lock, flags);
-	nvram_write_int( c, i );
-	spin_unlock_irqrestore (&rtc_lock, flags);
+	spin_lock_irqsave(&rtc_lock, flags);
+	nvram_write_int(c, i);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 }
 
-int nvram_check_checksum( void )
+int
+nvram_check_checksum(void)
 {
 	unsigned long flags;
 	int rv;
 
-	spin_lock_irqsave (&rtc_lock, flags);
+	spin_lock_irqsave(&rtc_lock, flags);
 	rv = nvram_check_checksum_int();
-	spin_unlock_irqrestore (&rtc_lock, flags);
-	return( rv );
+	spin_unlock_irqrestore(&rtc_lock, flags);
+	return rv;
 }
 
-void nvram_set_checksum( void )
+void
+nvram_set_checksum(void)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave (&rtc_lock, flags);
+	spin_lock_irqsave(&rtc_lock, flags);
 	nvram_set_checksum_int();
-	spin_unlock_irqrestore (&rtc_lock, flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 }
 
 #endif /* MACH == ATARI */
 
-
 /*
  * The are the file operation function for user access to /dev/nvram
  */
 
-static long long nvram_llseek(struct file *file,loff_t offset, int origin )
+static long long
+nvram_llseek(struct file *file, loff_t offset, int origin)
 {
-	switch( origin ) {
-	  case 0:
+	switch (origin) {
+	case 0:
 		/* nothing to do */
 		break;
-	  case 1:
+	case 1:
 		offset += file->f_pos;
 		break;
-	  case 2:
+	case 2:
 		offset += NVRAM_BYTES;
 		break;
 	}
-	return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
+	return (offset >= 0) ? (file->f_pos = offset) : -EINVAL;
 }
 
-static ssize_t nvram_read(struct file * file,
-	char * buf, size_t count, loff_t *ppos )
+static ssize_t
+nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
-	char contents [NVRAM_BYTES];
+	char contents[NVRAM_BYTES];
 	unsigned i = *ppos;
 	char *tmp;
 
-	spin_lock_irq (&rtc_lock);
-	
+	spin_lock_irq(&rtc_lock);
+
 	if (!nvram_check_checksum_int())
 		goto checksum_err;
 
 	for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp)
 		*tmp = nvram_read_int(i);
 
-	spin_unlock_irq (&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
 
-	if (copy_to_user (buf, contents, tmp - contents))
+	if (copy_to_user(buf, contents, tmp - contents))
 		return -EFAULT;
 
 	*ppos = i;
 
-	return (tmp - contents);
+	return tmp - contents;
 
-checksum_err:
-	spin_unlock_irq (&rtc_lock);
+      checksum_err:
+	spin_unlock_irq(&rtc_lock);
 	return -EIO;
 }
 
-static ssize_t nvram_write(struct file * file,
-		const char * buf, size_t count, loff_t *ppos )
+static ssize_t
+nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-	char contents [NVRAM_BYTES];
+	char contents[NVRAM_BYTES];
 	unsigned i = *ppos;
-	char * tmp;
+	char *tmp;
 
-	if (copy_from_user (contents, buf, (NVRAM_BYTES - i) < count ?
-						(NVRAM_BYTES - i) : count))
+	if (copy_from_user(contents, buf, (NVRAM_BYTES - i) < count ?
+	    (NVRAM_BYTES - i) : count))
 		return -EFAULT;
 
-	spin_lock_irq (&rtc_lock);
+	spin_lock_irq(&rtc_lock);
 
 	if (!nvram_check_checksum_int())
 		goto checksum_err;
 
 	for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp)
-		nvram_write_int (*tmp, i);
+		nvram_write_int(*tmp, i);
 
 	nvram_set_checksum_int();
 
-	spin_unlock_irq (&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
 
 	*ppos = i;
 
-	return (tmp - contents);
+	return tmp - contents;
 
-checksum_err:
-	spin_unlock_irq (&rtc_lock);
+      checksum_err:
+	spin_unlock_irq(&rtc_lock);
 	return -EIO;
 }
 
-static int nvram_ioctl( struct inode *inode, struct file *file,
-						unsigned int cmd, unsigned long arg )
+static int
+nvram_ioctl(struct inode *inode, struct file *file,
+    unsigned int cmd, unsigned long arg)
 {
 	int i;
-	
-	switch( cmd ) {
 
-	  case NVRAM_INIT:			/* initialize NVRAM contents and checksum */
+	switch (cmd) {
+
+	case NVRAM_INIT:	/* initialize NVRAM contents and checksum */
 		if (!capable(CAP_SYS_ADMIN))
-			return( -EACCES );
+			return -EACCES;
 
-		spin_lock_irq (&rtc_lock);
+		spin_lock_irq(&rtc_lock);
 
-		for( i = 0; i < NVRAM_BYTES; ++i )
-			nvram_write_int( 0, i );
+		for (i = 0; i < NVRAM_BYTES; ++i)
+			nvram_write_int(0, i);
 		nvram_set_checksum_int();
-		
-		spin_unlock_irq (&rtc_lock);
-		return( 0 );
-	  
-	  case NVRAM_SETCKS:		/* just set checksum, contents unchanged
-								 * (maybe useful after checksum garbaged
-								 * somehow...) */
+
+		spin_unlock_irq(&rtc_lock);
+		return 0;
+
+	case NVRAM_SETCKS:	/* just set checksum, contents unchanged
+				 * (maybe useful after checksum garbaged
+				 * somehow...) */
 		if (!capable(CAP_SYS_ADMIN))
-			return( -EACCES );
+			return -EACCES;
 
-		spin_lock_irq (&rtc_lock);
+		spin_lock_irq(&rtc_lock);
 		nvram_set_checksum_int();
-		spin_unlock_irq (&rtc_lock);
-		return( 0 );
+		spin_unlock_irq(&rtc_lock);
+		return 0;
 
-	  default:
-		return( -ENOTTY );
+	default:
+		return -ENOTTY;
 	}
 }
 
-static int nvram_open( struct inode *inode, struct file *file )
+static int
+nvram_open(struct inode *inode, struct file *file)
 {
 	if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
-		(nvram_open_mode & NVRAM_EXCL) ||
-		((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE)))
-		return( -EBUSY );
+	    (nvram_open_mode & NVRAM_EXCL) ||
+	    ((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE)))
+		return -EBUSY;
 
 	if (file->f_flags & O_EXCL)
 		nvram_open_mode |= NVRAM_EXCL;
 	if (file->f_mode & 2)
 		nvram_open_mode |= NVRAM_WRITE;
 	nvram_open_cnt++;
-	return( 0 );
+	return 0;
 }
 
-static int nvram_release( struct inode *inode, struct file *file )
+static int
+nvram_release(struct inode *inode, struct file *file)
 {
 	lock_kernel();
 	nvram_open_cnt--;
@@ -349,47 +361,51 @@
 		nvram_open_mode &= ~NVRAM_WRITE;
 	unlock_kernel();
 
-	return( 0 );
+	return 0;
 }
 
-
 #ifndef CONFIG_PROC_FS
-static int nvram_read_proc( char *buffer, char **start, off_t offset,
-			    int size, int *eof, void *data) { return 0; }
+static int
+nvram_read_proc(char *buffer, char **start, off_t offset,
+    int size, int *eof, void *data)
+{
+	return 0;
+}
 #else
 
-static int nvram_read_proc( char *buffer, char **start, off_t offset,
-							int size, int *eof, void *data )
+static int
+nvram_read_proc(char *buffer, char **start, off_t offset,
+    int size, int *eof, void *data)
 {
 	unsigned char contents[NVRAM_BYTES];
-    int i, len = 0;
-    off_t begin = 0;
+	int i, len = 0;
+	off_t begin = 0;
+
+	spin_lock_irq(&rtc_lock);
+	for (i = 0; i < NVRAM_BYTES; ++i)
+		contents[i] = nvram_read_int(i);
+	spin_unlock_irq(&rtc_lock);
+
+	*eof = mach_proc_infos(contents, buffer, &len, &begin, offset, size);
+
+	if (offset >= begin + len)
+		return 0;
+	*start = buffer + (offset - begin);
+	return (size < begin + len - offset) ? size : begin + len - offset;
 
-	spin_lock_irq (&rtc_lock);
-	for( i = 0; i < NVRAM_BYTES; ++i )
-		contents[i] = nvram_read_int( i );
-	spin_unlock_irq (&rtc_lock);
-	
-	*eof = mach_proc_infos( contents, buffer, &len, &begin, offset, size );
-
-    if (offset >= begin + len)
-		return( 0 );
-    *start = buffer + (offset - begin);
-    return( size < begin + len - offset ? size : begin + len - offset );
-	
 }
 
 /* This macro frees the machine specific function from bounds checking and
  * this like that... */
-#define	PRINT_PROC(fmt,args...)							\
-	do {												\
-		*len += sprintf( buffer+*len, fmt, ##args );	\
-		if (*begin + *len > offset + size)				\
-			return( 0 );								\
-		if (*begin + *len < offset) {					\
-			*begin += *len;								\
-			*len = 0;									\
-		}												\
+#define	PRINT_PROC(fmt,args...)					\
+	do {							\
+		*len += sprintf(buffer+*len, fmt, ##args);	\
+		if (*begin + *len > offset + size)		\
+			return 0;				\
+		if (*begin + *len < offset) {			\
+			*begin += *len;				\
+			*len = 0;				\
+		}						\
 	} while(0)
 
 #endif /* CONFIG_PROC_FS */
@@ -410,72 +426,74 @@
 	&nvram_fops
 };
 
-
-static int __init nvram_init(void)
+static int __init
+nvram_init(void)
 {
 	int ret;
 
 	/* First test whether the driver should init at all */
 	if (!CHECK_DRIVER_INIT())
-	    return( -ENXIO );
+		return -ENXIO;
 
-	ret = misc_register( &nvram_dev );
+	ret = misc_register(&nvram_dev);
 	if (ret) {
-		printk(KERN_ERR "nvram: can't misc_register on minor=%d\n", NVRAM_MINOR);
+		printk(KERN_ERR "nvram: can't misc_register on minor=%d\n",
+		    NVRAM_MINOR);
 		goto out;
 	}
-	if (!create_proc_read_entry("driver/nvram",0,0,nvram_read_proc,NULL)) {
+	if (!create_proc_read_entry("driver/nvram", 0, 0, nvram_read_proc,
+		NULL)) {
 		printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n");
 		ret = -ENOMEM;
 		goto outmisc;
 	}
 	ret = 0;
 	printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n");
-out:
-	return( ret );
-outmisc:
-	misc_deregister( &nvram_dev );
+      out:
+	return ret;
+      outmisc:
+	misc_deregister(&nvram_dev);
 	goto out;
 }
 
-static void __exit nvram_cleanup_module (void)
+static void __exit
+nvram_cleanup_module(void)
 {
-	remove_proc_entry( "driver/nvram", 0 );
-	misc_deregister( &nvram_dev );
+	remove_proc_entry("driver/nvram", 0);
+	misc_deregister(&nvram_dev);
 }
 
 module_init(nvram_init);
 module_exit(nvram_cleanup_module);
 
-
 /*
  * Machine specific functions
  */
 
-
 #if MACH == PC
 
-static int pc_check_checksum( void )
+static int
+pc_check_checksum(void)
 {
 	int i;
 	unsigned short sum = 0;
-	
-	for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
-		sum += nvram_read_int( i );
-	return( (sum & 0xffff) ==
-			((nvram_read_int(PC_CKS_LOC) << 8) |
-			 nvram_read_int(PC_CKS_LOC+1)) );
+
+	for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
+		sum += nvram_read_int(i);
+	return ((sum & 0xffff) ==
+	    ((nvram_read_int(PC_CKS_LOC)<<8) | nvram_read_int(PC_CKS_LOC+1)));
 }
 
-static void pc_set_checksum( void )
+static void
+pc_set_checksum(void)
 {
 	int i;
 	unsigned short sum = 0;
-	
-	for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
-		sum += nvram_read_int( i );
-	nvram_write_int( sum >> 8, PC_CKS_LOC );
-	nvram_write_int( sum & 0xff, PC_CKS_LOC+1 );
+
+	for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
+		sum += nvram_read_int(i);
+	nvram_write_int(sum >> 8, PC_CKS_LOC);
+	nvram_write_int(sum & 0xff, PC_CKS_LOC + 1);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -492,69 +510,67 @@
 	"monochrome",
 };
 
-static int pc_proc_infos( unsigned char *nvram, char *buffer, int *len,
-						  off_t *begin, off_t offset, int size )
+static int
+pc_proc_infos(unsigned char *nvram, char *buffer, int *len,
+    off_t *begin, off_t offset, int size)
 {
 	int checksum;
 	int type;
 
-	spin_lock_irq (&rtc_lock);
+	spin_lock_irq(&rtc_lock);
 	checksum = nvram_check_checksum_int();
-	spin_unlock_irq (&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
 
-	PRINT_PROC( "Checksum status: %svalid\n", checksum ? "" : "not " );
+	PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not ");
 
-	PRINT_PROC( "# floppies     : %d\n",
-				(nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0 );
-	PRINT_PROC( "Floppy 0 type  : " );
+	PRINT_PROC("# floppies     : %d\n",
+	    (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0);
+	PRINT_PROC("Floppy 0 type  : ");
 	type = nvram[2] >> 4;
-	if (type < sizeof(floppy_types)/sizeof(*floppy_types))
-		PRINT_PROC( "%s\n", floppy_types[type] );
+	if (type < sizeof (floppy_types) / sizeof (*floppy_types))
+		PRINT_PROC("%s\n", floppy_types[type]);
 	else
-		PRINT_PROC( "%d (unknown)\n", type );
-	PRINT_PROC( "Floppy 1 type  : " );
+		PRINT_PROC("%d (unknown)\n", type);
+	PRINT_PROC("Floppy 1 type  : ");
 	type = nvram[2] & 0x0f;
-	if (type < sizeof(floppy_types)/sizeof(*floppy_types))
-		PRINT_PROC( "%s\n", floppy_types[type] );
+	if (type < sizeof (floppy_types) / sizeof (*floppy_types))
+		PRINT_PROC("%s\n", floppy_types[type]);
 	else
-		PRINT_PROC( "%d (unknown)\n", type );
+		PRINT_PROC("%d (unknown)\n", type);
 
-	PRINT_PROC( "HD 0 type      : " );
+	PRINT_PROC("HD 0 type      : ");
 	type = nvram[4] >> 4;
 	if (type)
-		PRINT_PROC( "%02x\n", type == 0x0f ? nvram[11] : type );
+		PRINT_PROC("%02x\n", type == 0x0f ? nvram[11] : type);
 	else
-		PRINT_PROC( "none\n" );
+		PRINT_PROC("none\n");
 
-	PRINT_PROC( "HD 1 type      : " );
+	PRINT_PROC("HD 1 type      : ");
 	type = nvram[4] & 0x0f;
 	if (type)
-		PRINT_PROC( "%02x\n", type == 0x0f ? nvram[12] : type );
+		PRINT_PROC("%02x\n", type == 0x0f ? nvram[12] : type);
 	else
-		PRINT_PROC( "none\n" );
+		PRINT_PROC("none\n");
+
+	PRINT_PROC("HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+	    nvram[18] | (nvram[19] << 8),
+	    nvram[20], nvram[25],
+	    nvram[21] | (nvram[22] << 8), nvram[23] | (nvram[24] << 8));
+	PRINT_PROC("HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+	    nvram[39] | (nvram[40] << 8),
+	    nvram[41], nvram[46],
+	    nvram[42] | (nvram[43] << 8), nvram[44] | (nvram[45] << 8));
+
+	PRINT_PROC("DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8));
+	PRINT_PROC("Extended memory: %d kB (configured), %d kB (tested)\n",
+	    nvram[9] | (nvram[10] << 8), nvram[34] | (nvram[35] << 8));
 
-	PRINT_PROC( "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
-				nvram[18] | (nvram[19] << 8),
-				nvram[20], nvram[25],
-				nvram[21] | (nvram[22] << 8),
-				nvram[23] | (nvram[24] << 8) );
-	PRINT_PROC( "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
-				nvram[39] | (nvram[40] << 8),
-				nvram[41], nvram[46],
-				nvram[42] | (nvram[43] << 8),
-				nvram[44] | (nvram[45] << 8) );
-
-	PRINT_PROC( "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8) );
-	PRINT_PROC( "Extended memory: %d kB (configured), %d kB (tested)\n",
-				nvram[9] | (nvram[10] << 8),
-				nvram[34] | (nvram[35] << 8) );
-
-	PRINT_PROC( "Gfx adapter    : %s\n", gfx_types[ (nvram[6] >> 4)&3 ] );
-
-	PRINT_PROC( "FPU            : %sinstalled\n",
-				(nvram[6] & 2) ? "" : "not " );
-	
-	return( 1 );
+	PRINT_PROC("Gfx adapter    : %s\n", gfx_types[(nvram[6] >> 4) & 3]);
+
+	PRINT_PROC("FPU            : %sinstalled\n",
+	    (nvram[6] & 2) ? "" : "not ");
+
+	return 1;
 }
 #endif
 
@@ -562,26 +578,28 @@
 
 #if MACH == ATARI
 
-static int atari_check_checksum( void )
+static int
+atari_check_checksum(void)
 {
 	int i;
 	unsigned char sum = 0;
-	
-	for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
-		sum += nvram_read_int( i );
-	return( nvram_read_int( ATARI_CKS_LOC ) == (~sum & 0xff) &&
-			nvram_read_int( ATARI_CKS_LOC+1 ) == (sum & 0xff) );
+
+	for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
+		sum += nvram_read_int(i);
+	return (nvram_read_int(ATARI_CKS_LOC) == (~sum & 0xff) &&
+	    nvram_read_int(ATARI_CKS_LOC + 1) == (sum & 0xff));
 }
 
-static void atari_set_checksum( void )
+static void
+atari_set_checksum(void)
 {
 	int i;
 	unsigned char sum = 0;
-	
-	for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
-		sum += nvram_read_int( i );
-	nvram_write_int( ~sum, ATARI_CKS_LOC );
-	nvram_write_int( sum, ATARI_CKS_LOC+1 );
+
+	for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
+		sum += nvram_read_int(i);
+	nvram_write_int(~sum, ATARI_CKS_LOC);
+	nvram_write_int(sum, ATARI_CKS_LOC + 1);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -626,70 +644,71 @@
 
 #define fieldsize(a)	(sizeof(a)/sizeof(*a))
 
-static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
-			    off_t *begin, off_t offset, int size )
+static int
+atari_proc_infos(unsigned char *nvram, char *buffer, int *len,
+    off_t *begin, off_t offset, int size)
 {
 	int checksum = nvram_check_checksum();
 	int i;
 	unsigned vmode;
-	
-	PRINT_PROC( "Checksum status  : %svalid\n", checksum ? "" : "not " );
 
-	PRINT_PROC( "Boot preference  : " );
-	for( i = fieldsize(boot_prefs)-1; i >= 0; --i ) {
+	PRINT_PROC("Checksum status  : %svalid\n", checksum ? "" : "not ");
+
+	PRINT_PROC("Boot preference  : ");
+	for (i = fieldsize(boot_prefs) - 1; i >= 0; --i) {
 		if (nvram[1] == boot_prefs[i].val) {
-			PRINT_PROC( "%s\n", boot_prefs[i].name );
+			PRINT_PROC("%s\n", boot_prefs[i].name);
 			break;
 		}
 	}
 	if (i < 0)
-		PRINT_PROC( "0x%02x (undefined)\n", nvram[1] );
+		PRINT_PROC("0x%02x (undefined)\n", nvram[1]);
 
-	PRINT_PROC( "SCSI arbitration : %s\n", (nvram[16] & 0x80) ? "on" : "off" );
-	PRINT_PROC( "SCSI host ID     : " );
+	PRINT_PROC("SCSI arbitration : %s\n",
+	    (nvram[16] & 0x80) ? "on" : "off");
+	PRINT_PROC("SCSI host ID     : ");
 	if (nvram[16] & 0x80)
-		PRINT_PROC( "%d\n", nvram[16] & 7 );
+		PRINT_PROC("%d\n", nvram[16] & 7);
 	else
-		PRINT_PROC( "n/a\n" );
+		PRINT_PROC("n/a\n");
 
 	/* the following entries are defined only for the Falcon */
 	if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
 		return 1;
 
-	PRINT_PROC( "OS language      : " );
+	PRINT_PROC("OS language      : ");
 	if (nvram[6] < fieldsize(languages))
-		PRINT_PROC( "%s\n", languages[nvram[6]] );
+		PRINT_PROC("%s\n", languages[nvram[6]]);
 	else
-		PRINT_PROC( "%u (undefined)\n", nvram[6] );
-	PRINT_PROC( "Keyboard language: " );
+		PRINT_PROC("%u (undefined)\n", nvram[6]);
+	PRINT_PROC("Keyboard language: ");
 	if (nvram[7] < fieldsize(languages))
-		PRINT_PROC( "%s\n", languages[nvram[7]] );
+		PRINT_PROC("%s\n", languages[nvram[7]]);
 	else
-		PRINT_PROC( "%u (undefined)\n", nvram[7] );
-	PRINT_PROC( "Date format      : " );
-	PRINT_PROC( dateformat[nvram[8]&7],
-				nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/' );
-	PRINT_PROC( ", %dh clock\n", nvram[8] & 16 ? 24 : 12 );
-	PRINT_PROC( "Boot delay       : " );
+		PRINT_PROC("%u (undefined)\n", nvram[7]);
+	PRINT_PROC("Date format      : ");
+	PRINT_PROC(dateformat[nvram[8] & 7],
+	    nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/');
+	PRINT_PROC(", %dh clock\n", nvram[8] & 16 ? 24 : 12);
+	PRINT_PROC("Boot delay       : ");
 	if (nvram[10] == 0)
-		PRINT_PROC( "default" );
+		PRINT_PROC("default");
 	else
-		PRINT_PROC( "%ds%s\n", nvram[10],
-					nvram[10] < 8 ? ", no memory test" : "" );
+		PRINT_PROC("%ds%s\n", nvram[10],
+		    nvram[10] < 8 ? ", no memory test" : "");
 
 	vmode = (nvram[14] << 8) || nvram[15];
-	PRINT_PROC( "Video mode       : %s colors, %d columns, %s %s monitor\n",
-				colors[vmode & 7],
-				vmode & 8 ? 80 : 40,
-				vmode & 16 ? "VGA" : "TV",
-				vmode & 32 ? "PAL" : "NTSC" );
-	PRINT_PROC( "                   %soverscan, compat. mode %s%s\n",
-				vmode & 64 ? "" : "no ",
-				vmode & 128 ? "on" : "off",
-				vmode & 256 ?
-				  (vmode & 16 ? ", line doubling" : ", half screen") : "" );
-		
-	return( 1 );
+	PRINT_PROC("Video mode       : %s colors, %d columns, %s %s monitor\n",
+	    colors[vmode & 7],
+	    vmode & 8 ? 80 : 40,
+	    vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC");
+	PRINT_PROC("                   %soverscan, compat. mode %s%s\n",
+	    vmode & 64 ? "" : "no ",
+	    vmode & 128 ? "on" : "off",
+	    vmode & 256 ?
+	    (vmode & 16 ? ", line doubling" : ", half screen") : "");
+
+	return 1;
 }
 #endif
 
@@ -698,11 +717,3 @@
 MODULE_LICENSE("GPL");
 
 EXPORT_NO_SYMBOLS;
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */
-
diff -urN linux-2.4.20-pre1/drivers/char/pcxx.c linux-2.4.20-pre2/drivers/char/pcxx.c
--- linux-2.4.20-pre1/drivers/char/pcxx.c	Thu Sep 13 15:21:32 2001
+++ linux-2.4.20-pre2/drivers/char/pcxx.c	Mon Aug 12 16:34:16 2002
@@ -153,7 +153,6 @@
 DECLARE_TASK_QUEUE(tq_pcxx);
 
 static void pcxxpoll(unsigned long dummy);
-static void pcxxdelay(int);
 static void fepcmd(struct channel *, int, int, int, int, int);
 static void pcxe_put_char(struct tty_struct *, unsigned char);
 static void pcxe_flush_chars(struct tty_struct *);
@@ -1271,7 +1270,7 @@
 	for(crd=0; crd < numcards; crd++) {
 		bd = &boards[crd];
 		outb(FEPRST, bd->port);
-		pcxxdelay(1);
+		mdelay(1);
 
 		for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
 			if(i > 100) {
@@ -1283,7 +1282,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(10);
+			mdelay(10);
 		}
 		if(bd->status == DISABLED)
 			continue;
@@ -1362,7 +1361,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(1);
+			mdelay(1);
 		}
 		if(bd->status == DISABLED)
 			continue;
@@ -1413,7 +1412,7 @@
 #ifdef MODULE
 				schedule();
 #endif
-				pcxxdelay(50);
+				mdelay(50);
 			}
 
 			printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
@@ -1443,7 +1442,7 @@
 #ifdef MODULE
 				schedule();
 #endif
-				pcxxdelay(10);
+				mdelay(10);
 			}
 
 			printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
@@ -1487,7 +1486,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(1);
+			mdelay(1);
 		}
 
 		if(bd->status == DISABLED)
@@ -1520,7 +1519,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(1);
+			mdelay(1);
 		}
 		if(bd->status == DISABLED)
 			continue;
@@ -1825,15 +1824,6 @@
 }
 
 
-/*
- * pcxxdelay - delays a specified number of milliseconds
- */
-static void pcxxdelay(int msec)
-{
-	mdelay(msec);
-}
-
-
 static void 
 fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
 						int bytecmd)
diff -urN linux-2.4.20-pre1/drivers/char/serial.c linux-2.4.20-pre2/drivers/char/serial.c
--- linux-2.4.20-pre1/drivers/char/serial.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/char/serial.c	Mon Aug 12 16:34:16 2002
@@ -5237,7 +5237,7 @@
 	{	0, }
 };
 
-static void inline avoid_irq_share(struct pci_dev *dev)
+static inline void avoid_irq_share(struct pci_dev *dev)
 {
 	int i, map = 0x1FF8;
 	struct serial_state *state = rs_table;
@@ -5274,7 +5274,7 @@
        return 0;
 }
 
-static int inline check_compatible_id(struct pci_dev *dev)
+static inline int check_compatible_id(struct pci_dev *dev)
 {
        int i;
        for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
diff -urN linux-2.4.20-pre1/drivers/char/toshiba.c linux-2.4.20-pre2/drivers/char/toshiba.c
--- linux-2.4.20-pre1/drivers/char/toshiba.c	Thu Oct 11 09:04:57 2001
+++ linux-2.4.20-pre2/drivers/char/toshiba.c	Mon Aug 12 16:34:16 2002
@@ -84,8 +84,6 @@
 
 MODULE_PARM(tosh_fn, "i");
 
-MODULE_LICENSE("GPL");
-
 
 static int tosh_get_info(char *, char **, off_t, int);
 static int tosh_ioctl(struct inode *, struct file *, unsigned int,
@@ -524,3 +522,10 @@
 	misc_deregister(&tosh_device);
 }
 #endif
+
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(tosh_fn, "User specified Fn key detection port");
+MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
+MODULE_DESCRIPTION("Toshiba laptop SMM driver");
+MODULE_SUPPORTED_DEVICE("toshiba");
+
diff -urN linux-2.4.20-pre1/drivers/char/tpqic02.c linux-2.4.20-pre2/drivers/char/tpqic02.c
--- linux-2.4.20-pre1/drivers/char/tpqic02.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/char/tpqic02.c	Mon Aug 12 16:34:16 2002
@@ -1815,7 +1815,6 @@
 static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
 			       loff_t * ppos)
 {
-	int err;
 	kdev_t dev = filp->f_dentry->d_inode->i_rdev;
 	unsigned short flags = filp->f_flags;
 	unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
@@ -2009,7 +2008,6 @@
 static ssize_t qic02_tape_write(struct file *filp, const char *buf,
 				size_t count, loff_t * ppos)
 {
-	int err;
 	kdev_t dev = filp->f_dentry->d_inode->i_rdev;
 	unsigned short flags = filp->f_flags;
 	unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
diff -urN linux-2.4.20-pre1/drivers/fc4/Config.in linux-2.4.20-pre2/drivers/fc4/Config.in
--- linux-2.4.20-pre1/drivers/fc4/Config.in	Wed Nov  3 14:43:54 1999
+++ linux-2.4.20-pre2/drivers/fc4/Config.in	Mon Aug 12 16:34:16 2002
@@ -7,13 +7,13 @@
 tristate 'Fibre Channel and FC4 SCSI support' CONFIG_FC4
 if [ ! "$CONFIG_FC4" = "n" ]; then
    comment 'FC4 drivers'
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC
       tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL
    fi
    comment 'FC4 targets'
    dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI
    else
       dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI
diff -urN linux-2.4.20-pre1/drivers/hotplug/Makefile linux-2.4.20-pre2/drivers/hotplug/Makefile
--- linux-2.4.20-pre1/drivers/hotplug/Makefile	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/hotplug/Makefile	Mon Aug 12 16:34:16 2002
@@ -4,14 +4,14 @@
 
 O_TARGET	:= vmlinux-obj.o
 
-list-multi	:= cpqphp.o pci_hotplug.o ibmphp.o pcihpacpi.o 
+list-multi	:= cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o 
 
 export-objs	:= pci_hotplug_core.o pci_hotplug_util.o
 
 obj-$(CONFIG_HOTPLUG_PCI)		+= pci_hotplug.o
 obj-$(CONFIG_HOTPLUG_PCI_COMPAQ)	+= cpqphp.o
 obj-$(CONFIG_HOTPLUG_PCI_IBM)		+= ibmphp.o
-obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= pcihpacpi.o
+obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= acpiphp.o
 
 pci_hotplug-objs	:=	pci_hotplug_core.o	\
 				pci_hotplug_util.o
@@ -34,8 +34,10 @@
   endif
 endif
 
-pcihp_acpi_objs		:=	pcihp_acpi.o	\
-				pcihp_acpi_glue.o
+acpiphp_objs		:=	acpiphp_core.o	\
+				acpiphp_glue.o	\
+				acpiphp_pci.o	\
+				acpiphp_res.o
 
 ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y)
 	cpqphp-objs += cpqphp_nvram.o
@@ -53,5 +55,5 @@
 ibmphp.o: $(ibmphp-objs)
 	$(LD) -r -o $@ $(ibmphp-objs)
 
-pcihpacpi.o: $(pcihp_acpi_objs)
-	$(LD) -r -o $@ $(pcihp_acpi_objs)
+acpiphp.o: $(acpiphp_objs)
+	$(LD) -r -o $@ $(acpiphp_objs)
diff -urN linux-2.4.20-pre1/drivers/hotplug/acpiphp.h linux-2.4.20-pre2/drivers/hotplug/acpiphp.h
--- linux-2.4.20-pre1/drivers/hotplug/acpiphp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/hotplug/acpiphp.h	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,322 @@
+/*
+ * ACPI PCI Hot Plug Controller Driver
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>,
+ *		    <h-aono@ap.jp.nec.com>,
+ *		    <t-kouchi@cq.jp.nec.com>
+ *
+ */
+
+#ifndef _ACPIPHP_H
+#define _ACPIPHP_H
+
+#include "include/acpi.h"
+#include "pci_hotplug.h"
+
+#if ACPI_CA_VERSION < 0x20020201
+/* until we get a new version of the ACPI driver for both ia32 and ia64 ... */
+#define acpi_util_eval_error(h,p,s)
+
+static acpi_status
+acpi_evaluate_integer (
+	acpi_handle		handle,
+	acpi_string		pathname,
+	acpi_object_list	*arguments,
+	unsigned long		*data)
+{
+	acpi_status		status = AE_OK;
+	acpi_object		element;
+	acpi_buffer		buffer = {sizeof(acpi_object), &element};
+
+	if (!data)
+		return AE_BAD_PARAMETER;
+
+	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
+	if (ACPI_FAILURE(status)) {
+		acpi_util_eval_error(handle, pathname, status);
+		return status;
+	}
+
+	if (element.type != ACPI_TYPE_INTEGER) {
+		acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
+		return AE_BAD_DATA;
+	}
+
+	*data = element.integer.value;
+
+	return AE_OK;
+}
+#else  /* ACPI_CA_VERSION < 0x20020201 */
+#include "acpi_bus.h"
+#endif
+
+/* compatibility stuff for ACPI CA */
+#ifndef ACPI_MEMORY_RANGE
+#define ACPI_MEMORY_RANGE MEMORY_RANGE
+#endif
+
+#ifndef ACPI_IO_RANGE
+#define ACPI_IO_RANGE IO_RANGE
+#endif
+
+#ifndef ACPI_BUS_NUMBER_RANGE
+#define ACPI_BUS_NUMBER_RANGE BUS_NUMBER_RANGE
+#endif
+
+#ifndef ACPI_PREFETCHABLE_MEMORY
+#define ACPI_PREFETCHABLE_MEMORY PREFETCHABLE_MEMORY
+#endif
+
+#ifndef ACPI_PRODUCER
+#define ACPI_PRODUCER PRODUCER
+#endif
+
+#define dbg(format, arg...)					\
+	do {							\
+		if (debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk (KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
+#define info(format, arg...) printk (KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+#define warn(format, arg...) printk (KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+#define SLOT_MAGIC	0x67267322
+/* name size which is used for entries in pcihpfs */
+#define SLOT_NAME_SIZE	16		/* ACPIxxxx */
+
+struct acpiphp_bridge;
+struct acpiphp_slot;
+struct pci_resource;
+
+/*
+ * struct slot - slot information for each *physical* slot
+ */
+struct slot {
+	u32 magic;
+	u8 number;
+	struct hotplug_slot	*hotplug_slot;
+	struct list_head	slot_list;
+
+	/* if there are multiple corresponding ACPI slot objects,
+	   this points to one of them */
+	struct acpiphp_slot	*acpi_slot;
+};
+
+/*
+ * struct pci_resource - describes pci resource (mem, pfmem, io, bus)
+ */
+struct pci_resource {
+	struct pci_resource * next;
+	u64 base;
+	u32 length;
+};
+
+/**
+ * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters
+ * @cache_line_size in DWORD
+ * @latency_timer in PCI clock
+ * @enable_SERR 0 or 1
+ * @enable_PERR 0 or 1
+ */
+struct hpp_param {
+	u8 cache_line_size;
+	u8 latency_timer;
+	u8 enable_SERR;
+	u8 enable_PERR;
+};
+
+
+/**
+ * struct acpiphp_bridge - PCI bridge information
+ *
+ * for each bridge device in ACPI namespace
+ */
+struct acpiphp_bridge {
+	struct list_head list;
+	acpi_handle handle;
+	struct acpiphp_slot *slots;
+	int type;
+	int nr_slots;
+
+	u8 seg;
+	u8 bus;
+	u8 sub;
+
+	u32 flags;
+
+	/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
+	struct pci_bus *pci_bus;
+
+	/* PCI-to-PCI bridge device */
+	struct pci_dev *pci_dev;
+
+	struct pci_ops *pci_ops;
+
+	/* ACPI 2.0 _HPP parameters */
+	struct hpp_param hpp;
+
+	spinlock_t res_lock;
+
+	/* available resources on this bus */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+};
+
+
+/**
+ * struct acpiphp_slot - PCI slot information
+ *
+ * PCI slot information for each *physical* PCI slot
+ */
+struct acpiphp_slot {
+	struct acpiphp_slot *next;
+	struct acpiphp_bridge *bridge;	/* parent */
+	struct list_head funcs;		/* one slot may have different
+					   objects (i.e. for each function) */
+	struct acpiphp_func *func;	/* functions */
+	struct semaphore crit_sect;
+
+	u32		id;		/* slot id (serial #) for hotplug core */
+	u8		device;		/* pci device# */
+
+	u32		sun;		/* ACPI _SUN (slot unique number) */
+	u32		slotno;		/* slot number relative to bridge */
+	u32		flags;		/* see below */
+};
+
+
+/**
+ * struct acpiphp_func - PCI slot information
+ *
+ * PCI function information for each object in ACPI namespace
+ * typically 8 objects per slot (i.e. for each PCI function)
+ */
+struct acpiphp_func {
+	struct acpiphp_slot *slot;	/* parent */
+
+	struct list_head sibling;
+	struct pci_dev *pci_dev;
+
+	acpi_handle	handle;
+
+	u8		function;	/* pci function# */
+	u32		flags;		/* see below */
+
+	/* resources used for this function */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+};
+
+
+/* PCI bus bridge HID */
+#define ACPI_PCI_HOST_HID		"PNP0A03"
+
+/* PCI BRIDGE type */
+#define BRIDGE_TYPE_HOST		0
+#define BRIDGE_TYPE_P2P			1
+
+/* ACPI _STA method value (ignore bit 4; battery present) */
+#define ACPI_STA_PRESENT		(0x00000001)
+#define ACPI_STA_ENABLED		(0x00000002)
+#define ACPI_STA_SHOW_IN_UI		(0x00000004)
+#define ACPI_STA_FUNCTIONING		(0x00000008)
+#define ACPI_STA_ALL			(0x0000000f)
+
+/* bridge flags */
+#define BRIDGE_HAS_STA		(0x00000001)
+#define BRIDGE_HAS_EJ0		(0x00000002)
+#define BRIDGE_HAS_HPP		(0x00000004)
+#define BRIDGE_HAS_PS0		(0x00000010)
+#define BRIDGE_HAS_PS1		(0x00000020)
+#define BRIDGE_HAS_PS2		(0x00000040)
+#define BRIDGE_HAS_PS3		(0x00000080)
+
+/* slot flags */
+
+#define SLOT_POWEREDON		(0x00000001)
+#define SLOT_ENABLED		(0x00000002)
+#define SLOT_MULTIFUNCTION	(x000000004)
+
+/* function flags */
+
+#define FUNC_HAS_STA		(0x00000001)
+#define FUNC_HAS_EJ0		(0x00000002)
+#define FUNC_HAS_PS0		(0x00000010)
+#define FUNC_HAS_PS1		(0x00000020)
+#define FUNC_HAS_PS2		(0x00000040)
+#define FUNC_HAS_PS3		(0x00000080)
+
+/* not yet */
+#define SLOT_SUPPORT_66MHZ	(0x00010000)
+#define SLOT_SUPPORT_100MHZ	(0x00020000)
+#define SLOT_SUPPORT_133MHZ	(0x00040000)
+#define SLOT_SUPPORT_PCIX	(0x00080000)
+
+/* function prototypes */
+
+/* acpiphp_glue.c */
+extern int acpiphp_glue_init (void);
+extern void acpiphp_glue_exit (void);
+extern int acpiphp_get_num_slots (void);
+extern struct acpiphp_slot *get_slot_from_id (int id);
+typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
+extern int acpiphp_for_each_slot (acpiphp_callback fn, void *data);
+
+extern int acpiphp_check_bridge (struct acpiphp_bridge *bridge);
+extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
+extern int acpiphp_disable_slot (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
+
+/* acpiphp_pci.c */
+extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn);
+extern int acpiphp_configure_slot (struct acpiphp_slot *slot);
+extern int acpiphp_configure_function (struct acpiphp_func *func);
+extern int acpiphp_unconfigure_function (struct acpiphp_func *func);
+extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge);
+extern int acpiphp_init_func_resource (struct acpiphp_func *func);
+
+/* acpiphp_res.c */
+extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size);
+extern struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size);
+extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size);
+extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size);
+extern int acpiphp_resource_sort_and_combine (struct pci_resource **head);
+extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length);
+extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to);
+extern void acpiphp_free_resource (struct pci_resource **res);
+extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */
+extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */
+
+#endif /* _ACPIPHP_H */
diff -urN linux-2.4.20-pre1/drivers/hotplug/acpiphp_core.c linux-2.4.20-pre2/drivers/hotplug/acpiphp_core.c
--- linux-2.4.20-pre1/drivers/hotplug/acpiphp_core.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/hotplug/acpiphp_core.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,470 @@
+/*
+ * ACPI PCI Hot Plug Controller Driver
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>,
+ *                  <h-aono@ap.jp.nec.com>,
+ *		    <t-kouchi@cq.jp.nec.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+static LIST_HEAD(slot_list);
+
+#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE)
+	#define MY_NAME	"acpiphp"
+#else
+	#define MY_NAME	THIS_MODULE->name
+#endif
+
+/* local variables */
+static int debug = 1;			/* XXX set to 0 after debug */
+static int num_slots;
+
+#define DRIVER_VERSION	"0.3"
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>"
+#define DRIVER_DESC	"ACPI Hot Plug PCI Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int hardware_test	(struct hotplug_slot *slot, u32 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
+	owner:			THIS_MODULE,
+	enable_slot:		enable_slot,
+	disable_slot:		disable_slot,
+	set_attention_status:	set_attention_status,
+	hardware_test:		hardware_test,
+	get_power_status:	get_power_status,
+	get_attention_status:	get_attention_status,
+	get_latch_status:	get_latch_status,
+	get_adapter_status:	get_adapter_status,
+};
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check (struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL", function);
+		return -1;
+	}
+	if (slot->magic != SLOT_MAGIC) {
+		dbg("%s - bad magic number for slot", function);
+		return -1;
+	}
+	if (!slot->hotplug_slot) {
+		dbg("%s - slot->hotplug_slot == NULL!", function);
+		return -1;
+	}
+	return 0;
+}
+
+
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
+{ 
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot->private;
+	if (slot_paranoia_check (slot, function))
+                return NULL;
+	return slot;
+}
+
+
+/**
+ * enable_slot - power on and enable a slot
+ * @hotplug_slot: slot to enable
+ *
+ * Actual tasks are done in acpiphp_enable_slot()
+ *
+ */
+static int enable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	/* enable the specified slot */
+	retval = acpiphp_enable_slot (slot->acpi_slot);
+
+	return retval;
+}
+
+
+/**
+ * disable_slot - disable and power off a slot
+ * @hotplug_slot: slot to disable
+ *
+ * Actual tasks are done in acpiphp_disable_slot()
+ *
+ */
+static int disable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	/* disable the specified slot */
+	retval = acpiphp_disable_slot (slot->acpi_slot);
+
+	return retval;
+}
+
+
+/**
+ * set_attention_status - set attention LED
+ *
+ * TBD:
+ * ACPI doesn't have known method to manipulate
+ * attention status LED.
+ *
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+	int retval = 0;
+	
+	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	switch (status) {
+		case 0:
+			/* FIXME turn light off */
+			hotplug_slot->info->attention_status = 0;
+			break;
+
+		case 1:
+		default:
+			/* FIXME turn light on */
+			hotplug_slot->info->attention_status = 1;
+			break;
+	}
+
+	return retval;
+}
+
+
+/**
+ * hardware_test - hardware test
+ *
+ * We have nothing to do for now...
+ *
+ */
+static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	err ("No hardware tests are defined for this driver");
+	retval = -ENODEV;
+
+	return retval;
+}
+
+
+/**
+ * get_power_status - get power status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ * Some platforms may not implement _STA method properly.
+ * In that case, the value returned may not be reliable.
+ *
+ */
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_power_status (slot->acpi_slot);
+
+	return retval;
+}
+
+
+/**
+ * get_attention_status - get attention LED status
+ *
+ * TBD:
+ * ACPI doesn't provide any formal means to access attention LED status.
+ *
+ */
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	int retval = 0;
+	
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	*value = hotplug_slot->info->attention_status;
+
+	return retval;
+}
+
+
+/**
+ * get_latch_status - get latch status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ * ACPI doesn't provide any formal means to access latch status.
+ * Instead, we fake latch status from _STA
+ *
+ */
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_latch_status (slot->acpi_slot);
+
+	return retval;
+}
+
+
+/**
+ * get_adapter_status - get adapter status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ * ACPI doesn't provide any formal means to access adapter status.
+ * Instead, we fake adapter status from _STA
+ *
+ */
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval = 0;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_adapter_status (slot->acpi_slot);
+
+	return retval;
+}
+
+
+static int init_acpi (void)
+{
+	int retval;
+
+	/* initialize internal data structure etc. */
+	retval = acpiphp_glue_init();
+
+	/* read initial number of slots */
+	if (!retval) {
+		num_slots = acpiphp_get_num_slots();
+		if (num_slots == 0)
+			retval = -ENODEV;
+	}
+
+	return retval;
+}
+
+
+static void exit_acpi (void)
+{
+	/* deallocate internal data structures etc. */
+	acpiphp_glue_exit();
+}
+
+
+/**
+ * make_slot_name - make a slot name that appears in pcihpfs
+ * @slot: slot to name
+ *
+ */
+static void make_slot_name (struct slot *slot)
+{
+	snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%x", slot->acpi_slot->sun);
+}
+
+/**
+ * init_slots - initialize 'struct slot' structures for each slot
+ *
+ */
+static int init_slots (void)
+{
+	struct slot *slot;
+	int retval = 0;
+	int i;
+
+	for (i = 0; i < num_slots; ++i) {
+		slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+		if (!slot)
+			return -ENOMEM;
+		memset(slot, 0, sizeof(struct slot));
+
+		slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		if (!slot->hotplug_slot) {
+			kfree (slot);
+			return -ENOMEM;
+		}
+		memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+
+		slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if (!slot->hotplug_slot->info) {
+			kfree (slot->hotplug_slot);
+			kfree (slot);
+			return -ENOMEM;
+		}
+		memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+
+		slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!slot->hotplug_slot->name) {
+			kfree (slot->hotplug_slot->info);
+			kfree (slot->hotplug_slot);
+			kfree (slot);
+			return -ENOMEM;
+		}
+
+		slot->magic = SLOT_MAGIC;
+		slot->number = i;
+
+		slot->hotplug_slot->private = slot;
+		slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
+
+		slot->acpi_slot = get_slot_from_id (i);
+		slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
+		slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot);
+		slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
+		slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
+
+		make_slot_name (slot);
+
+		retval = pci_hp_register (slot->hotplug_slot);
+		if (retval) {
+			err ("pci_hp_register failed with error %d", retval);
+			kfree (slot->hotplug_slot->info);
+			kfree (slot->hotplug_slot->name);
+			kfree (slot->hotplug_slot);
+			kfree (slot);
+			return retval;
+		}
+
+		/* add slot to our internal list */
+		list_add (&slot->slot_list, &slot_list);
+	}
+
+	return retval;
+}
+
+
+static void cleanup_slots (void)
+{
+	struct list_head *tmp;
+	struct slot *slot;
+
+	list_for_each (tmp, &slot_list) {
+		slot = list_entry (tmp, struct slot, slot_list);
+		list_del (&slot->slot_list);
+		pci_hp_deregister (slot->hotplug_slot);
+		kfree (slot->hotplug_slot->info);
+		kfree (slot->hotplug_slot->name);
+		kfree (slot->hotplug_slot);
+		kfree (slot);
+	}
+
+	return;
+}
+
+
+static int __init acpiphp_init(void)
+{
+	int retval;
+
+	/* read all the ACPI info from the system */
+	retval = init_acpi();
+	if (retval)
+		return retval;
+
+	retval = init_slots();
+	if (retval)
+		return retval;
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION);
+	return 0;
+}
+
+
+static void __exit acpiphp_exit(void)
+{
+	cleanup_slots();
+	exit_acpi();
+}
+
+module_init(acpiphp_init);
+module_exit(acpiphp_exit);
diff -urN linux-2.4.20-pre1/drivers/hotplug/acpiphp_glue.c linux-2.4.20-pre2/drivers/hotplug/acpiphp_glue.c
--- linux-2.4.20-pre1/drivers/hotplug/acpiphp_glue.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/hotplug/acpiphp_glue.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,1514 @@
+/*
+ * ACPI PCI HotPlug glue functions to ACPI CA subsystem
+ *
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <t-kouchi@cq.jp.nec.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+static LIST_HEAD(bridge_list);
+
+static int debug = 1;			/* XXX set 0 after debug */
+#define MY_NAME "acpiphp_glue"
+
+static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
+static void handle_hotplug_event_func (acpi_handle, u32, void *);
+static struct pci_ops *default_ops;
+
+/*
+ * initialization & terminatation routines
+ */
+
+/**
+ * is_ejectable - determine if a slot is ejectable
+ * @handle: handle to acpi namespace
+ *
+ * Ejectable slot should satisfy at least these conditions:
+ *
+ *  1. has _ADR method
+ *  2. has _EJ0 method
+ *
+ * optionally
+ *
+ *  1. has _STA method
+ *  2. has _PS0 method
+ *  3. has _PS3 method
+ *  4. ..
+ *
+ */
+static int is_ejectable (acpi_handle handle)
+{
+	acpi_status status;
+	acpi_handle tmp;
+
+	status = acpi_get_handle(handle, "_ADR", &tmp);
+	if (ACPI_FAILURE(status)) {
+		return 0;
+	}
+
+	status = acpi_get_handle(handle, "_EJ0", &tmp);
+	if (ACPI_FAILURE(status)) {
+		return 0;
+	}
+
+	return 1;
+}
+
+
+/* callback routine to check the existence of ejectable slots */
+static acpi_status
+is_ejectable_slot (acpi_handle handle, u32 lvl,	void *context, void **rv)
+{
+	acpi_status status;
+	acpi_handle tmp;
+	int *count = (int *)context;
+
+	if (is_ejectable(handle)) {
+		(*count)++;
+		/* only one ejectable slot is enough */
+		return AE_CTRL_TERMINATE;
+	} else {
+		return AE_OK;
+	}
+}
+
+
+/* callback routine to register each ACPI PCI slot object */
+static acpi_status
+register_slot (acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
+	struct acpiphp_slot *slot;
+	struct acpiphp_func *newfunc;
+	acpi_handle tmp;
+	acpi_status status = AE_OK;
+	unsigned long adr, sun;
+	int device, function;
+	static int num_slots = 0;	/* XXX if we support I/O node hotplug... */
+
+	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
+
+	if (ACPI_FAILURE(status))
+		return AE_OK;
+
+	status = acpi_get_handle(handle, "_EJ0", &tmp);
+
+	if (ACPI_FAILURE(status))
+		return AE_OK;
+
+	device = (adr >> 16) & 0xffff;
+	function = adr & 0xffff;
+
+	newfunc = kmalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
+	if (!newfunc)
+		return AE_NO_MEMORY;
+	memset(newfunc, 0, sizeof(struct acpiphp_func));
+
+	INIT_LIST_HEAD(&newfunc->sibling);
+	newfunc->handle = handle;
+	newfunc->function = function;
+	newfunc->flags = FUNC_HAS_EJ0;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
+		newfunc->flags |= FUNC_HAS_STA;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp)))
+		newfunc->flags |= FUNC_HAS_PS0;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
+		newfunc->flags |= FUNC_HAS_PS3;
+
+	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
+	if (ACPI_FAILURE(status))
+		sun = -1;
+
+	/* search for objects that share the same slot */
+	for (slot = bridge->slots; slot; slot = slot->next)
+		if (slot->device == device) {
+			if (slot->sun != sun)
+				warn("sibling found, but _SUN doesn't match!");
+			break;
+		}
+
+	if (!slot) {
+		slot = kmalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
+		if (!slot) {
+			kfree(newfunc);
+			return AE_NO_MEMORY;
+		}
+
+		memset(slot, 0, sizeof(struct acpiphp_slot));
+		slot->bridge = bridge;
+		slot->id = num_slots++;
+		slot->device = device;
+		slot->sun = sun;
+		INIT_LIST_HEAD(&slot->funcs);
+		init_MUTEX(&slot->crit_sect);
+
+		slot->next = bridge->slots;
+		bridge->slots = slot;
+
+		bridge->nr_slots++;
+
+		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d",
+		    slot->bridge->bus, slot->device, slot->sun);
+	}
+
+	newfunc->slot = slot;
+	list_add_tail(&newfunc->sibling, &slot->funcs);
+
+	/* associate corresponding pci_dev */
+	newfunc->pci_dev = pci_find_slot(bridge->bus,
+					 PCI_DEVFN(device, function));
+	if (newfunc->pci_dev) {
+		if (acpiphp_init_func_resource(newfunc) < 0) {
+			kfree(newfunc);
+			return AE_ERROR;
+		}
+		slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+	}
+
+	/* install notify handler */
+	status = acpi_install_notify_handler(handle,
+					     ACPI_SYSTEM_NOTIFY,
+					     handle_hotplug_event_func,
+					     newfunc);
+
+	if (ACPI_FAILURE(status)) {
+		err("failed to register interrupt notify handler");
+		return status;
+	}
+
+	return AE_OK;
+}
+
+
+/* see if it's worth looking at this bridge */
+static int detect_ejectable_slots (acpi_handle *bridge_handle)
+{
+	acpi_status status;
+	int count;
+
+	count = 0;
+
+	/* only check slots defined directly below bridge object */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
+				     is_ejectable_slot, (void *)&count, NULL);
+
+	return count;
+}
+
+
+/* decode ACPI _CRS data and convert into our internal resource list
+ * TBD: _TRA, etc.
+ */
+static void
+decode_acpi_resource (acpi_resource *resource, struct acpiphp_bridge *bridge)
+{
+	acpi_resource_address16 *address16_data;
+	acpi_resource_address32 *address32_data;
+	acpi_resource_address64 *address64_data;
+	struct pci_resource *res;
+
+	u32 resource_type, producer_consumer, address_length;
+	u64 min_address_range, max_address_range;
+	u16 cache_attribute = 0;
+
+	int done = 0, found;
+
+	/* shut up gcc */
+	resource_type = producer_consumer = address_length = 0;
+	min_address_range = max_address_range = 0;
+
+	while (!done) {
+		found = 0;
+
+		switch (resource->id) {
+		case ACPI_RSTYPE_ADDRESS16:
+			address16_data = (acpi_resource_address16 *)&resource->data;
+			resource_type = address16_data->resource_type;
+			producer_consumer = address16_data->producer_consumer;
+			min_address_range = address16_data->min_address_range;
+			max_address_range = address16_data->max_address_range;
+			address_length = address16_data->address_length;
+			if (resource_type == ACPI_MEMORY_RANGE)
+				cache_attribute = address16_data->attribute.memory.cache_attribute;
+			found = 1;
+			break;
+
+		case ACPI_RSTYPE_ADDRESS32:
+			address32_data = (acpi_resource_address32 *)&resource->data;
+			resource_type = address32_data->resource_type;
+			producer_consumer = address32_data->producer_consumer;
+			min_address_range = address32_data->min_address_range;
+			max_address_range = address32_data->max_address_range;
+			address_length = address32_data->address_length;
+			if (resource_type == ACPI_MEMORY_RANGE)
+				cache_attribute = address32_data->attribute.memory.cache_attribute;
+			found = 1;
+			break;
+
+		case ACPI_RSTYPE_ADDRESS64:
+			address64_data = (acpi_resource_address64 *)&resource->data;
+			resource_type = address64_data->resource_type;
+			producer_consumer = address64_data->producer_consumer;
+			min_address_range = address64_data->min_address_range;
+			max_address_range = address64_data->max_address_range;
+			address_length = address64_data->address_length;
+			if (resource_type == ACPI_MEMORY_RANGE)
+				cache_attribute = address64_data->attribute.memory.cache_attribute;
+			found = 1;
+			break;
+
+		case ACPI_RSTYPE_END_TAG:
+			done = 1;
+			break;
+
+		default:
+			/* ignore */
+			break;
+		}
+
+		resource = (acpi_resource *)((char*)resource + resource->length);
+
+		if (found && producer_consumer == ACPI_PRODUCER && address_length > 0) {
+			switch (resource_type) {
+			case ACPI_MEMORY_RANGE:
+				if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
+					dbg("resource type: prefetchable memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					res = acpiphp_make_resource(min_address_range,
+							    address_length);
+					if (!res) {
+						err("out of memory");
+						return;
+					}
+					res->next = bridge->p_mem_head;
+					bridge->p_mem_head = res;
+				} else {
+					dbg("resource type: memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					res = acpiphp_make_resource(min_address_range,
+							    address_length);
+					if (!res) {
+						err("out of memory");
+						return;
+					}
+					res->next = bridge->mem_head;
+					bridge->mem_head = res;
+				}
+				break;
+			case ACPI_IO_RANGE:
+				dbg("resource type: io 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+				res = acpiphp_make_resource(min_address_range,
+						    address_length);
+				if (!res) {
+					err("out of memory");
+					return;
+				}
+				res->next = bridge->io_head;
+				bridge->io_head = res;
+				break;
+			case ACPI_BUS_NUMBER_RANGE:
+				dbg("resource type: bus number %d - %d", (u32)min_address_range, (u32)max_address_range);
+				res = acpiphp_make_resource(min_address_range,
+						    address_length);
+				if (!res) {
+					err("out of memory");
+					return;
+				}
+				res->next = bridge->bus_head;
+				bridge->bus_head = res;
+				break;
+			default:
+				/* invalid type */
+				break;
+			}
+		}
+	}
+
+	acpiphp_resource_sort_and_combine(&bridge->io_head);
+	acpiphp_resource_sort_and_combine(&bridge->mem_head);
+	acpiphp_resource_sort_and_combine(&bridge->p_mem_head);
+	acpiphp_resource_sort_and_combine(&bridge->bus_head);
+#if 1
+	info("ACPI _CRS resource:");
+	acpiphp_dump_resource(bridge);
+#endif
+}
+
+
+/* find pci_bus structure associated to specific bus number */
+static struct pci_bus *find_pci_bus(const struct list_head *list, int bus)
+{
+	const struct list_head *l;
+
+	list_for_each(l, list) {
+		struct pci_bus *b = pci_bus_b(l);
+		if (b->number == bus)
+			return b;
+
+		if (!list_empty(&b->children)) {
+			/* XXX recursive call */
+			b = find_pci_bus(&b->children, bus);
+
+			if (b)
+				return b;
+		}
+	}
+
+	return 0;
+}
+
+
+/* decode ACPI 2.0 _HPP hot plug parameters */
+static void decode_hpp(struct acpiphp_bridge *bridge)
+{
+	acpi_status status;
+#if ACPI_CA_VERSION < 0x20020201
+	acpi_buffer buffer;
+#else
+	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+#endif
+	acpi_object *package;
+	int i;
+
+	/* default numbers */
+	bridge->hpp.cache_line_size = 0x10;
+	bridge->hpp.latency_timer = 0x40;
+	bridge->hpp.enable_SERR = 0;
+	bridge->hpp.enable_PERR = 0;
+
+#if ACPI_CA_VERSION < 0x20020201
+	buffer.length = 0;
+	buffer.pointer = NULL;
+
+	status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
+
+	if (status == AE_BUFFER_OVERFLOW) {
+		buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
+		if (!buffer.pointer)
+			return;
+		status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
+	}
+#else
+	status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
+#endif
+
+	if (ACPI_FAILURE(status)) {
+		dbg("_HPP evaluation failed");
+		return;
+	}
+
+	package = (acpi_object *) buffer.pointer;
+
+	if (!package || package->type != ACPI_TYPE_PACKAGE ||
+	    package->package.count != 4 || !package->package.elements) {
+		err("invalid _HPP object; ignoring");
+		goto err_exit;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (package->package.elements[i].type != ACPI_TYPE_INTEGER) {
+			err("invalid _HPP parameter type; ignoring");
+			goto err_exit;
+		}
+	}
+
+	bridge->hpp.cache_line_size = package->package.elements[0].integer.value;
+	bridge->hpp.latency_timer = package->package.elements[1].integer.value;
+	bridge->hpp.enable_SERR = package->package.elements[2].integer.value;
+	bridge->hpp.enable_PERR = package->package.elements[3].integer.value;
+
+	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)",
+	    bridge->hpp.cache_line_size,
+	    bridge->hpp.latency_timer,
+	    bridge->hpp.enable_SERR,
+	    bridge->hpp.enable_PERR);
+
+	bridge->flags |= BRIDGE_HAS_HPP;
+
+ err_exit:
+	kfree(buffer.pointer);
+}
+
+
+/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */
+static void init_bridge_misc (struct acpiphp_bridge *bridge)
+{
+	acpi_status status;
+
+	/* decode ACPI 2.0 _HPP (hot plug parameters) */
+	decode_hpp(bridge);
+
+	/* subtract all resources already allocated */
+	acpiphp_detect_pci_resource(bridge);
+
+	/* register all slot objects under this bridge */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
+				     register_slot, bridge, NULL);
+
+	/* install notify handler */
+	status = acpi_install_notify_handler(bridge->handle,
+					     ACPI_SYSTEM_NOTIFY,
+					     handle_hotplug_event_bridge,
+					     bridge);
+
+	if (ACPI_FAILURE(status)) {
+		err("failed to register interrupt notify handler");
+	}
+
+	list_add(&bridge->list, &bridge_list);
+
+#if 1
+	dbg("Bridge resource:");
+	acpiphp_dump_resource(bridge);
+#endif
+}
+
+
+/* allocate and initialize host bridge data structure */
+static void add_host_bridge (acpi_handle *handle, int seg, int bus)
+{
+	acpi_status status;
+#if ACPI_CA_VERSION < 0x20020201
+	acpi_buffer buffer;
+#else
+	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+#endif
+	struct acpiphp_bridge *bridge;
+
+	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
+	if (bridge == NULL)
+		return;
+
+	memset(bridge, 0, sizeof(struct acpiphp_bridge));
+
+	bridge->type = BRIDGE_TYPE_HOST;
+	bridge->handle = handle;
+	bridge->seg = seg;
+	bridge->bus = bus;
+
+	bridge->pci_bus = find_pci_bus(&pci_root_buses, bus);
+	bridge->pci_ops = bridge->pci_bus->ops;
+
+	bridge->res_lock = SPIN_LOCK_UNLOCKED;
+
+	/* to be overridden when we decode _CRS	*/
+	bridge->sub = bridge->bus;
+
+	/* decode resources */
+
+#if ACPI_CA_VERSION < 0x20020201
+	buffer.length = 0;
+	buffer.pointer = NULL;
+
+	status = acpi_get_current_resources(handle, &buffer);
+
+	if (status == AE_BUFFER_OVERFLOW) {
+		buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
+		if (!buffer.pointer)
+			return;
+		status = acpi_get_current_resources(handle, &buffer);
+	}
+#else
+	status = acpi_get_current_resources(handle, &buffer);
+#endif
+
+	if (ACPI_FAILURE(status)) {
+		err("failed to decode bridge resources");
+		kfree(bridge);
+		return;
+	}
+
+	decode_acpi_resource(buffer.pointer, bridge);
+	kfree(buffer.pointer);
+
+	if (bridge->bus_head) {
+		bridge->bus = bridge->bus_head->base;
+		bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1;
+	}
+
+	init_bridge_misc(bridge);
+}
+
+
+/* allocate and initialize PCI-to-PCI bridge data structure */
+static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int fn)
+{
+	acpi_status status;
+	struct acpiphp_bridge *bridge;
+	u8 tmp8;
+	u16 tmp16;
+	u32 tmp;
+	u64 base64, limit64;
+	u32 base, limit, base32u, limit32u;
+
+	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
+	if (bridge == NULL) {
+		err("out of memory");
+		return;
+	}
+
+	memset(bridge, 0, sizeof(struct acpiphp_bridge));
+
+	bridge->type = BRIDGE_TYPE_P2P;
+	bridge->handle = handle;
+	bridge->seg = seg;
+
+	bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
+	if (!bridge->pci_dev) {
+		err("Can't get pci_dev");
+		kfree(bridge);
+		return;
+	}
+
+	bridge->pci_bus = bridge->pci_dev->subordinate;
+	if (!bridge->pci_bus) {
+		err("This is not a PCI-to-PCI bridge!");
+		kfree(bridge);
+		return;
+	}
+	bridge->pci_ops = bridge->pci_bus->ops;
+
+	bridge->res_lock = SPIN_LOCK_UNLOCKED;
+
+	bridge->bus = bridge->pci_bus->number;
+	bridge->sub = bridge->pci_bus->subordinate;
+
+	/*
+	 * decode resources under this P2P bridge
+	 */
+
+	/* I/O resources */
+	pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8);
+	base = tmp8;
+	pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8);
+	limit = tmp8;
+
+	switch (base & PCI_IO_RANGE_TYPE_MASK) {
+	case PCI_IO_RANGE_TYPE_16:
+		base = (base << 8) & 0xf000;
+		limit = ((limit << 8) & 0xf000) + 0xfff;
+		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
+		if (!bridge->io_head) {
+			err("out of memory");
+			return;
+		}
+		dbg("16bit I/O range: %04x-%04x",
+		    (u32)bridge->io_head->base,
+		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
+		break;
+	case PCI_IO_RANGE_TYPE_32:
+		pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16);
+		base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000);
+		pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16);
+		limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;
+		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
+		if (!bridge->io_head) {
+			err("out of memory");
+			return;
+		}
+		dbg("32bit I/O range: %08x-%08x",
+		    (u32)bridge->io_head->base,
+		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
+		break;
+	case 0x0f:
+		dbg("I/O space unsupported");
+		break;
+	default:
+		warn("Unknown I/O range type");
+	}
+
+	/* Memory resources (mandatory for P2P bridge) */
+	pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16);
+	base = (tmp16 & 0xfff0) << 16;
+	pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16);
+	limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
+	bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
+	if (!bridge->mem_head) {
+		err("out of memory");
+		return;
+	}
+	dbg("32bit Memory range: %08x-%08x",
+	    (u32)bridge->mem_head->base,
+	    (u32)(bridge->mem_head->base + bridge->mem_head->length-1));
+
+	/* Prefetchable Memory resources (optional) */
+	pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16);
+	base = tmp16;
+	pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16);
+	limit = tmp16;
+
+	switch (base & PCI_MEMORY_RANGE_TYPE_MASK) {
+	case PCI_PREF_RANGE_TYPE_32:
+		base = (base & 0xfff0) << 16;
+		limit = ((limit & 0xfff0) << 16) | 0xfffff;
+		bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
+		if (!bridge->p_mem_head) {
+			err("out of memory");
+			return;
+		}
+		dbg("32bit Prefetchable memory range: %08x-%08x",
+		    (u32)bridge->p_mem_head->base,
+		    (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
+		break;
+	case PCI_PREF_RANGE_TYPE_64:
+		pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u);
+		pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u);
+		base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16);
+		limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff;
+
+		bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
+		if (!bridge->p_mem_head) {
+			err("out of memory");
+			return;
+		}
+		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x",
+		    (u32)(bridge->p_mem_head->base >> 32),
+		    (u32)(bridge->p_mem_head->base & 0xffffffff),
+		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),
+		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff));
+		break;
+	case 0x0f:
+		break;
+	default:
+		warn("Unknown prefetchale memory type");
+	}
+
+	init_bridge_misc(bridge);
+}
+
+
+/* callback routine to find P2P bridges */
+static acpi_status
+find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	acpi_status status;
+	acpi_handle dummy_handle;
+	unsigned long *segbus = context;
+	unsigned long tmp;
+	int seg, bus, device, function;
+	struct pci_dev *dev;
+	u32 val;
+
+	/* get PCI address */
+	seg = (*segbus >> 8) & 0xff;
+	bus = *segbus & 0xff;
+
+	status = acpi_get_handle(handle, "_ADR", &dummy_handle);
+	if (ACPI_FAILURE(status))
+		return AE_OK;		/* continue */
+
+	status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);
+	if (ACPI_FAILURE(status)) {
+		dbg("%s: _ADR evaluation failure", __FUNCTION__);
+		return AE_OK;
+	}
+
+	device = (tmp >> 16) & 0xffff;
+	function = tmp & 0xffff;
+
+	dev = pci_find_slot(bus, PCI_DEVFN(device, function));
+
+	if (!dev)
+		return AE_OK;
+
+	if (!dev->subordinate)
+		return AE_OK;
+
+	/* check if this bridge has ejectable slots */
+	if (detect_ejectable_slots(handle) > 0) {
+		dbg("found PCI-to-PCI bridge at PCI %02x:%02x.%d", bus, device, function);
+		add_p2p_bridge(handle, seg, bus, device, function);
+	}
+
+	return AE_OK;
+}
+
+
+/* find hot-pluggable slots, and then find P2P bridge */
+static int add_bridges (acpi_handle *handle)
+{
+	acpi_status status;
+	unsigned long tmp;
+	int seg, bus;
+	acpi_handle dummy_handle;
+	int sta = -1;
+
+	/* if the bridge doesn't have _STA, we assume it is always there */
+	status = acpi_get_handle(handle, "_STA", &dummy_handle);
+	if (ACPI_SUCCESS(status)) {
+		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
+		if (ACPI_FAILURE(status)) {
+			dbg("%s: _STA evaluation failure", __FUNCTION__);
+			return 0;
+		}
+		if ((tmp & ACPI_STA_FUNCTIONING) == 0)
+			/* don't register this object */
+			return 0;
+	}
+
+	/* get PCI segment number */
+	status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
+
+	seg = ACPI_SUCCESS(status) ? tmp : 0;
+
+	/* get PCI bus number */
+	status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
+
+	if (ACPI_SUCCESS(status)) {
+		bus = tmp;
+	} else {
+		warn("can't get bus number, assuming 0");
+		bus = 0;
+	}
+
+	/* check if this bridge has ejectable slots */
+	if (detect_ejectable_slots(handle) > 0) {
+		dbg("found PCI host-bus bridge with hot-pluggable slots");
+		add_host_bridge(handle, seg, bus);
+		return 0;
+	}
+
+	tmp = seg << 8 | bus;
+
+	/* search P2P bridges under this host bridge */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+				     find_p2p_bridge, &tmp, NULL);
+
+	if (ACPI_FAILURE(status))
+		warn("find_p2p_bridge faied (error code = 0x%x)",status);
+
+	return 0;
+}
+
+
+/* callback routine to enumerate all the bridges in ACPI namespace */
+static acpi_status
+find_host_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	acpi_status status;
+	acpi_device_info info;
+	char objname[5];
+	acpi_buffer buffer = { sizeof(objname), objname };
+
+	status = acpi_get_object_info(handle, &info);
+	if (ACPI_FAILURE(status)) {
+		dbg("%s: failed to get bridge information", __FUNCTION__);
+		return AE_OK;		/* continue */
+	}
+
+	info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
+
+	/* TBD check _CID also */
+	if (strcmp(info.hardware_id, ACPI_PCI_HOST_HID) == 0) {
+
+		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+		dbg("checking PCI-hotplug capable bridges under [%s]", objname);
+		add_bridges(handle);
+	}
+	return AE_OK;
+}
+
+
+static int power_on_slot (struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	struct acpiphp_func *func;
+	struct list_head *l;
+	int retval = 0;
+
+	/* is this already enabled? */
+	if (slot->flags & SLOT_POWEREDON)
+		goto err_exit;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_PS0) {
+			dbg("%s: executing _PS0 on %02x:%02x.%d", __FUNCTION__,
+			    slot->bridge->bus, slot->device, func->function);
+			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
+			if (ACPI_FAILURE(status)) {
+				warn("%s: _PS0 failed", __FUNCTION__);
+				retval = -1;
+				goto err_exit;
+			}
+		}
+	}
+
+	/* TBD: evaluate _STA to check if the slot is enabled */
+
+	slot->flags |= SLOT_POWEREDON;
+
+ err_exit:
+	return retval;
+}
+
+
+static int power_off_slot (struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	struct acpiphp_func *func;
+	struct list_head *l;
+	acpi_object_list arg_list;
+	acpi_object arg;
+
+	int retval = 0;
+
+	/* is this already enabled? */
+	if ((slot->flags & SLOT_POWEREDON) == 0)
+		goto err_exit;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_PS3) {
+			dbg("%s: executing _PS3 on %02x:%02x.%d", __FUNCTION__,
+			    slot->bridge->bus, slot->device, func->function);
+			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
+			if (ACPI_FAILURE(status)) {
+				warn("%s: _PS3 failed", __FUNCTION__);
+				retval = -1;
+				goto err_exit;
+			}
+		}
+	}
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_EJ0) {
+			dbg("%s: executing _EJ0 on %02x:%02x.%d", __FUNCTION__,
+			    slot->bridge->bus, slot->device, func->function);
+
+			/* _EJ0 method take one argument */
+			arg_list.count = 1;
+			arg_list.pointer = &arg;
+			arg.type = ACPI_TYPE_INTEGER;
+			arg.integer.value = 1;
+
+			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
+			if (ACPI_FAILURE(status)) {
+				warn("%s: _EJ0 failed", __FUNCTION__);
+				retval = -1;
+				goto err_exit;
+			}
+		}
+	}
+
+	/* TBD: evaluate _STA to check if the slot is disabled */
+
+	slot->flags &= (~SLOT_POWEREDON);
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * enable_device - enable, configure a slot
+ * @slot: slot to be enabled
+ *
+ * This function should be called per *physical slot*,
+ * not per each slot object in ACPI namespace.
+ *
+ */
+static int enable_device (struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	u8 bus;
+	struct pci_dev dev0, *dev;
+	struct pci_bus *child;
+	struct list_head *l;
+	struct acpiphp_func *func;
+	int retval = 0;
+
+	if (slot->flags & SLOT_ENABLED)
+		goto err_exit;
+
+	/* sanity check: dev should be NULL when hot-plugged in */
+	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
+	if (dev) {
+		/* This case shouldn't happen */
+		err("pci_dev structure already exists.");
+		retval = -1;
+		goto err_exit;
+	}
+
+	/* allocate resources to device */
+	retval = acpiphp_configure_slot(slot);
+	if (retval)
+		goto err_exit;
+
+	memset(&dev0, 0, sizeof (struct pci_dev));
+
+	dev0.bus = slot->bridge->pci_bus;
+	dev0.devfn = PCI_DEVFN(slot->device, 0);
+	dev0.sysdata = dev0.bus->sysdata;
+
+	/* returned `dev' is the *first function* only! */
+	dev = pci_scan_slot (&dev0);
+
+	if (!dev) {
+		err("No new device found");
+		retval = -1;
+		goto err_exit;
+	}
+
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus);
+		child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus);
+		pci_do_scan_bus(child);
+	}
+
+	/* associate pci_dev to our representation */
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		func->pci_dev = pci_find_slot(slot->bridge->bus,
+					      PCI_DEVFN(slot->device,
+							func->function));
+		if (!func->pci_dev)
+			continue;
+
+		/* configure device */
+		retval = acpiphp_configure_function(func);
+		if (retval)
+			goto err_exit;
+	}
+
+	slot->flags |= SLOT_ENABLED;
+
+#if 1
+	dbg("Available resources:");
+	acpiphp_dump_resource(slot->bridge);
+#endif
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * disable_device - disable a slot
+ */
+static int disable_device (struct acpiphp_slot *slot)
+{
+	int retval = 0;
+	struct acpiphp_func *func;
+	struct list_head *l;
+	acpi_status status;
+
+	/* is this slot already disabled? */
+	if (!(slot->flags & SLOT_ENABLED))
+		goto err_exit;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->pci_dev) {
+			if (acpiphp_unconfigure_function(func) == 0) {
+				func->pci_dev = NULL;
+			} else {
+				err("failed to unconfigure device");
+				retval = -1;
+				goto err_exit;
+			}
+		}
+	}
+
+	slot->flags &= (~SLOT_ENABLED);
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * get_slot_status - get ACPI slot status
+ *
+ * if a slot has _STA for each function and if any one of them
+ * returned non-zero status, return it
+ *
+ * if a slot doesn't have _STA and if any one of its functions'
+ * configuration space is configured, return 0x0f as a _STA
+ *
+ * otherwise return 0
+ */
+static unsigned int get_slot_status (struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	unsigned long sta = 0;
+	int fn;
+	u32 dvid;
+	struct list_head *l;
+	struct acpiphp_func *func;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_STA) {
+			status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
+			if (ACPI_SUCCESS(status) && sta)
+				break;
+		} else {
+			pci_read_config_dword_nodev(default_ops,
+						    slot->bridge->bus,
+						    slot->device,
+						    func->function,
+						    PCI_VENDOR_ID, &dvid);
+			if (dvid != 0xffffffff) {
+				sta = ACPI_STA_ALL;
+				break;
+			}
+		}
+	}
+
+	return (unsigned int)sta;
+}
+
+
+/*
+ * ACPI event handlers
+ */
+
+/**
+ * handle_hotplug_event_bridge - handle ACPI event on bridges
+ *
+ * @handle: Notify()'ed acpi_handle 
+ * @type: Notify code
+ * @context: pointer to acpiphp_bridge structure
+ *
+ * handles ACPI event notification on {host,p2p} bridges
+ *
+ */
+static void handle_hotplug_event_bridge (acpi_handle handle, u32 type, void *context)
+{
+	struct acpiphp_bridge *bridge;
+	char objname[64];
+	acpi_buffer buffer = { sizeof(objname), objname };
+
+	bridge = (struct acpiphp_bridge *)context;
+
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		/* bus re-enumerate */
+		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		acpiphp_check_bridge(bridge);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		/* device check */
+		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		acpiphp_check_bridge(bridge);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_WAKE:
+		/* wake event */
+		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		break;
+
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		/* request device eject */
+		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		break;
+
+	default:
+		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		break;
+	}
+}
+
+
+/**
+ * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
+ *
+ * @handle: Notify()'ed acpi_handle 
+ * @type: Notify code
+ * @context: pointer to acpiphp_func structure
+ *
+ * handles ACPI event notification on slots
+ *
+ */
+static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *context)
+{
+	struct acpiphp_func *func;
+	char objname[64];
+	acpi_buffer buffer = { sizeof(objname), objname };
+
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+	func = (struct acpiphp_func *)context;
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		/* bus re-enumerate */
+		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		acpiphp_enable_slot(func->slot);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		/* device check : re-enumerate from parent bus */
+		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		acpiphp_check_bridge(func->slot->bridge);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_WAKE:
+		/* wake event */
+		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		break;
+
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		/* request device eject */
+		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		acpiphp_disable_slot(func->slot);
+		break;
+
+	default:
+		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		break;
+	}
+}
+
+
+/**
+ * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures
+ *
+ */
+int acpiphp_glue_init (void)
+{
+	acpi_status status;
+
+	if (list_empty(&pci_root_buses))
+		return -1;
+
+	/* set default pci_ops for configuration space operation */
+	default_ops = pci_bus_b(pci_root_buses.next)->ops;
+	if (!default_ops)
+		return -1;
+
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+				     ACPI_UINT32_MAX, find_host_bridge,
+				     NULL, NULL);
+
+	if (ACPI_FAILURE(status)) {
+		err("%s: acpi_walk_namespace() failed", __FUNCTION__);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures
+ *
+ * This function frees all data allocated in acpiphp_glue_init()
+ */
+void acpiphp_glue_exit (void)
+{
+	struct list_head *node, *shead, *l, *n;
+	struct acpiphp_bridge *bridge;
+	struct acpiphp_slot *slot, *next;
+	struct acpiphp_func *func;
+	acpi_status status;
+
+	list_for_each(node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		slot = bridge->slots;
+		while (slot) {
+			next = slot->next;
+			list_for_each_safe(l, n, &slot->funcs) {
+				func = list_entry(l, struct acpiphp_func, sibling);
+				acpiphp_free_resource(&func->io_head);
+				acpiphp_free_resource(&func->mem_head);
+				acpiphp_free_resource(&func->p_mem_head);
+				acpiphp_free_resource(&func->bus_head);
+				status = acpi_remove_notify_handler(func->handle,
+								    ACPI_SYSTEM_NOTIFY,
+								    handle_hotplug_event_func);
+				if (ACPI_FAILURE(status))
+					err("failed to remove notify handler");
+				kfree(func);
+			}
+			kfree(slot);
+			slot = next;
+		}
+		status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
+						    handle_hotplug_event_bridge);
+		if (ACPI_FAILURE(status))
+			err("failed to remove notify handler");
+
+		acpiphp_free_resource(&bridge->io_head);
+		acpiphp_free_resource(&bridge->mem_head);
+		acpiphp_free_resource(&bridge->p_mem_head);
+		acpiphp_free_resource(&bridge->bus_head);
+
+		kfree(bridge);
+	}
+}
+
+
+/**
+ * acpiphp_get_num_slots - count number of slots in a system
+ */
+int acpiphp_get_num_slots (void)
+{
+	struct list_head *node;
+	struct acpiphp_bridge *bridge;
+	int num_slots;
+
+	num_slots = 0;
+
+	list_for_each(node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		dbg("Bus%d %dslot(s)", bridge->bus, bridge->nr_slots);
+		num_slots += bridge->nr_slots;
+	}
+
+	dbg("Total %dslots", num_slots);
+	return num_slots;
+}
+
+
+/**
+ * acpiphp_for_each_slot - call function for each slot
+ * @fn: callback function
+ * @data: context to be passed to callback function
+ *
+ */
+int acpiphp_for_each_slot(acpiphp_callback fn, void *data)
+{
+	struct list_head *node;
+	struct acpiphp_bridge *bridge;
+	struct acpiphp_slot *slot;
+	int retval = 0;
+
+	list_for_each(node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		for (slot = bridge->slots; slot; slot = slot->next) {
+			retval = fn(slot, data);
+			if (!retval)
+				goto err_exit;
+		}
+	}
+
+ err_exit:
+	return retval;
+}
+
+
+/* search matching slot from id  */
+struct acpiphp_slot *get_slot_from_id (int id)
+{
+	struct list_head *node;
+	struct acpiphp_bridge *bridge;
+	struct acpiphp_slot *slot;
+
+	list_for_each(node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		for (slot = bridge->slots; slot; slot = slot->next)
+			if (slot->id == id)
+				return slot;
+	}
+
+	/* should never happen! */
+	err("%s: no object for id %d",__FUNCTION__, id);
+	return 0;
+}
+
+
+/**
+ * acpiphp_enable_slot - power on slot
+ */
+int acpiphp_enable_slot (struct acpiphp_slot *slot)
+{
+	int retval;
+	int online = 0;
+
+	down(&slot->crit_sect);
+
+	/* wake up all functions */
+	retval = power_on_slot(slot);
+	if (retval)
+		goto err_exit;
+
+	if (get_slot_status(slot) == ACPI_STA_ALL)
+		/* configure all functions */
+		retval = enable_device(slot);
+
+ err_exit:
+	up(&slot->crit_sect);
+	return retval;
+}
+
+
+/**
+ * acpiphp_disable_slot - power off slot
+ */
+int acpiphp_disable_slot (struct acpiphp_slot *slot)
+{
+	struct list_head *l;
+	struct acpiphp_func *func;
+	int retval = 0;
+
+	down(&slot->crit_sect);
+
+	/* unconfigure all functions */
+	retval = disable_device(slot);
+	if (retval)
+		goto err_exit;
+
+	/* power off all functions */
+	retval = power_off_slot(slot);
+	if (retval)
+		goto err_exit;
+
+#if 1
+	acpiphp_resource_sort_and_combine(&slot->bridge->io_head);
+	acpiphp_resource_sort_and_combine(&slot->bridge->mem_head);
+	acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head);
+	acpiphp_resource_sort_and_combine(&slot->bridge->bus_head);
+	dbg("Available resources:");
+	acpiphp_dump_resource(slot->bridge);
+#endif
+
+ err_exit:
+	up(&slot->crit_sect);
+	return retval;
+}
+
+
+/**
+ * acpiphp_check_bridge - re-enumerate devices
+ */
+int acpiphp_check_bridge (struct acpiphp_bridge *bridge)
+{
+	struct acpiphp_slot *slot;
+	unsigned int sta;
+	int retval = 0;
+	int enabled, disabled;
+
+	enabled = disabled = 0;
+
+	for (slot = bridge->slots; slot; slot = slot->next) {
+		sta = get_slot_status(slot);
+		if (slot->flags & SLOT_ENABLED) {
+			/* if enabled but not present, disable */
+			if (sta != ACPI_STA_ALL) {
+				retval = acpiphp_disable_slot(slot);
+				if (retval) {
+					err("Error occured in enabling");
+					up(&slot->crit_sect);
+					goto err_exit;
+				}
+				enabled++;
+			}
+		} else {
+			/* if disabled but present, enable */
+			if (sta == ACPI_STA_ALL) {
+				retval = acpiphp_enable_slot(slot);
+				if (retval) {
+					err("Error occured in enabling");
+					up(&slot->crit_sect);
+					goto err_exit;
+				}
+				disabled++;
+			}
+		}
+	}
+
+	dbg("%s: %d enabled, %d disabled", __FUNCTION__, enabled, disabled);
+
+ err_exit:
+	return retval;
+}
+
+
+/*
+ * slot enabled:  1
+ * slot disabled: 0
+ */
+u8 acpiphp_get_power_status (struct acpiphp_slot *slot)
+{
+	unsigned int sta;
+
+	sta = get_slot_status(slot);
+
+	return (sta & ACPI_STA_ENABLED) ? 1 : 0;
+}
+
+
+/*
+ * attention LED ON: 1
+ *              OFF: 0
+ *
+ * TBD
+ * no direct attention led status information via ACPI
+ *
+ */
+u8 acpiphp_get_attention_status (struct acpiphp_slot *slot)
+{
+	return 0;
+}
+
+
+/*
+ * latch closed:  1
+ * latch   open:  0
+ */
+u8 acpiphp_get_latch_status (struct acpiphp_slot *slot)
+{
+	unsigned int sta;
+
+	sta = get_slot_status(slot);
+
+	return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;
+}
+
+
+/*
+ * adapter presence : 1
+ *          absence : 0
+ */
+u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot)
+{
+	unsigned int sta;
+
+	sta = get_slot_status(slot);
+
+	return (sta == 0) ? 0 : 1;
+}
diff -urN linux-2.4.20-pre1/drivers/hotplug/acpiphp_pci.c linux-2.4.20-pre2/drivers/hotplug/acpiphp_pci.c
--- linux-2.4.20-pre1/drivers/hotplug/acpiphp_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/hotplug/acpiphp_pci.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,763 @@
+/*
+ * ACPI PCI HotPlug PCI configuration space management
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001,2002 IBM Corp.
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <t-kouchi@cq.jp.nec.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+static int debug = 1;			/* XXX set 0 after debug */
+#define MY_NAME "acpiphp_pci"
+
+static void acpiphp_configure_irq (struct pci_dev *dev);
+
+
+/* allocate mem/pmem/io resource to a new function */
+static int alloc_resource (struct acpiphp_func *func)
+{
+	u64 base;
+	u32 bar, len;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct acpiphp_bridge *bridge;
+	struct pci_resource *res;
+	struct pci_ops *ops;
+	int bus, device, function;
+
+	bridge = func->slot->bridge;
+	bus = bridge->bus;
+	device = func->slot->device;
+	function = func->function;
+	ops = bridge->pci_ops;
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_write_config_dword_nodev (ops, bus, device, function, address[count], 0xFFFFFFFF);
+		pci_read_config_dword_nodev(ops, bus, device, function, address[count], &bar);
+
+		if (!bar)	/* This BAR is not implemented */
+			continue;
+
+		dbg("Device %02x.%02x BAR %d wants %x", device, function, count, bar);
+
+		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+
+			len = bar & 0xFFFFFFFC;
+			len = ~len + 1;
+
+			dbg ("len in IO %x, BAR %d", len, count);
+
+			spin_lock(&bridge->res_lock);
+			res = acpiphp_get_io_resource(&bridge->io_head, len);
+			spin_unlock(&bridge->res_lock);
+
+			if (!res) {
+				err("cannot allocate requested io for %02x:%02x.%d len %x\n",
+				    bus, device, function, len);
+				return -1;
+			}
+			pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+			res->next = func->io_head;
+			func->io_head = res;
+
+		} else {
+			/* This is Memory */
+			if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+
+				len = bar & 0xFFFFFFF0;
+				len = ~len + 1;
+
+				dbg("len in PFMEM %x, BAR %d", len, count);
+
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource(&bridge->p_mem_head, len);
+				spin_unlock(&bridge->res_lock);
+
+				if (!res) {
+					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
+					    bus, device, function, len);
+					return -1;
+				}
+
+				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+
+				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					dbg ("inside the pfmem 64 case, count %d", count);
+					count += 1;
+					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+				}
+
+				res->next = func->p_mem_head;
+				func->p_mem_head = res;
+
+			} else {
+				/* regular memory */
+
+				len = bar & 0xFFFFFFF0;
+				len = ~len + 1;
+
+				dbg("len in MEM %x, BAR %d", len, count);
+
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource(&bridge->mem_head, len);
+				spin_unlock(&bridge->res_lock);
+
+				if (!res) {
+					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
+					    bus, device, function, len);
+					return -1;
+				}
+
+				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+
+				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					dbg ("inside mem 64 case, reg. mem, count %d", count);
+					count += 1;
+					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+				}
+
+				res->next = func->mem_head;
+				func->mem_head = res;
+
+			}
+		}
+	}
+
+	/* disable expansion rom */
+	pci_write_config_dword_nodev(ops, bus, device, function, PCI_ROM_ADDRESS, 0x00000000);
+
+	return 0;
+}
+
+
+/* enable pci_dev */
+static int configure_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+	u16 tmp;
+	struct acpiphp_func *func;
+	struct acpiphp_bridge *bridge;
+	struct pci_dev *dev;
+
+	func = (struct acpiphp_func *)wrapped_dev->data;
+	bridge = (struct acpiphp_bridge *)wrapped_bus->data;
+	dev = wrapped_dev->dev;
+
+	/* TBD: support PCI-to-PCI bridge case */
+	if (!func || !bridge)
+		return 0;
+
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, bridge->hpp.cache_line_size);
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, bridge->hpp.latency_timer);
+
+	pci_read_config_word(dev, PCI_COMMAND, &tmp);
+	if (bridge->hpp.enable_SERR)
+		tmp |= PCI_COMMAND_SERR;
+	if (bridge->hpp.enable_PERR)
+		tmp |= PCI_COMMAND_PARITY;
+	//tmp |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+	pci_write_config_word(dev, PCI_COMMAND, tmp);
+
+	acpiphp_configure_irq(dev);
+#ifdef CONFIG_PROC_FS
+	pci_proc_attach_device(dev);
+#endif
+	pci_announce_device_to_drivers(dev);
+
+	return 0;
+}
+
+
+static int is_pci_dev_in_use (struct pci_dev* dev) 
+{
+	/* 
+	 * dev->driver will be set if the device is in use by a new-style 
+	 * driver -- otherwise, check the device's regions to see if any
+	 * driver has claimed them
+	 */
+
+	int i, inuse=0;
+
+	if (dev->driver) return 1; //assume driver feels responsible
+
+	for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
+		if (!pci_resource_start(dev, i))
+			continue;
+
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO)
+			inuse = check_region(pci_resource_start(dev, i),
+					     pci_resource_len(dev, i));
+		else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+			inuse = check_mem_region(pci_resource_start(dev, i),
+						 pci_resource_len(dev, i));
+	}
+
+	return inuse;
+}
+
+
+static int pci_hp_remove_device (struct pci_dev *dev)
+{
+	if (is_pci_dev_in_use(dev)) {
+		err("***Cannot safely power down device -- "
+		       "it appears to be in use***\n");
+		return -EBUSY;
+	}
+	pci_remove_device(dev);
+	return 0;
+}
+
+
+/* remove device driver */
+static int unconfigure_pci_dev_driver (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev *dev = wrapped_dev->dev;
+
+	dbg("attempting removal of driver for device %s", dev->slot_name);
+
+	/* Now, remove the Linux Driver Representation */
+	if (dev->driver) {
+		if (dev->driver->remove) {
+			dev->driver->remove(dev);
+			dbg("driver was properly removed");
+		}
+		dev->driver = NULL;
+	}
+
+	return is_pci_dev_in_use(dev);
+}
+
+
+/* remove pci_dev itself from system */
+static int unconfigure_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev *dev = wrapped_dev->dev;
+
+	/* Now, remove the Linux Representation */
+	if (dev) {
+		if (pci_hp_remove_device(dev) == 0) {
+			kfree(dev); /* Now, remove */
+		} else {
+			return -1; /* problems while freeing, abort visitation */
+		}
+	}
+
+	return 0;
+}
+
+
+/* remove pci_bus itself from system */
+static int unconfigure_pci_bus (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev)
+{
+	struct pci_bus *bus = wrapped_bus->bus;
+
+#ifdef CONFIG_PROC_FS
+	/* Now, remove the Linux Representation */
+	if (bus->procdir) {
+		pci_proc_detach_bus(bus);
+	}
+#endif
+	/* the cleanup code should live in the kernel ... */
+	bus->self->subordinate = NULL;
+	/* unlink from parent bus */
+	list_del(&bus->node);
+
+	/* Now, remove */
+	if (bus)
+		kfree(bus);
+
+	return 0;
+}
+
+
+/* detect_used_resource - subtract resource under dev from bridge */
+static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
+{
+	u32 bar, len, pin;
+	u64 base;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct pci_resource *res;
+
+	dbg("Device %s", dev->slot_name);
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_read_config_dword(dev, address[count], &bar);
+
+		if (!bar)	/* This BAR is not implemented */
+			continue;
+
+		pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
+		pci_read_config_dword(dev, address[count], &len);
+
+		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			base = bar & 0xFFFFFFFC;
+			len &= 0xFFFFFFFC;
+			len = ~len + 1;
+
+			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+
+			spin_lock(&bridge->res_lock);
+			res = acpiphp_get_resource_with_base(&bridge->io_head, base, len);
+			spin_unlock(&bridge->res_lock);
+			if (res)
+				kfree(res);
+		} else {
+			/* This is Memory */
+			base = bar & 0xFFFFFFF0;
+			if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					dbg ("prefetch mem 64");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len);
+				spin_unlock(&bridge->res_lock);
+				if (res)
+					kfree(res);
+			} else {
+				/* regular memory */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					dbg ("mem 64");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len);
+				spin_unlock(&bridge->res_lock);
+				if (res)
+					kfree(res);
+			}
+		}
+
+		pci_write_config_dword(dev, address[count], bar);
+	}
+
+	return 0;
+}
+
+
+/* detect_pci_resource_bus - subtract resource under pci_bus */
+static void detect_used_resource_bus(struct acpiphp_bridge *bridge, struct pci_bus *bus)
+{
+	struct list_head *l;
+	struct pci_dev *dev;
+
+	list_for_each(l, &bus->devices) {
+		dev = pci_dev_b(l);
+		detect_used_resource(bridge, dev);
+		/* XXX recursive call */
+		if (dev->subordinate)
+			detect_used_resource_bus(bridge, dev->subordinate);
+	}
+}
+
+
+/**
+ * acpiphp_detect_pci_resource - detect resources under bridge
+ * @bridge: detect all resources already used under this bridge
+ *
+ * collect all resources already allocated for all devices under a bridge.
+ */
+int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
+{
+	struct list_head *l;
+	struct pci_dev *dev;
+
+	detect_used_resource_bus(bridge, bridge->pci_bus);
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_init_slot_resource - gather resource usage information of a slot
+ * @slot: ACPI slot object to be checked, should have valid pci_dev member
+ *
+ * TBD: PCI-to-PCI bridge case
+ *      use pci_dev->resource[]
+ */
+int acpiphp_init_func_resource (struct acpiphp_func *func)
+{
+	u64 base;
+	u32 bar, len;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct pci_resource *res;
+	struct pci_ops *ops;
+	struct pci_dev *dev;
+
+	dev = func->pci_dev;
+	dbg("Hot-pluggable device %s", dev->slot_name);
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_read_config_dword (dev, address[count], &bar);
+
+		if (!bar)	/* This BAR is not implemented */
+			continue;
+
+		pci_write_config_dword (dev, address[count], 0xFFFFFFFF);
+		pci_read_config_dword (dev, address[count], &len);
+
+		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			base = bar & 0xFFFFFFFC;
+			len &= 0xFFFFFFFC;
+			len = ~len + 1;
+
+			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+
+			res = acpiphp_make_resource(base, len);
+			if (!res)
+				goto no_memory;
+
+			res->next = func->io_head;
+			func->io_head = res;
+
+		} else {
+			/* This is Memory */
+			base = bar & 0xFFFFFFF0;
+			if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					dbg ("prefetch mem 64");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				res = acpiphp_make_resource(base, len);
+				if (!res)
+					goto no_memory;
+
+				res->next = func->p_mem_head;
+				func->p_mem_head = res;
+
+			} else {
+				/* regular memory */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					dbg ("mem 64");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				res = acpiphp_make_resource(base, len);
+				if (!res)
+					goto no_memory;
+
+				res->next = func->mem_head;
+				func->mem_head = res;
+
+			}
+		}
+
+		pci_write_config_dword (dev, address[count], bar);
+	}
+#if 1
+	acpiphp_dump_func_resource(func);
+#endif
+
+	return 0;
+
+ no_memory:
+	err("out of memory");
+	acpiphp_free_resource(&func->io_head);
+	acpiphp_free_resource(&func->mem_head);
+	acpiphp_free_resource(&func->p_mem_head);
+
+	return -1;
+}
+
+
+/**
+ * acpiphp_configure_slot - allocate PCI resources
+ * @slot: slot to be configured
+ *
+ * initializes a PCI functions on a device inserted
+ * into the slot
+ *
+ */
+int acpiphp_configure_slot (struct acpiphp_slot *slot)
+{
+	struct acpiphp_func *func;
+	struct list_head *l;
+	u8 hdr;
+	u32 dvid;
+	int retval = 0;
+	int is_multi = 0;
+
+	pci_read_config_byte_nodev(slot->bridge->pci_ops,
+				   slot->bridge->bus, slot->device, 0,
+				   PCI_HEADER_TYPE, &hdr);
+
+	if (hdr & 0x80)
+		is_multi = 1;
+
+	list_for_each(l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+		if (is_multi || func->function == 0) {
+			pci_read_config_dword_nodev(slot->bridge->pci_ops,
+						    slot->bridge->bus,
+						    slot->device,
+						    func->function,
+						    PCI_VENDOR_ID, &dvid);
+			if (dvid != 0xffffffff) {
+				retval = alloc_resource(func);
+				if (retval)
+					break;
+			}
+		}
+	}
+
+	return retval;
+}
+
+
+/* for pci_visit_dev() */
+static struct pci_visit configure_functions = {
+	post_visit_pci_dev:	configure_pci_dev
+};
+
+static struct pci_visit unconfigure_functions_phase1 = {
+	post_visit_pci_dev:	unconfigure_pci_dev_driver
+};
+
+static struct pci_visit unconfigure_functions_phase2 = {
+	post_visit_pci_bus:	unconfigure_pci_bus,
+	post_visit_pci_dev:	unconfigure_pci_dev
+};
+
+
+/**
+ * acpiphp_configure_function - configure PCI function
+ * @func: function to be configured
+ *
+ * initializes a PCI functions on a device inserted
+ * into the slot
+ *
+ */
+int acpiphp_configure_function (struct acpiphp_func *func)
+{
+	int retval = 0;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	struct acpiphp_bridge *bridge;
+
+	/* if pci_dev is NULL, ignore it */
+	if (!func->pci_dev)
+		goto err_exit;
+
+	bridge = func->slot->bridge;
+
+	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+	wrapped_dev.dev = func->pci_dev;
+	wrapped_dev.data = func;
+	wrapped_bus.bus = bridge->pci_bus;
+	wrapped_bus.data = bridge;
+
+	retval = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
+	if (retval)
+		goto err_exit;
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * acpiphp_unconfigure_function - unconfigure PCI function
+ * @func: function to be unconfigured
+ *
+ */
+int acpiphp_unconfigure_function (struct acpiphp_func *func)
+{
+	struct acpiphp_bridge *bridge;
+	struct pci_resource *tmp;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	int retval = 0;
+
+	/* if pci_dev is NULL, ignore it */
+	if (!func->pci_dev)
+		goto err_exit;
+
+	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+	wrapped_dev.dev = func->pci_dev;
+	//wrapped_dev.data = func;
+	wrapped_bus.bus = func->slot->bridge->pci_bus;
+	//wrapped_bus.data = func->slot->bridge;
+
+	retval = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus);
+	if (retval)
+		goto err_exit;
+
+	retval = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus);
+	if (retval)
+		goto err_exit;
+
+	/* free all resources */
+	bridge = func->slot->bridge;
+
+	spin_lock(&bridge->res_lock);
+	acpiphp_move_resource(&func->io_head, &bridge->io_head);
+	acpiphp_move_resource(&func->mem_head, &bridge->mem_head);
+	acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head);
+	acpiphp_move_resource(&func->bus_head, &bridge->bus_head);
+	spin_unlock(&bridge->res_lock);
+
+ err_exit:
+	return retval;
+}
+
+
+/* XXX IA64 specific */
+#ifdef CONFIG_IA64
+static int ia64_get_irq(struct pci_dev *dev, int pin)
+{
+	extern int pci_pin_to_vector(int bus, int slot, int pci_pin);
+	int irq;
+
+	irq = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
+
+	if (irq < 0 && dev->bus->parent) {
+		/* go back to the bridge */
+		struct pci_dev *bridge = dev->bus->self;
+
+		if (bridge) {
+			/* allow for multiple bridges on an adapter */
+			do {
+				/* do the bridge swizzle... */
+				pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+				irq = pci_pin_to_vector(bridge->bus->number,
+							PCI_SLOT(bridge->devfn),
+							   pin);
+			} while (irq < 0 && (bridge = bridge->bus->self));
+		}
+		if (irq >= 0)
+			printk(KERN_WARNING
+			       "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n",
+			       dev->bus->number, PCI_SLOT(dev->devfn),
+			       pin, irq);
+		else
+			printk(KERN_WARNING
+			       "PCI: Couldn't map irq for (B%d,I%d,P%d)\n",
+			       dev->bus->number, PCI_SLOT(dev->devfn), pin);
+	}
+
+	return irq;
+}
+#endif
+
+
+/*
+ * acpiphp_configure_irq - configure PCI_INTERRUPT_PIN
+ *
+ * for x86 platforms, pcibios_enable_device calls pcibios_enable_irq,
+ * which allocates irq for pci_dev
+ *
+ * for IA64 platforms, we have to program dev->irq from pci IRQ routing
+ * information derived from ACPI table
+ *
+ * TBD:
+ * separate architecture dependent part
+ * (preferably, pci_enable_device() cares for allocating irq...)
+ */
+static void acpiphp_configure_irq (struct pci_dev *dev)
+{
+#if CONFIG_IA64		    /* XXX IA64 specific, need i386 version */
+	int bus, device, function, irq;
+	u8 tmp;
+
+	bus = dev->bus->number;
+	device = PCI_SLOT(dev->devfn);
+	function = PCI_FUNC(dev->devfn);
+
+	pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &tmp);
+
+	if ((tmp > 0x00) && (tmp < 0x05)) {
+		irq = ia64_get_irq(dev, tmp - 1);
+		if (irq > 0) {
+			dev->irq = irq;
+			pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq);
+		} else {
+			err("Couldn't get IRQ for INT%c", 'A' + tmp - 1);
+		}
+	}
+#endif
+}
diff -urN linux-2.4.20-pre1/drivers/hotplug/acpiphp_res.c linux-2.4.20-pre2/drivers/hotplug/acpiphp_res.c
--- linux-2.4.20-pre1/drivers/hotplug/acpiphp_res.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/hotplug/acpiphp_res.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,708 @@
+/*
+ * ACPI PCI HotPlug Utility functions
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
+ * Copyright (c) 2002 NEC Corporation
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>,<h-aono@ap.jp.nec.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+
+#include <linux/ioctl.h>
+#include <linux/fcntl.h>
+
+#include <linux/list.h>
+
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+#define MY_NAME "acpiphp_res"
+
+/* local variables */
+static int debug = 0;
+
+/*
+ * sort_by_size - sort nodes by their length, smallest first
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length > (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length > current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+
+
+/*
+ * sort_by_max_size - sort nodes by their length, largest first
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length < (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length < current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+
+/**
+ * get_io_resource - get resource for I/O ports
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length that is not in the
+ * ISA aliasing window.  If it finds a node larger than "size"
+ * it will split it up.
+ *
+ * size must be a power of two.
+ *
+ * difference from get_resource is handling of ISA aliasing space.
+ *
+ */
+struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_size(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_qword - node->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
+
+			if (!split_node)
+				return NULL;
+
+			node->base = temp_qword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = acpiphp_make_resource(node->base + size, node->length - size);
+
+			if (!split_node)
+				return NULL;
+
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if (node->base & 0x300L)
+			continue;
+
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+
+	return node;
+}
+
+
+/**
+ * get_max_resource - get the largest resource
+ *
+ * Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ */
+struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_max_size(head))
+		return NULL;
+
+	for (max = *head;max; max = max->next) {
+
+		/* If not big enough we could probably just bail, 
+		   instead we'll continue to the next. */
+		if (max->length < size)
+			continue;
+
+		if (max->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = (max->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max->length - (temp_qword - max->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(max->base, temp_qword - max->base);
+
+			if (!split_node)
+				return NULL;
+
+			max->base = temp_qword;
+			max->length -= split_node->length;
+
+			/* Put it next in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		if ((max->base + max->length) & (size - 1)) {
+			/* this one isn't end aligned properly at the top
+			   so we'll make a new entry and split it up */
+			temp_qword = ((max->base + max->length) & ~(size - 1));
+
+			split_node = acpiphp_make_resource(temp_qword,
+							   max->length + max->base - temp_qword);
+
+			if (!split_node)
+				return NULL;
+
+			max->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max->length < size)
+			continue;
+
+		/* Now take it out of the list */
+		temp = (struct pci_resource*) *head;
+		if (temp == max) {
+			*head = max->next;
+		} else {
+			while (temp && temp->next != max) {
+				temp = temp->next;
+			}
+
+			temp->next = max->next;
+		}
+
+		max->next = NULL;
+		return max;
+	}
+
+	/* If we get here, we couldn't find one */
+	return NULL;
+}
+
+
+/**
+ * get_resource - get resource (mem, pfmem)
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ *
+ */
+struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_size(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x",
+		    __FUNCTION__, size, node, (u32)node->base, node->length);
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			dbg("%s: not aligned", __FUNCTION__);
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_qword - node->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
+
+			if (!split_node)
+				return NULL;
+
+			node->base = temp_qword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			dbg("%s: too big", __FUNCTION__);
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = acpiphp_make_resource(node->base + size, node->length - size);
+
+			if (!split_node)
+				return NULL;
+
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		dbg("%s: got one!!!", __FUNCTION__);
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return node;
+}
+
+/**
+ * get_resource_with_base - get resource with specific base address
+ *
+ * this function 
+ * returns the first node of "size" length located at specified base address.
+ * If it finds a node larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ *
+ */
+struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		    (u32)base, size, node, (u32)node->base, node->length);
+		if (node->base > base)
+			continue;
+
+		if ((node->base + node->length) < (base + size))
+			continue;
+
+		if (node->base < base) {
+			dbg(": split 1");
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = base;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_qword - node->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
+
+			if (!split_node)
+				return NULL;
+
+			node->base = temp_qword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}
+
+		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		    (u32)base, size, node, (u32)node->base, node->length);
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			dbg(": split 2");
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = acpiphp_make_resource(node->base + size, node->length - size);
+
+			if (!split_node)
+				return NULL;
+
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		dbg(": got one!!!");
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return node;
+}
+
+
+/**
+ * acpiphp_resource_sort_and_combine
+ *
+ * Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int acpiphp_resource_sort_and_combine (struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	dbg("*head->next = %p",(*head)->next);
+
+	if (!(*head)->next)
+		return 0;	/* only one item on the list, already sorted! */
+
+	dbg("*head->base = 0x%x",(u32)(*head)->base);
+	dbg("*head->next->base = 0x%x", (u32)(*head)->next->base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->base > (*head)->next->base)) {
+			node1 = *head;
+			(*head) = (*head)->next;
+			node1->next = (*head)->next;
+			(*head)->next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1->next && node1->next->next) {
+			if (node1->next->base > node1->next->next->base) {
+				out_of_order++;
+				node2 = node1->next;
+				node1->next = node1->next->next;
+				node1 = node1->next;
+				node2->next = node1->next;
+				node1->next = node2;
+			} else
+				node1 = node1->next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 && node1->next) {
+		if ((node1->base + node1->length) == node1->next->base) {
+			/* Combine */
+			dbg("8..");
+			node1->length += node1->next->length;
+			node2 = node1->next;
+			node1->next = node1->next->next;
+			kfree(node2);
+		} else
+			node1 = node1->next;
+	}
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_make_resource - make resource structure
+ * @base: base address of a resource
+ * @length: length of a resource
+ */
+struct pci_resource *acpiphp_make_resource (u64 base, u32 length)
+{
+	struct pci_resource *res;
+
+	res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+	if (res) {
+		memset(res, 0, sizeof(struct pci_resource));
+		res->base = base;
+		res->length = length;
+	}
+
+	return res;
+}
+
+
+/**
+ * acpiphp_move_resource - move linked resources from one to another
+ * @from: head of linked resource list
+ * @to: head of linked resource list
+ */
+void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to)
+{
+	struct pci_resource *tmp;
+
+	while (*from) {
+		tmp = (*from)->next;
+		(*from)->next = *to;
+		*to = *from;
+		*from = tmp;
+	}
+
+	/* *from = NULL is guaranteed */
+}
+
+
+/**
+ * acpiphp_free_resource - free all linked resources
+ * @res: head of linked resource list
+ */
+void acpiphp_free_resource (struct pci_resource **res)
+{
+	struct pci_resource *tmp;
+
+	while (*res) {
+		tmp = (*res)->next;
+		kfree(*res);
+		*res = tmp;
+	}
+
+	/* *res = NULL is guaranteed */
+}
+
+
+/* debug support functions;  will go away sometime :) */
+static void dump_resource(struct pci_resource *head)
+{
+	struct pci_resource *p;
+	int cnt;
+
+	p = head;
+	cnt = 0;
+
+	while (p) {
+		info("[%02d] %08x - %08x",
+		     cnt++, (u32)p->base, (u32)p->base + p->length - 1);
+		p = p->next;
+	}
+}
+
+void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
+{
+	info("I/O resource:");
+	dump_resource(bridge->io_head);
+	info("MEM resource:");
+	dump_resource(bridge->mem_head);
+	info("PMEM resource:");
+	dump_resource(bridge->p_mem_head);
+	info("BUS resource:");
+	dump_resource(bridge->bus_head);
+}
+
+void acpiphp_dump_func_resource(struct acpiphp_func *func)
+{
+	info("I/O resource:");
+	dump_resource(func->io_head);
+	info("MEM resource:");
+	dump_resource(func->mem_head);
+	info("PMEM resource:");
+	dump_resource(func->p_mem_head);
+	info("BUS resource:");
+	dump_resource(func->bus_head);
+}
+
+/*
+EXPORT_SYMBOL(acpiphp_get_io_resource);
+EXPORT_SYMBOL(acpiphp_get_max_resource);
+EXPORT_SYMBOL(acpiphp_get_resource);
+EXPORT_SYMBOL(acpiphp_resource_sort_and_combine);
+*/
diff -urN linux-2.4.20-pre1/drivers/hotplug/ibmphp.h linux-2.4.20-pre2/drivers/hotplug/ibmphp.h
--- linux-2.4.20-pre1/drivers/hotplug/ibmphp.h	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/hotplug/ibmphp.h	Mon Aug 12 16:34:16 2002
@@ -168,13 +168,11 @@
 
 struct ebda_hpc_bus {
 	u32 bus_num;
-/*
 	u8 slots_at_33_conv;
 	u8 slots_at_66_conv;
 	u8 slots_at_66_pcix;
 	u8 slots_at_100_pcix;
 	u8 slots_at_133_pcix;
-*/
 };
 
 
@@ -232,12 +230,15 @@
 	u8 slot_max;
 	u8 slot_count;
 	u8 busno;
-	u8 current_speed;
-	u8 supported_speed;
 	u8 controller_id;
-	u8 supported_bus_mode;
+	u8 current_speed;
 	u8 current_bus_mode;
 	u8 index;
+	u8 slots_at_33_conv;
+	u8 slots_at_66_conv;
+	u8 slots_at_66_pcix;
+	u8 slots_at_100_pcix;
+	u8 slots_at_133_pcix;
 	struct list_head bus_info_list;
 };
 
@@ -690,8 +691,11 @@
 	u8 bus;
 	u8 device;
 	u8 number;
+	u8 real_physical_slot_num;
 	char name[100];
 	u32 capabilities;
+	u8 supported_speed;
+	u8 supported_bus_mode;
 	struct hotplug_slot *hotplug_slot;
 	struct controller *ctrl;
 	struct pci_func *func;
@@ -709,10 +713,12 @@
 struct controller {
 	struct ebda_hpc_slot *slots;
 	struct ebda_hpc_bus *buses;
+	u8 starting_slot_num;	/* starting and ending slot #'s this ctrl controls*/
+	u8 ending_slot_num;
 	u8 revision;
 	u8 options;		/* which options HPC supports */
 	u8 status;
-	u8 ctlr_id;		/* TONI */
+	u8 ctlr_id;
 	u8 slot_count;
 	u8 bus_count;
 	u8 ctlr_relative_id;
diff -urN linux-2.4.20-pre1/drivers/hotplug/ibmphp_core.c linux-2.4.20-pre2/drivers/hotplug/ibmphp_core.c
--- linux-2.4.20-pre1/drivers/hotplug/ibmphp_core.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/hotplug/ibmphp_core.c	Mon Aug 12 16:34:16 2002
@@ -44,7 +44,7 @@
 #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
 #define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
 
-#define DRIVER_VERSION	"0.1"
+#define DRIVER_VERSION	"0.3"
 #define DRIVER_DESC	"IBM Hot Plug PCI Controller Driver"
 
 int ibmphp_debug;
@@ -393,8 +393,8 @@
 		pslot = (struct slot *) hotplug_slot->private;
 		if (pslot) {
 			rc = 0;
-			mode = pslot->bus_on->supported_bus_mode;
-			*value = pslot->bus_on->supported_speed;
+			mode = pslot->supported_bus_mode;
+			*value = pslot->supported_speed;
 			*value &= 0x0f;
 
 			if (mode == BUS_MODE_PCIX)
@@ -1009,6 +1009,7 @@
 	}
 	return rc;
 }
+
 /*******************************************************
  * Returns whether the bus is empty or not 
  *******************************************************/
@@ -1036,7 +1037,9 @@
 
 /***********************************************************
  * If the HPC permits and the bus currently empty, tries to set the 
- * bus speed and mode at the maximum card capability
+ * bus speed and mode at the maximum card and bus capability
+ * Parameters: slot
+ * Returns: bus is set (0) or error code
  ***********************************************************/
 static int set_bus (struct slot * slot_cur)
 {
@@ -1056,30 +1059,102 @@
 			cmd = HPC_BUS_33CONVMODE;
 			break;
 		case HPC_SLOT_SPEED_66:
-			if (SLOT_PCIX (slot_cur->ext_status))
-				cmd = HPC_BUS_66PCIXMODE;
-			else
-				cmd = HPC_BUS_66CONVMODE;
+			if (SLOT_PCIX (slot_cur->ext_status)) {
+				if ((slot_cur->supported_speed >= BUS_SPEED_66) && (slot_cur->supported_bus_mode == BUS_MODE_PCIX))
+					cmd = HPC_BUS_66PCIXMODE;
+				else if (!SLOT_BUS_MODE (slot_cur->ext_status))
+					/* if max slot/bus capability is 66 pci
+					and there's no bus mode mismatch, then
+					the adapter supports 66 pci */ 
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			} else {
+				if (slot_cur->supported_speed >= BUS_SPEED_66)
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			}
 			break;
 		case HPC_SLOT_SPEED_133:
-			if (slot_cur->bus_on->slot_count > 1)
+			switch (slot_cur->supported_speed) {
+			case BUS_SPEED_33:
+				cmd = HPC_BUS_33CONVMODE;
+				break;
+			case BUS_SPEED_66:
+				if (slot_cur->supported_bus_mode == BUS_MODE_PCIX)
+					cmd = HPC_BUS_66PCIXMODE;
+				else
+					cmd = HPC_BUS_66CONVMODE;
+				break;
+			case BUS_SPEED_100:
 				cmd = HPC_BUS_100PCIXMODE;
-			else
+				break;
+			case BUS_SPEED_133:
 				cmd = HPC_BUS_133PCIXMODE;
+				break;
+			default:
+				err ("Wrong bus speed \n");
+				return -ENODEV;
+			}
 			break;
 		default:
 			err ("wrong slot speed \n");
 			return -ENODEV;
 		}
 		debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd);
-		rc = ibmphp_hpc_writeslot (slot_cur, cmd);
-		if (rc)
-			return rc;
+		ibmphp_hpc_writeslot (slot_cur, cmd);
 	}
+	/* This is for x400, once Brandon fixes the firmware, 
+	will not need this delay */
+	long_delay (1 * HZ);
 	debug ("%s -Exit \n", __FUNCTION__);
 	return 0;
 }
 
+/* This routine checks the bus limitations that the slot is on from the BIOS.
+ * This is used in deciding whether or not to power up the slot.  
+ * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on
+ * same bus) 
+ * Parameters: slot
+ * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus
+ */
+static int check_limitations (struct slot *slot_cur)
+{
+	u8 i;
+	struct slot * tmp_slot;
+	u8 count = 0;
+	u8 limitation = 0;
+
+	for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) {
+		tmp_slot = ibmphp_get_slot_from_physical_num (i);
+		if ((SLOT_POWER (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) 
+			count++;
+	}
+	get_cur_bus_info (&slot_cur);
+	switch (slot_cur->bus_on->current_speed) {
+	case BUS_SPEED_33:
+		limitation = slot_cur->bus_on->slots_at_33_conv;
+		break;
+	case BUS_SPEED_66:
+		if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
+			limitation = slot_cur->bus_on->slots_at_66_pcix;
+		else
+			limitation = slot_cur->bus_on->slots_at_66_conv;
+		break;
+	case BUS_SPEED_100:
+		limitation = slot_cur->bus_on->slots_at_100_pcix;
+		break;
+	case BUS_SPEED_133:
+		limitation = slot_cur->bus_on->slots_at_133_pcix;
+		break;
+	}
+
+	if ((count + 1) > limitation)
+		return -EINVAL;
+	return 0;
+}
+
 static inline void print_card_capability (struct slot *slot_cur)
 {
 	info ("capability of the card is ");
@@ -1136,7 +1211,28 @@
 		ibmphp_unlock_operations ();
 		return -ENODEV;
 	}
-		
+
+	/*-----------------debugging------------------------------*/
+	get_cur_bus_info (&slot_cur);
+	debug ("the current bus speed right after set_bus = %x \n", slot_cur->bus_on->current_speed); 
+	/*----------------------------------------------------------*/
+
+	rc = check_limitations (slot_cur);
+	if (rc) {
+		err ("Adding this card exceeds the limitations of this bus. \n");
+		err ("(i.e., >1 133MHz cards running on same bus, or >2 66 PCI cards running on same bus \n. Try hot-adding into another bus \n");
+		attn_off (slot_cur);
+		attn_on (slot_cur);
+
+		if (slot_update (&slot_cur)) {
+			ibmphp_unlock_operations ();
+			return -ENODEV;
+		}
+		ibmphp_update_slot_info (slot_cur);
+		ibmphp_unlock_operations ();
+		return -EINVAL;
+	}
+
 	rc = power_on (slot_cur);
 
 	if (rc) {
@@ -1151,19 +1247,24 @@
 			return -ENODEV;
 		}
 		/* Check to see the error of why it failed */
-		if (!(SLOT_PWRGD (slot_cur->status)))
+		if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PWRGD (slot_cur->status)))
 			err ("power fault occured trying to power up \n");
 		else if (SLOT_BUS_SPEED (slot_cur->status)) {
 			err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
 			print_card_capability (slot_cur);
-		} else if (SLOT_BUS_MODE (slot_cur->ext_status)) 
+		} else if (SLOT_BUS_MODE (slot_cur->ext_status)) {
 			err ("bus mode mismatch occured.  please check current bus mode and card capability \n");
-
+			print_card_capability (slot_cur);
+		}
 		ibmphp_update_slot_info (slot_cur);
-		ibmphp_unlock_operations (); 
+		ibmphp_unlock_operations ();
 		return rc;
 	}
 	debug ("after power_on\n");
+	/*-----------------------debugging---------------------------*/
+	get_cur_bus_info (&slot_cur);
+	debug ("the current bus speed right after power_on = %x \n", slot_cur->bus_on->current_speed);
+	/*----------------------------------------------------------*/
 
 	rc = slot_update (&slot_cur);
 	if (rc) {
@@ -1180,7 +1281,7 @@
 	
 	if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) {
 		faulted = 1;
-		err ("power fault occured trying to power up...\n");
+		err ("power fault occured trying to power up... \n");
 	} else if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) {
 		faulted = 1;
 		err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
@@ -1200,8 +1301,8 @@
 			return rcpr;
 		}
 			
-		if (slot_update (&slot_cur)) {
-			ibmphp_unlock_operations ();
+		if (slot_update (&slot_cur)) {                      
+			ibmphp_unlock_operations ();	
 			return -ENODEV;
 		}
 		ibmphp_update_slot_info (slot_cur);
@@ -1278,20 +1379,24 @@
 {
 	int rc;
 	struct slot *slot_cur = (struct slot *) hotplug_slot->private;
-	u8 flag = slot_cur->flag;
+	u8 flag;
+	int parm = 0;
 
-	slot_cur->flag = TRUE;
 	debug ("DISABLING SLOT... \n"); 
 		
-	ibmphp_lock_operations (); 
-	if (slot_cur == NULL) {
-		ibmphp_unlock_operations ();
+	if (slot_cur == NULL) 
 		return -ENODEV;
-	}
-	if (slot_cur->ctrl == NULL) {
-		ibmphp_unlock_operations ();
+	
+	if (slot_cur->ctrl == NULL) 
 		return -ENODEV;
-	}
+	
+	flag = slot_cur->flag;	/* to see if got here from polling */
+	
+	if (flag)
+		ibmphp_lock_operations ();
+	
+	slot_cur->flag = TRUE;
+
 	if (flag == TRUE) {
 		rc = validate (slot_cur, DISABLE);	/* checking if powered off already & valid slot # */
 		if (rc) {
@@ -1333,10 +1438,21 @@
 		ibmphp_unlock_operations ();
 		return rc;
 	}
+        
+	/* If we got here from latch suddenly opening on operating card or 
+	a power fault, there's no power to the card, so cannot
+	read from it to determine what resources it occupied.  This operation
+	is forbidden anyhow.  The best we can do is remove it from kernel
+	lists at least */
+
+	if (!flag) {
+		attn_off (slot_cur);
+		return 0;
+	}
 
-	rc = ibmphp_unconfigure_card (&slot_cur, 0);
+	rc = ibmphp_unconfigure_card (&slot_cur, parm);
 	slot_cur->func = NULL;
-	debug ("in disable_slot. after unconfigure_card \n");
+	debug ("in disable_slot. after unconfigure_card\n");
 	if (rc) {
 		err ("could not unconfigure card.\n");
 		attn_off (slot_cur);	/* need to turn off if was blinking b4 */
@@ -1347,9 +1463,7 @@
 			return -EFAULT;
 		}
 
-		if (flag) 
-			ibmphp_update_slot_info (slot_cur);
-
+		ibmphp_update_slot_info (slot_cur);
 		ibmphp_unlock_operations ();
 		return -EFAULT;
 	}
@@ -1363,9 +1477,7 @@
 			return -EFAULT;
 		}
 
-		if (flag)
-			ibmphp_update_slot_info (slot_cur);
-
+		ibmphp_update_slot_info (slot_cur);
 		ibmphp_unlock_operations ();
 		return rc;
 	}
@@ -1375,11 +1487,7 @@
 		ibmphp_unlock_operations ();
 		return -EFAULT;
 	}
-	if (flag) 
-		rc = ibmphp_update_slot_info (slot_cur);
-	else
-		rc = 0;
-
+	rc = ibmphp_update_slot_info (slot_cur);
 	ibmphp_print_test ();
 	ibmphp_unlock_operations();
 	return rc;
@@ -1422,9 +1530,12 @@
 	int rc = 0;
 
 	init_flag = 1;
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
 	ibmphp_pci_root_ops = get_root_pci_ops ();
 	if (ibmphp_pci_root_ops == NULL) {
-		err ("cannot read bus operations... will not be able to read the cards.  Please check your system \n");
+		err ("cannot read bus operations... will not be able to read the cards.  Please check your system\n");
 		return -ENODEV;	
 	}
 
@@ -1439,13 +1550,13 @@
 		ibmphp_unload ();
 		return rc;
 	}
-	debug ("after ibmphp_access_ebda () \n");
+	debug ("after ibmphp_access_ebda ()\n");
 
 	if ((rc = ibmphp_rsrc_init ())) {
 		ibmphp_unload ();
 		return rc;
 	}
-	debug ("AFTER Resource & EBDA INITIALIZATIONS \n");
+	debug ("AFTER Resource & EBDA INITIALIZATIONS\n");
 
 	max_slots = get_max_slots ();
 
@@ -1463,7 +1574,6 @@
 	 * so that no one can unload us. */
 	MOD_DEC_USE_COUNT;
 
-	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
 
 	return 0;
 }
@@ -1471,9 +1581,9 @@
 static void __exit ibmphp_exit (void)
 {
 	ibmphp_hpc_stop_poll_thread ();
-	debug ("after polling \n");
+	debug ("after polling\n");
 	ibmphp_unload ();
-	debug ("done \n");
+	debug ("done\n");
 }
 
 module_init (ibmphp_init);
diff -urN linux-2.4.20-pre1/drivers/hotplug/ibmphp_ebda.c linux-2.4.20-pre2/drivers/hotplug/ibmphp_ebda.c
--- linux-2.4.20-pre1/drivers/hotplug/ibmphp_ebda.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/hotplug/ibmphp_ebda.c	Mon Aug 12 16:34:16 2002
@@ -161,9 +161,14 @@
 		debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count);
 		debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno);
 		debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed);
-		debug ("%s - supported_speed = %x\n", __FUNCTION__, ptr->supported_speed);
 		debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id);
-		debug ("%s - bus_mode = %x\n", __FUNCTION__, ptr->supported_bus_mode);
+		
+		debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv);
+		debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv);
+		debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix);
+		debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix);
+		debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix);
+
 	}
 }
 
@@ -455,19 +460,9 @@
 				bus_info_ptr1->index = bus_index++;
 				bus_info_ptr1->current_speed = 0xff;
 				bus_info_ptr1->current_bus_mode = 0xff;
-				if ( ((slot_ptr->slot_cap) & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX )
-					bus_info_ptr1->supported_speed =  3;
-				else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX )
-					bus_info_ptr1->supported_speed =  2;
-				else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX )
-					bus_info_ptr1->supported_speed =  1;
+				
 				bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
-				if ( ((slot_ptr->slot_cap) & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP )
-					bus_info_ptr1->supported_bus_mode = 1;
-				else
-					bus_info_ptr1->supported_bus_mode =0;
-
-
+				
 				list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head);
 
 			} else {
@@ -486,9 +481,25 @@
 		/* init bus structure */
 		bus_ptr = hpc_ptr->buses;
 		for (bus = 0; bus < bus_num; bus++) {
-			bus_ptr->bus_num = readb (io_mem + addr_bus);
+			bus_ptr->bus_num = readb (io_mem + addr_bus + bus);
+			bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus);
+			bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1);
+
+			bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2);
+
+			bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3);
+
+			bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4);
+
+			bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num);
+			if (bus_info_ptr2) {
+				bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv;
+				bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv;
+				bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix;
+				bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix;
+				bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; 
+			}
 			bus_ptr++;
-			addr_bus += 1;
 		}
 
 		hpc_ptr->ctlr_type = temp;
@@ -511,10 +522,6 @@
 			case 2:
 				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
 				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
-				/* following 2 lines for testing purpose */
-				if (hpc_ptr->u.wpeg_ctlr.i2c_addr == 0) 
-					hpc_ptr->ctlr_type = 4;	
-				
 
 				hpc_ptr->irq = readb (io_mem + addr + 5);
 				addr += 6;
@@ -537,6 +544,8 @@
 
 		hpc_ptr->revision = 0xff;
 		hpc_ptr->options = 0xff;
+		hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
+		hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num;
 
 		// register slots with hpc core as well as create linked list of ibm slot
 		for (index = 0; index < hpc_ptr->slot_count; index++) {
@@ -573,10 +582,24 @@
 				return -ENOMEM;
 			}
 
+
 			((struct slot *)hp_slot_ptr->private)->flag = TRUE;
 			snprintf (hp_slot_ptr->name, 10, "%d", hpc_ptr->slots[index].slot_num);
 
 			((struct slot *) hp_slot_ptr->private)->capabilities = hpc_ptr->slots[index].slot_cap;
+			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
+				((struct slot *) hp_slot_ptr->private)->supported_speed =  3;
+			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
+				((struct slot *) hp_slot_ptr->private)->supported_speed =  2;
+			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
+				((struct slot *) hp_slot_ptr->private)->supported_speed =  1;
+				
+			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
+				((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 1;
+			else
+				((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 0;
+
+
 			((struct slot *) hp_slot_ptr->private)->bus = hpc_ptr->slots[index].slot_bus_num;
 
 			bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num);
@@ -591,7 +614,7 @@
 
 			((struct slot *) hp_slot_ptr->private)->ctlr_index = hpc_ptr->slots[index].ctl_index;
 			((struct slot *) hp_slot_ptr->private)->number = hpc_ptr->slots[index].slot_num;
-
+			
 			((struct slot *) hp_slot_ptr->private)->hotplug_slot = hp_slot_ptr;
 
 			rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr);
diff -urN linux-2.4.20-pre1/drivers/hotplug/ibmphp_hpc.c linux-2.4.20-pre2/drivers/hotplug/ibmphp_hpc.c
--- linux-2.4.20-pre1/drivers/hotplug/ibmphp_hpc.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-pre2/drivers/hotplug/ibmphp_hpc.c	Mon Aug 12 16:34:16 2002
@@ -3,7 +3,7 @@
  *
  * Written By: Jyoti Shah, IBM Corporation
  *
- * Copyright (c) 2001,2001 IBM Corp.
+ * Copyright (c) 2001-2002 IBM Corp.
  *
  * All rights reserved.
  *
@@ -27,7 +27,6 @@
  *
  */
 
-//#include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/time.h>
 #include <linux/module.h>
@@ -35,9 +34,6 @@
 #include <linux/smp_lock.h>
 #include "ibmphp.h"
 
-#define POLL_NO		0x01
-#define POLL_YES	0x00
-
 static int to_debug = FALSE;
 #define debug_polling(fmt, arg...)	do { if (to_debug) debug (fmt, arg); } while (0)
 
@@ -83,10 +79,6 @@
 //
 //----------------------------------------------------------------------------
 #define WPG_I2C_IOREMAP_SIZE	0x2044	// size of linear address interval
-#define WPG_CTLR_MAX		0x01	// max controllers
-#define WPG_SLOT_MAX		0x06	// max slots
-#define WPG_CTLR_SLOT_MAX	0x06	// max slots per controller
-#define WPG_FIRST_CTLR		0x00	// index of the controller
 
 //----------------------------------------------------------------------------
 // command index
@@ -102,19 +94,15 @@
 // if bits 20,22,25,26,27,29,30 are OFF return TRUE
 #define HPC_I2CSTATUS_CHECK(s)	((u8)((s & 0x00000A76) ? FALSE : TRUE))
 
-// return code 0:poll slots, 1-POLL_LATCH_CNT:poll latch register
-#define INCREMENT_POLLCNT(i)	((i < POLL_LATCH_CNT) ? i++ : (i=0))
 //----------------------------------------------------------------------------
 // global variables
 //----------------------------------------------------------------------------
 static int ibmphp_shutdown;
 static int tid_poll;
-static int stop_polling;		// 2 values: poll, don't poll
 static struct semaphore sem_hpcaccess;	// lock access to HPC
 static struct semaphore semOperations;	// lock all operations and
 					// access to data structures
 static struct semaphore sem_exit;	// make sure polling thread goes away
-static struct semaphore sem_poll;	// make sure poll is idle 
 //----------------------------------------------------------------------------
 // local function prototypes
 //----------------------------------------------------------------------------
@@ -127,7 +115,7 @@
 static void poll_hpc (void);
 static int update_slot (struct slot *, u8);
 static int process_changeinstatus (struct slot *, struct slot *);
-static int process_changeinlatch (u8, u8);
+static int process_changeinlatch (u8, u8, struct controller *);
 static int hpc_poll_thread (void *);
 static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *);
 //----------------------------------------------------------------------------
@@ -145,8 +133,6 @@
 	init_MUTEX (&sem_hpcaccess);
 	init_MUTEX (&semOperations);
 	init_MUTEX_LOCKED (&sem_exit);
-	init_MUTEX_LOCKED (&sem_poll);
-	stop_polling = POLL_YES;
 	to_debug = FALSE;
 	ibmphp_shutdown = FALSE;
 	tid_poll = 0;
@@ -277,8 +263,7 @@
 	int i;
 
 
-	debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n",
-		       __FUNCTION__, (ulong) WPGBbar, index, cmd);
+	debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n", __FUNCTION__, (ulong) WPGBbar, index, cmd);
 
 	rc = 0;
 	//--------------------------------------------------------------------
@@ -470,8 +455,7 @@
 	int rc = 0;
 	int busindex;
 
-	debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n",
-		       __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus);
+	debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n", __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus);
 
 	if ((pslot == NULL)
 	    || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) {
@@ -716,11 +700,6 @@
 void ibmphp_lock_operations (void)
 {
 	down (&semOperations);
-	stop_polling = POLL_NO;
-	to_debug = TRUE;
-
-	/* waiting for polling to actually stop */
-	down (&sem_poll);
 }
 
 /*----------------------------------------------------------------------
@@ -729,8 +708,6 @@
 void ibmphp_unlock_operations (void)
 {
 	debug ("%s - Entry\n", __FUNCTION__);
-	stop_polling = POLL_YES;
-	to_debug = FALSE;
 	up (&semOperations);
 	debug ("%s - Exit\n", __FUNCTION__);
 }
@@ -738,34 +715,30 @@
 /*----------------------------------------------------------------------
 * Name:    poll_hpc()
 *---------------------------------------------------------------------*/
+#define POLL_LATCH_REGISTER	0
+#define POLL_SLOTS		1
+#define POLL_SLEEP		2
 static void poll_hpc (void)
 {
-	struct slot myslot, *pslot = NULL;
+	struct slot myslot;
+	struct slot *pslot = NULL;
 	struct list_head *pslotlist;
 	int rc;
+	int poll_state = POLL_LATCH_REGISTER;
 	u8 oldlatchlow = 0x00;
 	u8 curlatchlow = 0x00;
-	int pollcnt = 0;
+	int poll_count = 0;
 	u8 ctrl_count = 0x00;
 
-	debug ("poll_hpc - Entry\n");
+	debug ("%s - Entry\n", __FUNCTION__);
 
 	while (!ibmphp_shutdown) {
-		if (stop_polling) {
-			debug ("poll_hpc - stop_polling\n");
-			up (&sem_poll); 
-			/* to prevent deadlock */
-			if (ibmphp_shutdown)
-				break;
-			/* to make the thread sleep */
-			down (&semOperations);
-			up (&semOperations);
-			debug ("poll_hpc - after stop_polling sleep\n");
-		} else {
-			if (pollcnt) {
-				// only poll the latch register
-				oldlatchlow = curlatchlow;
+		/* try to get the lock to do some kind of harware access */
+		down (&semOperations);
 
+		switch (poll_state) {
+			case POLL_LATCH_REGISTER:
+				oldlatchlow = curlatchlow;
 				ctrl_count = 0x00;
 				list_for_each (pslotlist, &ibmphp_slot_head) {
 					if (ctrl_count >= ibmphp_get_total_controllers())
@@ -779,14 +752,16 @@
 										  &curlatchlow);
 							if (oldlatchlow != curlatchlow)
 								process_changeinlatch (oldlatchlow,
-											curlatchlow);
+										       curlatchlow,
+										       pslot->ctrl);
 						}
 					}
 				}
-			} else {
+				poll_state = POLL_SLOTS;
+				break;
+
+			case POLL_SLOTS:
 				list_for_each (pslotlist, &ibmphp_slot_head) {
-					if (stop_polling)
-						break;
 					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
 					// make a copy of the old status
 					memcpy ((void *) &myslot, (void *) pslot,
@@ -797,31 +772,45 @@
 						process_changeinstatus (pslot, &myslot);
 				}
 
-				if (!stop_polling) {
-					ctrl_count = 0x00;
-					list_for_each (pslotlist, &ibmphp_slot_head) {
-						if (ctrl_count >= ibmphp_get_total_controllers())
-							break;
-						pslot =
-						    list_entry (pslotlist, struct slot,
-								ibm_slot_list);
-						if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
-							ctrl_count++;
-							if (READ_SLOT_LATCH (pslot->ctrl))
-								rc = ibmphp_hpc_readslot (pslot,
-											  READ_SLOTLATCHLOWREG,
-											  &curlatchlow);
-						}
+				ctrl_count = 0x00;
+				list_for_each (pslotlist, &ibmphp_slot_head) {
+					if (ctrl_count >= ibmphp_get_total_controllers())
+						break;
+					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+					if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+						ctrl_count++;
+						if (READ_SLOT_LATCH (pslot->ctrl))
+							rc = ibmphp_hpc_readslot (pslot,
+										  READ_SLOTLATCHLOWREG,
+										  &curlatchlow);
 					}
 				}
-			}
-			INCREMENT_POLLCNT (pollcnt);
-			long_delay (POLL_INTERVAL_SEC * HZ);	// snooze
+				++poll_count;
+				if (poll_count >= POLL_LATCH_CNT) {
+					poll_count = 0;
+					poll_state = POLL_SLEEP;
+				}
+				break;
+
+			case POLL_SLEEP:
+				/* don't sleep with a lock on the hardware */
+				up (&semOperations);
+				long_delay (POLL_INTERVAL_SEC * HZ);
+				down (&semOperations);
+				poll_state = POLL_LATCH_REGISTER;
+				break;
 		}
+
+		/* give up the harware semaphore */
+		up (&semOperations);
+
+		/* sleep for a short time just for good measure */
+		set_current_state (TASK_INTERRUPTIBLE);
+		schedule_timeout (HZ/10);
 	}
-	up (&sem_poll);
+
 	up (&sem_exit);
-	debug ("poll_hpc - Exit\n");
+	debug ("%s - Exit\n", __FUNCTION__);
 }
 
 
@@ -917,7 +906,6 @@
 
 	// bit 0 - HPC_SLOT_POWER
 	if ((pslot->status & 0x01) != (poldslot->status & 0x01))
-		/* ????????? DO WE NEED TO UPDATE BUS SPEED INFO HERE ??? */
 		update = TRUE;
 
 	// bit 1 - HPC_SLOT_CONNECT
@@ -936,7 +924,7 @@
 	// bit 5 - HPC_SLOT_PWRGD
 	if ((pslot->status & 0x20) != (poldslot->status & 0x20))
 		// OFF -> ON: ignore, ON -> OFF: disable slot
-		if (poldslot->status & 0x20)
+		if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) 
 			disable = TRUE;
 
 	// bit 6 - HPC_SLOT_BUS_SPEED
@@ -947,20 +935,20 @@
 		update = TRUE;
 		// OPEN -> CLOSE
 		if (pslot->status & 0x80) {
-			if (SLOT_POWER (pslot->status)) {
+			if (SLOT_PWRGD (pslot->status)) {
 				// power goes on and off after closing latch
 				// check again to make sure power is still ON
 				long_delay (1 * HZ);
 				rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status);
-				if (SLOT_POWER (status))
+				if (SLOT_PWRGD (status))
 					update = TRUE;
 				else	// overwrite power in pslot to OFF
 					pslot->status &= ~HPC_SLOT_POWER;
 			}
 		}
 		// CLOSE -> OPEN 
-		else if ((SLOT_POWER (poldslot->status) == HPC_SLOT_POWER_ON)
-			|| (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED)) {
+		else if ((SLOT_PWRGD (poldslot->status) == HPC_SLOT_PWRGD_GOOD)
+			&& (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) {
 			disable = TRUE;
 		}
 		// else - ignore
@@ -994,7 +982,7 @@
 * Return   0 or error codes
 * Value:
 *---------------------------------------------------------------------*/
-static int process_changeinlatch (u8 old, u8 new)
+static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl)
 {
 	struct slot myslot, *pslot;
 	u8 i;
@@ -1004,7 +992,7 @@
 	debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new);
 	// bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots
 
-	for (i = 1; i <= 6; i++) {
+	for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) {
 		mask = 0x01 << i;
 		if ((mask & old) != (mask & new)) {
 			pslot = ibmphp_get_slot_from_physical_num (i);
@@ -1090,7 +1078,6 @@
 	// cleanup
 	free_hpc_access ();
 	ibmphp_unlock_operations ();
-	up (&sem_poll);
 	up (&sem_exit);
 
 	debug ("ibmphp_hpc_stop_poll_thread - Exit\n");
diff -urN linux-2.4.20-pre1/drivers/hotplug/pcihp_acpi.c linux-2.4.20-pre2/drivers/hotplug/pcihp_acpi.c
--- linux-2.4.20-pre1/drivers/hotplug/pcihp_acpi.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/hotplug/pcihp_acpi.c	Wed Dec 31 16:00:00 1969
@@ -1,397 +0,0 @@
-/*
- * ACPI PCI Hot Plug Controller Driver
- *
- * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001-2002 IBM Corp.
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <gregkh@us.ibm.com>,
- *                  <h-aono@ap.jp.nec.com>,
- *		    <t-kouchi@cq.jp.nec.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include "pci_hotplug.h"
-#include "pcihp_acpi.h"
-
-static LIST_HEAD(slot_list);
-
-#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE)
-	#define MY_NAME	"pcihp_acpi"
-#else
-	#define MY_NAME	THIS_MODULE->name
-#endif
-
-/* local variables */
-static int debug = 1;			/* XXX */
-static int num_slots;
-
-#define DRIVER_VERSION	"0.2"
-#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>"
-#define DRIVER_DESC	"ACPI Hot Plug PCI Controller Driver"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
-
-static int enable_slot		(struct hotplug_slot *slot);
-static int disable_slot		(struct hotplug_slot *slot);
-static int set_attention_status (struct hotplug_slot *slot, u8 value);
-static int hardware_test	(struct hotplug_slot *slot, u32 value);
-static int get_power_status	(struct hotplug_slot *slot, u8 *value);
-static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
-static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
-static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
-
-static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
-	owner:			THIS_MODULE,
-	enable_slot:		enable_slot,
-	disable_slot:		disable_slot,
-	set_attention_status:	set_attention_status,
-	hardware_test:		hardware_test,
-	get_power_status:	get_power_status,
-	get_attention_status:	get_attention_status,
-	get_latch_status:	get_latch_status,
-	get_adapter_status:	get_adapter_status,
-};
-
-
-/* Inline functions to check the sanity of a pointer that is passed to us */
-static inline int slot_paranoia_check (struct slot *slot, const char *function)
-{
-	if (!slot) {
-		dbg("%s - slot == NULL", function);
-		return -1;
-	}
-	if (slot->magic != SLOT_MAGIC) {
-		dbg("%s - bad magic number for slot", function);
-		return -1;
-	}
-	if (!slot->hotplug_slot) {
-		dbg("%s - slot->hotplug_slot == NULL!", function);
-		return -1;
-	}
-	return 0;
-}
-
-static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
-{ 
-	struct slot *slot;
-
-	if (!hotplug_slot) {
-		dbg("%s - hotplug_slot == NULL", function);
-		return NULL;
-	}
-
-	slot = (struct slot *)hotplug_slot->private;
-	if (slot_paranoia_check (slot, function))
-                return NULL;
-	return slot;
-}
-
-
-static int enable_slot (struct hotplug_slot *hotplug_slot)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	/* enable the specified slot */
-	retval = pcihp_acpi_enable_slot (slot->acpi_slot);
-
-	return retval;
-}
-
-static int disable_slot (struct hotplug_slot *hotplug_slot)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	/* disable the specified slot */
-	retval = pcihp_acpi_disable_slot (slot->acpi_slot);
-
-	return retval;
-}
-
-static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	/* TBD
-	 * ACPI doesn't have known method to manipulate
-	 * attention status LED
-	 */
-	switch (status) {
-		case 0:
-			/* FIXME turn light off */
-			slot->attention_status = 0;
-			break;
-
-		case 1:
-		default:
-			/* FIXME turn light on */
-			slot->attention_status = 1;
-			break;
-	}
-
-	return retval;
-}
-
-static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	err ("No hardware tests are defined for this driver");
-	retval = -ENODEV;
-
-	return retval;
-}
-
-static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	*value = pcihp_acpi_get_power_status (slot->acpi_slot);
-
-	return retval;
-}
-
-static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	*value = slot->attention_status;
-
-	return retval;
-}
-
-static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	*value = pcihp_acpi_get_latch_status (slot->acpi_slot);
-
-	return retval;
-}
-
-static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
-{
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	int retval = 0;
-	
-	if (slot == NULL)
-		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
-
-	*value = pcihp_acpi_get_adapter_status (slot->acpi_slot);
-
-	return retval;
-}
-
-static int init_acpi (void)
-{
-	int retval;
-
-	dbg("init_acpi");		/* XXX */
-	/* initialize internal data structure etc. */
-	retval = pcihp_acpi_glue_init();
-
-	/* read initial number of slots */
-	if (!retval) {
-		num_slots = pcihp_acpi_get_num_slots();
-		if (num_slots == 0)
-			retval = -ENODEV;
-	}
-
-	return retval;
-}
-
-static void exit_acpi (void)
-{
-	/* deallocate internal data structures etc. */
-	pcihp_acpi_glue_exit();
-}
-
-#define SLOT_NAME_SIZE	10
-static void make_slot_name (struct slot *slot)
-{
-	/* FIXME - get this from the ACPI representation of the slot */
-	snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d", slot->number);
-}
-
-static int init_slots (void)
-{
-	struct slot *slot;
-	int retval = 0;
-	int i;
-
-	for (i = 0; i < num_slots; ++i) {
-		slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
-		if (!slot)
-			return -ENOMEM;
-		memset(slot, 0, sizeof(struct slot));
-
-		slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
-		if (!slot->hotplug_slot) {
-			kfree (slot);
-			return -ENOMEM;
-		}
-		memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
-
-		slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
-		if (!slot->hotplug_slot->info) {
-			kfree (slot->hotplug_slot);
-			kfree (slot);
-			return -ENOMEM;
-		}
-		memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
-
-		slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
-		if (!slot->hotplug_slot->name) {
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
-			return -ENOMEM;
-		}
-
-		slot->magic = SLOT_MAGIC;
-		slot->number = i;
-
-		slot->hotplug_slot->private = slot;
-		make_slot_name (slot);
-		slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
-		
-		slot->acpi_slot = get_slot_from_id (i);
-		slot->hotplug_slot->info->power_status = pcihp_acpi_get_power_status(slot->acpi_slot);
-		slot->hotplug_slot->info->attention_status = pcihp_acpi_get_attention_status(slot->acpi_slot);
-		slot->hotplug_slot->info->latch_status = pcihp_acpi_get_latch_status(slot->acpi_slot);
-		slot->hotplug_slot->info->adapter_status = pcihp_acpi_get_adapter_status(slot->acpi_slot);
-
-		dbg ("registering slot %d", i);
-		retval = pci_hp_register (slot->hotplug_slot);
-		if (retval) {
-			err ("pci_hp_register failed with error %d", retval);
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot->name);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
-			return retval;
-		}
-
-		/* add slot to our internal list */
-		list_add (&slot->slot_list, &slot_list);
-	}
-
-	return retval;
-}
-		
-static void cleanup_slots (void)
-{
-	struct list_head *tmp;
-	struct slot *slot;
-
-	list_for_each (tmp, &slot_list) {
-		slot = list_entry (tmp, struct slot, slot_list);
-		list_del (&slot->slot_list);
-		pci_hp_deregister (slot->hotplug_slot);
-		kfree (slot->hotplug_slot->info);
-		kfree (slot->hotplug_slot->name);
-		kfree (slot->hotplug_slot);
-		kfree (slot);
-	}
-
-	return;
-}
-
-static int __init pcihp_acpi_init(void)
-{
-	int retval;
-
-	/* read all the ACPI info from the system */
-	retval = init_acpi();
-	if (retval)
-		return retval;
-
-	retval = init_slots();
-	if (retval)
-		return retval;
-
-	info (DRIVER_DESC " version: " DRIVER_VERSION);
-	return 0;
-}
-
-static void __exit pcihp_acpi_exit(void)
-{
-	cleanup_slots();
-	exit_acpi();
-}
-
-module_init(pcihp_acpi_init);
-module_exit(pcihp_acpi_exit);
diff -urN linux-2.4.20-pre1/drivers/hotplug/pcihp_acpi.h linux-2.4.20-pre2/drivers/hotplug/pcihp_acpi.h
--- linux-2.4.20-pre1/drivers/hotplug/pcihp_acpi.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/hotplug/pcihp_acpi.h	Wed Dec 31 16:00:00 1969
@@ -1,231 +0,0 @@
-/*
- * ACPI PCI Hot Plug Controller Driver
- *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <gregkh@us.ibm.com>,
- *		    <h-aono@ap.jp.nec.com>,
- *		    <t-kouchi@cq.jp.nec.com>
- *
- */
-
-#ifndef _PCIHP_ACPI_H
-#define _PCIHP_ACPI_H
-
-#include "include/acpi.h"
-
-#if ACPI_CA_VERSION < 0x20020201
-/* until we get a new version of the ACPI driver for both ia32 and ia64 ... */
-#define acpi_util_eval_error(h,p,s)
-
-static acpi_status
-acpi_evaluate_integer (
-	acpi_handle		handle,
-	acpi_string		pathname,
-	acpi_object_list	*arguments,
-	unsigned long		*data)
-{
-	acpi_status             status = AE_OK;
-	acpi_object             element;
-	acpi_buffer		buffer = {sizeof(acpi_object), &element};
-
-	if (!data)
-		return AE_BAD_PARAMETER;
-
-	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
-	if (ACPI_FAILURE(status)) {
-		acpi_util_eval_error(handle, pathname, status);
-		return status;
-	}
-
-	if (element.type != ACPI_TYPE_INTEGER) {
-		acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
-		return AE_BAD_DATA;
-	}
-
-	*data = element.integer.value;
-
-	return AE_OK;
-}
-#else  /* ACPI_CA_VERSION < 0x20020201 */
-#include "acpi_bus.h"
-#endif /* ACPI_CA_VERSION < 0x20020201 */
-
-/* compatibility stuff */
-#ifndef ACPI_MEMORY_RANGE
-#define ACPI_MEMORY_RANGE MEMORY_RANGE
-#endif
-
-#ifndef ACPI_IO_RANGE
-#define ACPI_IO_RANGE IO_RANGE
-#endif
-
-#ifndef ACPI_BUS_NUMBER_RANGE
-#define ACPI_BUS_NUMBER_RANGE BUS_NUMBER_RANGE
-#endif
-
-#ifndef ACPI_PREFETCHABLE_MEMORY
-#define ACPI_PREFETCHABLE_MEMORY PREFETCHABLE_MEMORY
-#endif
-
-#ifndef ACPI_PRODUCER
-#define ACPI_PRODUCER PRODUCER
-#endif
-
-
-#define dbg(format, arg...)					\
-	do {							\
-		if (debug)					\
-			printk (KERN_DEBUG "%s: " format "\n",	\
-				MY_NAME , ## arg); 		\
-	} while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
-
-/*
- * types and constants
- */
-
-#define SLOT_MAGIC	0x67267322
-
-struct pcihp_acpi_bridge;
-struct pcihp_acpi_slot;
-
-/* slot information for each *physical* slot */
-
-struct slot {
-	u32 magic;
-	u8 number;
-	struct hotplug_slot	*hotplug_slot;
-	struct list_head	slot_list;
-
-	int			attention_status;
-
-	struct pci_resource	*mem_head;
-	struct pci_resource	*p_mem_head;
-	struct pci_resource	*io_head;
-	struct pci_resource	*bus_head;
-
-	/* if there are multiple corresponding slot objects,
-	   this point to one of them */
-	struct pcihp_acpi_slot	*acpi_slot;
-
-	struct pci_dev		*pci_dev;
-};
-
-#define RESOURCE_TYPE_IO	(1)
-#define RESOURCE_TYPE_MEM	(2)
-#define RESOURCE_TYPE_PREFETCH	(3)
-#define RESOURCE_TYPE_BUS	(4)
-
-/* TBD 64bit resource support */
-struct pci_resource {
-	struct pci_resource * next;
-	u32 base;
-	u32 length;
-};
-
-/* bridge information for each bridge device in ACPI namespace */
-
-struct pcihp_acpi_bridge {
-	struct list_head list;
-	acpi_handle handle;
-	struct pcihp_acpi_slot *slots;
-	int nr_slots;
-	u8 seg;
-	u8 bus;
-	u8 sub;
-	u32 status;
-	u32 flags;
-
-	/* resources on this bus (free resources) */
-	struct pci_resource *free_io;
-	struct pci_resource *free_mem;
-	struct pci_resource *free_prefetch;
-	struct pci_resource *free_bus;
-
-	/* used resources (embedded or owned resources) */
-	struct pci_resource *used_io;
-	struct pci_resource *used_mem;
-	struct pci_resource *used_prefetch;
-	struct pci_resource *used_bus;
-};
-
-/*
- * slot information for each slot object in ACPI namespace
- * usually 8 objects per slot (for each PCI function)
- */
-
-struct pcihp_acpi_slot {
-	struct pcihp_acpi_slot	*next;
-	struct pcihp_acpi_bridge *bridge; /* this slot located on */
-	struct list_head sibling;	/* one slot may have different
-					   objects (i.e. for each function) */
-	acpi_handle	handle;
-	u32		id;		/* slot id (this driver specific) */
-	u8		device;		/* pci device# */
-	u8		function;	/* pci function# */
-	u8		pin;		/* pci interrupt pin */
-	u32		sun;		/* _SUN */
-	u32		flags;		/* see below */
-	u32		status;		/* _STA */
-};
-
-/* PCI bus bridge HID */
-#define ACPI_PCI_ROOT_HID		"PNP0A03"
-
-/* ACPI _STA method value (ignore bit 4; battery present) */
-#define ACPI_STA_PRESENT		(0x00000001)
-#define ACPI_STA_ENABLED		(0x00000002)
-#define ACPI_STA_SHOW_IN_UI		(0x00000004)
-#define ACPI_STA_FUNCTIONAL		(0x00000008)
-#define ACPI_STA_ALL			(0x0000000f)
-
-/* bridge flags */
-#define BRIDGE_HAS_STA	(0x00000001)
-
-/* slot flags */
-
-#define SLOT_HAS_EJ0	(0x00000001)
-#define SLOT_HAS_PS0	(0x00000002)
-#define SLOT_HAS_PS3	(0x00000004)
-
-/* function prototypes */
-
-/* pcihp_acpi_glue.c */
-extern int pcihp_acpi_glue_init (void);
-extern void pcihp_acpi_glue_exit (void);
-extern int pcihp_acpi_get_num_slots (void);
-extern struct pcihp_acpi_slot *get_slot_from_id (int id);
-
-extern int pcihp_acpi_enable_slot (struct pcihp_acpi_slot *slot);
-extern int pcihp_acpi_disable_slot (struct pcihp_acpi_slot *slot);
-extern u8 pcihp_acpi_get_power_status (struct pcihp_acpi_slot *slot);
-extern u8 pcihp_acpi_get_attention_status (struct pcihp_acpi_slot *slot);
-extern u8 pcihp_acpi_get_latch_status (struct pcihp_acpi_slot *slot);
-extern u8 pcihp_acpi_get_adapter_status (struct pcihp_acpi_slot *slot);
-
-#endif /* _PCIHP_ACPI_H */
diff -urN linux-2.4.20-pre1/drivers/hotplug/pcihp_acpi_ctrl.c linux-2.4.20-pre2/drivers/hotplug/pcihp_acpi_ctrl.c
--- linux-2.4.20-pre1/drivers/hotplug/pcihp_acpi_ctrl.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/hotplug/pcihp_acpi_ctrl.c	Wed Dec 31 16:00:00 1969
@@ -1,642 +0,0 @@
-/*
- * ACPI PCI HotPlug Utility functions
- *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <gregkh@us.ibm.com>,<h-aono@ap.jp.nec.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/sysctl.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-
-#include <linux/ioctl.h>
-#include <linux/fcntl.h>
-
-#include <linux/list.h>
-
-#include <asm/uaccess.h>
-
-#define _LINUX                          /* for acpi subcomponent */
-
-#include "include/acpi.h"
-
-#include "pci_hotplug.h"
-#include "pchihp_acpi.h"
-
-#if !defined(CONFIG_HOTPLUG_PCI_MODULE)
-	#define MY_NAME "pci_hotplug"
-#else
-	#define MY_NAME THIS_MODULE->name
-#endif
-
-#define dbg(fmt, arg...) do { if (debug) printk(KERN_WARNING "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
-
-
-/* local variables */
-static int debug = 0;
-
-/*
- * sort_by_size
- *
- * Sorts nodes on the list by their length.
- * Smallest first.
- *
- */
-static int sort_by_size(struct pci_resource **head)
-{
-	struct pci_resource *current_res;
-	struct pci_resource *next_res;
-	int out_of_order = 1;
-
-	if (!(*head))
-		return(1);
-
-	if (!((*head)->next))
-		return(0);
-
-	while (out_of_order) {
-		out_of_order = 0;
-
-		// Special case for swapping list head
-		if (((*head)->next) &&
-		    ((*head)->length > (*head)->next->length)) {
-			out_of_order++;
-			current_res = *head;
-			*head = (*head)->next;
-			current_res->next = (*head)->next;
-			(*head)->next = current_res;
-		}
-
-		current_res = *head;
-
-		while (current_res->next && current_res->next->next) {
-			if (current_res->next->length > current_res->next->next->length) {
-				out_of_order++;
-				next_res = current_res->next;
-				current_res->next = current_res->next->next;
-				current_res = current_res->next;
-				next_res->next = current_res->next;
-				current_res->next = next_res;
-			} else
-				current_res = current_res->next;
-		}
-	}  // End of out_of_order loop
-
-	return(0);
-}
-
-
-/*
- * sort_by_max_size
- *
- * Sorts nodes on the list by their length.
- * Largest first.
- *
- */
-static int sort_by_max_size(struct pci_resource **head)
-{
-	struct pci_resource *current_res;
-	struct pci_resource *next_res;
-	int out_of_order = 1;
-
-	if (!(*head))
-		return(1);
-
-	if (!((*head)->next))
-		return(0);
-
-	while (out_of_order) {
-		out_of_order = 0;
-
-		// Special case for swapping list head
-		if (((*head)->next) &&
-		    ((*head)->length < (*head)->next->length)) {
-			out_of_order++;
-			current_res = *head;
-			*head = (*head)->next;
-			current_res->next = (*head)->next;
-			(*head)->next = current_res;
-		}
-
-		current_res = *head;
-
-		while (current_res->next && current_res->next->next) {
-			if (current_res->next->length < current_res->next->next->length) {
-				out_of_order++;
-				next_res = current_res->next;
-				current_res->next = current_res->next->next;
-				current_res = current_res->next;
-				next_res->next = current_res->next;
-				current_res->next = next_res;
-			} else
-				current_res = current_res->next;
-		}
-	}  // End of out_of_order loop
-
-	return(0);
-}
-
-/*
- * get_io_resource
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length that is not in the
- * ISA aliasing window.  If it finds a node larger than "size"
- * it will split it up.
- *
- * size must be a power of two.
- */
-struct pci_resource *hotplug_get_io_resource (struct pci_resource **head, u32 size)
-{
-	struct pci_resource *prevnode;
-	struct pci_resource *node;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-
-	if (!(*head))
-		return(NULL);
-
-	if ( hotplug_resource_sort_and_combine(head) )
-		return(NULL);
-
-	if ( sort_by_size(head) )
-		return(NULL);
-
-	for (node = *head; node; node = node->next) {
-		if (node->length < size)
-			continue;
-
-		if (node->base & (size - 1)) {
-			// this one isn't base aligned properly
-			// so we'll make a new entry and split it up
-			temp_dword = (node->base | (size-1)) + 1;
-
-			// Short circuit if adjusted size is too small
-			if ((node->length - (temp_dword - node->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base;
-			split_node->length = temp_dword - node->base;
-			node->base = temp_dword;
-			node->length -= split_node->length;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		} // End of non-aligned base
-
-		// Don't need to check if too small since we already did
-		if (node->length > size) {
-			// this one is longer than we need
-			// so we'll make a new entry and split it up
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base + size;
-			split_node->length = node->length - size;
-			node->length = size;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		}  // End of too big on top end
-
-		// For IO make sure it's not in the ISA aliasing space
-		if (node->base & 0x300L)
-			continue;
-
-		// If we got here, then it is the right size
-		// Now take it out of the list
-		if (*head == node) {
-			*head = node->next;
-		} else {
-			prevnode = *head;
-			while (prevnode->next != node)
-				prevnode = prevnode->next;
-
-			prevnode->next = node->next;
-		}
-		node->next = NULL;
-		// Stop looping
-		break;
-	}
-
-	return(node);
-}
-
-
-/*
- * get_max_resource
- *
- * Gets the largest node that is at least "size" big from the
- * list pointed to by head.  It aligns the node on top and bottom
- * to "size" alignment before returning it.
- */
-struct pci_resource *hotplug_get_max_resource (struct pci_resource **head, u32 size)
-{
-	struct pci_resource *max;
-	struct pci_resource *temp;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-
-	if (!(*head))
-		return(NULL);
-
-	if (hotplug_resource_sort_and_combine(head))
-		return(NULL);
-
-	if (sort_by_max_size(head))
-		return(NULL);
-
-	for (max = *head;max; max = max->next) {
-
-		// If not big enough we could probably just bail, 
-		// instead we'll continue to the next.
-		if (max->length < size)
-			continue;
-
-		if (max->base & (size - 1)) {
-			// this one isn't base aligned properly
-			// so we'll make a new entry and split it up
-			temp_dword = (max->base | (size-1)) + 1;
-
-			// Short circuit if adjusted size is too small
-			if ((max->length - (temp_dword - max->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = max->base;
-			split_node->length = temp_dword - max->base;
-			max->base = temp_dword;
-			max->length -= split_node->length;
-
-			// Put it next in the list
-			split_node->next = max->next;
-			max->next = split_node;
-		}
-
-		if ((max->base + max->length) & (size - 1)) {
-			// this one isn't end aligned properly at the top
-			// so we'll make a new entry and split it up
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-			temp_dword = ((max->base + max->length) & ~(size - 1));
-			split_node->base = temp_dword;
-			split_node->length = max->length + max->base
-					     - split_node->base;
-			max->length -= split_node->length;
-
-			// Put it in the list
-			split_node->next = max->next;
-			max->next = split_node;
-		}
-
-		// Make sure it didn't shrink too much when we aligned it
-		if (max->length < size)
-			continue;
-
-		// Now take it out of the list
-		temp = (struct pci_resource*) *head;
-		if (temp == max) {
-			*head = max->next;
-		} else {
-			while (temp && temp->next != max) {
-				temp = temp->next;
-			}
-
-			temp->next = max->next;
-		}
-
-		max->next = NULL;
-		return(max);
-	}
-
-	// If we get here, we couldn't find one
-	return(NULL);
-}
-
-
-/*
- * get_resource
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length.  If it finds a node
- * larger than "size" it will split it up.
- *
- * size must be a power of two.
- */
-struct pci_resource *hotplug_get_resource (struct pci_resource **head, u32 size)
-{
-	struct pci_resource *prevnode;
-	struct pci_resource *node;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-
-	if (!(*head))
-		return(NULL);
-
-	if ( hotplug_resource_sort_and_combine(head) )
-		return(NULL);
-
-	if ( sort_by_size(head) )
-		return(NULL);
-
-	for (node = *head; node; node = node->next) {
-		dbg(__FUNCTION__": req_size =%x node=%p, base=%x, length=%x\n",
-		    size, node, node->base, node->length);
-		if (node->length < size)
-			continue;
-
-		if (node->base & (size - 1)) {
-			dbg(__FUNCTION__": not aligned\n");
-			// this one isn't base aligned properly
-			// so we'll make a new entry and split it up
-			temp_dword = (node->base | (size-1)) + 1;
-
-			// Short circuit if adjusted size is too small
-			if ((node->length - (temp_dword - node->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base;
-			split_node->length = temp_dword - node->base;
-			node->base = temp_dword;
-			node->length -= split_node->length;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		} // End of non-aligned base
-
-		// Don't need to check if too small since we already did
-		if (node->length > size) {
-			dbg(__FUNCTION__": too big\n");
-			// this one is longer than we need
-			// so we'll make a new entry and split it up
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base + size;
-			split_node->length = node->length - size;
-			node->length = size;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		}  // End of too big on top end
-
-		dbg(__FUNCTION__": got one!!!\n");
-		// If we got here, then it is the right size
-		// Now take it out of the list
-		if (*head == node) {
-			*head = node->next;
-		} else {
-			prevnode = *head;
-			while (prevnode->next != node)
-				prevnode = prevnode->next;
-
-			prevnode->next = node->next;
-		}
-		node->next = NULL;
-		// Stop looping
-		break;
-	}
-	return(node);
-}
-
-/*
- * get_resource_with_base
- *
- * this function 
- * returns the first node of "size" length located at specified base address.
- * If it finds a node larger than "size" it will split it up.
- *
- * size must be a power of two.
- */
-struct pci_resource *hotplug_get_resource_with_base (struct pci_resource **head, u32 base, u32 size)
-{
-	struct pci_resource *prevnode;
-	struct pci_resource *node;
-	struct pci_resource *split_node;
-	u32 temp_dword;
-
-	if (!(*head))
-		return(NULL);
-
-	if ( hotplug_resource_sort_and_combine(head) )
-		return(NULL);
-
-	for (node = *head; node; node = node->next) {
-		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
-		    base, size, node, node->base, node->length);
-		if (node->base > base)
-			continue;
-
-		if ((node->base + node->length) < (base + size))
-			continue;
-
-		if (node->base < base) {
-			dbg(": split 1\n");
-			// this one isn't base aligned properly
-			// so we'll make a new entry and split it up
-			temp_dword = base;
-
-			// Short circuit if adjusted size is too small
-			if ((node->length - (temp_dword - node->base)) < size)
-				continue;
-
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base;
-			split_node->length = temp_dword - node->base;
-			node->base = temp_dword;
-			node->length -= split_node->length;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		}
-
-		dbg(": 2st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
-		    base, size, node, node->base, node->length);
-
-		// Don't need to check if too small since we already did
-		if (node->length >= size) {
-			dbg(": split 2\n");
-			// this one is longer than we need
-			// so we'll make a new entry and split it up
-			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
-			if (!split_node)
-				return(NULL);
-
-			split_node->base = node->base + size;
-			split_node->length = node->length - size;
-			node->length = size;
-
-			// Put it in the list
-			split_node->next = node->next;
-			node->next = split_node;
-		}  // End of too big on top end
-
-		dbg(": got one!!!\n");
-		// If we got here, then it is the right size
-		// Now take it out of the list
-		if (*head == node) {
-			*head = node->next;
-		} else {
-			prevnode = *head;
-			while (prevnode->next != node)
-				prevnode = prevnode->next;
-
-			prevnode->next = node->next;
-		}
-		node->next = NULL;
-		// Stop looping
-		break;
-	}
-	return(node);
-}
-
-/*
- * hotplug_resource_sort_and_combine
- *
- * Sorts all of the nodes in the list in ascending order by
- * their base addresses.  Also does garbage collection by
- * combining adjacent nodes.
- *
- * returns 0 if success
- */
-int hotplug_resource_sort_and_combine(struct pci_resource **head)
-{
-	struct pci_resource *node1;
-	struct pci_resource *node2;
-	int out_of_order = 1;
-
-	dbg(__FUNCTION__": head = %p, *head = %p\n", head, *head);
-
-	if (!(*head))
-		return(1);
-
-	dbg("*head->next = %p\n",(*head)->next);
-
-	if (!(*head)->next)
-		return(0);	/* only one item on the list, already sorted! */
-
-	dbg("*head->base = 0x%x\n",(*head)->base);
-	dbg("*head->next->base = 0x%x\n",(*head)->next->base);
-	while (out_of_order) {
-		out_of_order = 0;
-
-		// Special case for swapping list head
-		if (((*head)->next) &&
-		    ((*head)->base > (*head)->next->base)) {
-			node1 = *head;
-			(*head) = (*head)->next;
-			node1->next = (*head)->next;
-			(*head)->next = node1;
-			out_of_order++;
-		}
-
-		node1 = (*head);
-
-		while (node1->next && node1->next->next) {
-			if (node1->next->base > node1->next->next->base) {
-				out_of_order++;
-				node2 = node1->next;
-				node1->next = node1->next->next;
-				node1 = node1->next;
-				node2->next = node1->next;
-				node1->next = node2;
-			} else
-				node1 = node1->next;
-		}
-	}  // End of out_of_order loop
-
-	node1 = *head;
-
-	while (node1 && node1->next) {
-		if ((node1->base + node1->length) == node1->next->base) {
-			// Combine
-			dbg("8..\n");
-			node1->length += node1->next->length;
-			node2 = node1->next;
-			node1->next = node1->next->next;
-			kfree(node2);
-		} else
-			node1 = node1->next;
-	}
-
-	return(0);
-}
-
-/*
-EXPORT_SYMBOL(hotplug_get_io_resource);
-EXPORT_SYMBOL(hotplug_get_max_resource);
-EXPORT_SYMBOL(hotplug_get_resource);
-EXPORT_SYMBOL(hotplug_resource_sort_and_combine);
-*/
diff -urN linux-2.4.20-pre1/drivers/hotplug/pcihp_acpi_glue.c linux-2.4.20-pre2/drivers/hotplug/pcihp_acpi_glue.c
--- linux-2.4.20-pre1/drivers/hotplug/pcihp_acpi_glue.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/hotplug/pcihp_acpi_glue.c	Wed Dec 31 16:00:00 1969
@@ -1,757 +0,0 @@
-/*
- * ACPI PCI HotPlug glue functions to ACPI CA subsystem
- *
- * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <t-kouchi@cq.jp.nec.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include "pcihp_acpi.h"
-
-/*
- * TODO:
- * resource management
- * irq related interface? (_PRT)
- * consider locking
- */
-
-static LIST_HEAD(bridge_list);
-
-static int debug = 1;			/* XXX set 0 after debug */
-#define MY_NAME "pcihp_acpi_glue"
-
-static void handle_hotplug_event (acpi_handle, u32, void *);
-
-/*
- * initialization & terminatation routines
- */
-
-/*
- * Ejectable slot satisfies at least these conditions:
- *  1. has _ADR method
- *  2. has _STA method
- *  3. has _EJ0 method
- *
- * optionally
- *  1. has _PS0 method
- *  2. has _PS3 method
- *  3. TBD...
- */
-
-/* callback routine to check the existence of ejectable slots */
-static acpi_status
-is_ejectable_slot (acpi_handle handle, u32 lvl,	void *context, void **rv)
-{
-	acpi_status status;
-	acpi_handle tmp;
-	int *count = (int *)context;
-
-	status = acpi_get_handle(handle, "_ADR", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	status = acpi_get_handle(handle, "_STA", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	status = acpi_get_handle(handle, "_EJ0", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	(*count)++;
-
-	/* only one ejectable slot is enough */
-	return AE_CTRL_TERMINATE;
-}
-
-
-/* callback routine to register each ACPI PCI slot object */
-static acpi_status
-register_slot (acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	struct pcihp_acpi_bridge *bridge = (struct pcihp_acpi_bridge *)context;
-	struct pcihp_acpi_slot *slot, *newslot;
-	acpi_handle tmp;
-	acpi_status status = AE_OK;
-	static int num_slots = 0;	/* XXX */
-	unsigned long adr, sun, sta;
-
-	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
-
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
-	}
-
-	status = acpi_get_handle(handle, "_EJ0", &tmp);
-
-	if (ACPI_FAILURE(status)) {
-		dbg("This slot doesn't have _EJ0");
-		//return AE_OK;
-	}
-
-	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-
-	if (ACPI_FAILURE(status)) {
-		dbg("This slot doesn't have _STA");
-		//return AE_OK;
-	}
-
-	newslot = kmalloc(sizeof(struct pcihp_acpi_slot), GFP_KERNEL);
-	if (!newslot) {
-		return AE_NO_MEMORY;
-	}
-
-	memset(newslot, 0, sizeof(struct pcihp_acpi_slot));
-
-	INIT_LIST_HEAD(&newslot->sibling);
-	newslot->bridge = bridge;
-	newslot->handle = handle;
-	newslot->device = (adr >> 16) & 0xffff;
-	newslot->function = adr & 0xffff;
-	newslot->status = sta;
-	newslot->sun = -1;
-	newslot->flags = SLOT_HAS_EJ0;
-	newslot->id = num_slots++;
-	bridge->nr_slots++;
-
-	dbg("new slot id=%d device=0x%d function=0x%x", newslot->id, newslot->device, newslot->function);
-
-	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
-	if (ACPI_SUCCESS(status)) {
-		newslot->sun = sun;
-	}
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) {
-		newslot->flags |= SLOT_HAS_PS0;
-	}
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) {
-		newslot->flags |= SLOT_HAS_PS3;
-	}
-
-	/* search for objects that share the same slot */
-	for (slot = bridge->slots; slot; slot = slot->next)
-		if (slot->device == newslot->device) {
-			dbg("found a sibling slot!");
-			list_add(&slot->sibling, &newslot->sibling);
-			newslot->id = slot->id;
-			num_slots --;
-			bridge->nr_slots --;
-			break;
-		}
-
-	/* link myself to bridge's slot list */
-	newslot->next = bridge->slots;
-	bridge->slots = newslot;
-
-	return AE_OK;
-}
-
-/* see if it's worth managing this brige */
-static int
-detect_ejectable_slots (acpi_handle *root)
-{
-	acpi_status status;
-	int count;
-
-	count = 0;
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root, ACPI_UINT32_MAX,
-				     is_ejectable_slot, (void *)&count, NULL);
-
-	dbg("%s: count=%d", __FUNCTION__, count);
-	return count;
-}
-
-
-/*
- * push one resource to resource list
- *
- * TBD: use hotplug_resource_sort_and_combine
- * TBD: 64bit resource handling (is it really used?)
- */
-static void
-push_resource (u32 base, u32 length, struct pci_resource **resource)
-{
-	struct pci_resource *resp, *newres;
-	int coalesced = 0;
-
-	if (length == 0) {
-		dbg("zero sized resource. ignored.");
-		return;
-	}
-
-	for (resp = *resource; resp; resp = resp->next) {
-
-		/* coalesce contiguous region */
-
-		if (resp->base + resp->length == base) {
-			resp->length += length;
-			coalesced = 1;
-			break;
-		}
-	}
-
-	if (!coalesced) {
-		newres = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-		if (!newres) {
-			/* TBD panic? */
-			return;
-		}
-		newres->base = base;
-		newres->length = length;
-		newres->next = (*resource);
-		*resource = newres;
-	}
-}
-
-
-/* decode ACPI _CRS data and convert into our internal resource list */
-static void
-decode_acpi_resource (acpi_resource *resource, struct pcihp_acpi_bridge *bridge)
-{
-	acpi_resource_address16 *address16_data;
-	acpi_resource_address32 *address32_data;
-	//acpi_resource_address64 *address64_data;
-
-	u32 resource_type, producer_consumer, min_address_range, max_address_range, address_length;
-	u16 cache_attribute = 0;
-
-	int done = 0, found;
-
-	/* shut up gcc */
-	resource_type = producer_consumer = min_address_range = max_address_range = address_length = 0;
-
-	while (!done) {
-		found = 0;
-
-		switch (resource->id) {
-		case ACPI_RSTYPE_ADDRESS16:
-			address16_data = (acpi_resource_address16 *)&resource->data;
-			resource_type = address16_data->resource_type;
-			producer_consumer = address16_data->producer_consumer;
-			min_address_range = address16_data->min_address_range;
-			max_address_range = address16_data->max_address_range;
-			address_length = address16_data->address_length;
-			if (resource_type == ACPI_MEMORY_RANGE)
-				cache_attribute = address16_data->attribute.memory.cache_attribute;
-			found = 1;
-			break;
-
-		case ACPI_RSTYPE_ADDRESS32:
-			address32_data = (acpi_resource_address32 *)&resource->data;
-			resource_type = address32_data->resource_type;
-			producer_consumer = address32_data->producer_consumer;
-			min_address_range = address32_data->min_address_range;
-			max_address_range = address32_data->max_address_range;
-			address_length = address32_data->address_length;
-			if (resource_type == ACPI_MEMORY_RANGE)
-				cache_attribute = address32_data->attribute.memory.cache_attribute;
-			found = 1;
-			break;
-/*
-		case ACPI_RSTYPE_ADDRESS64:
-			address64_data = (acpi_resource_address64 *)&resource->data;
-			resource_type = address64_data->resource_type;
-			break;
-*/
-		case ACPI_RSTYPE_END_TAG:
-			done = 1;
-			break;
-
-		default:
-			/* ignore */
-			break;
-		}
-
-		resource = (acpi_resource *)((char*)resource + resource->length);
-		if (found && producer_consumer == ACPI_PRODUCER) {
-			switch (resource_type) {
-			case ACPI_MEMORY_RANGE:
-				if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
-					dbg("resource type: prefetchable memory 0x%x - 0x%x", min_address_range, max_address_range);
-					push_resource(min_address_range,
-						      address_length,
-						      &bridge->free_prefetch);
-				} else {
-					dbg("resource type: memory 0x%x - 0x%x", min_address_range, max_address_range);
-					push_resource(min_address_range,
-						      address_length,
-						      &bridge->free_mem);
-				}
-				break;
-			case ACPI_IO_RANGE:
-				dbg("resource type: io 0x%x - 0x%x", min_address_range, max_address_range);
-				push_resource(min_address_range,
-					      address_length,
-					      &bridge->free_io);
-				break;
-			case ACPI_BUS_NUMBER_RANGE:
-				dbg("resource type: bus number %d - %d", min_address_range, max_address_range);
-				push_resource(min_address_range,
-					      address_length,
-					      &bridge->free_bus);
-				break;
-			default:
-				/* invalid type */
-				break;
-			}
-		}
-	}
-}
-
-
-/* allocate and initialize bridge data structure */
-static int add_bridge (acpi_handle *handle)
-{
-	struct pcihp_acpi_bridge *bridge;
- 	acpi_status status;
-	acpi_buffer buffer;
-	unsigned long tmp;
-	acpi_handle dummy_handle;
-	int sta = -1;
-
-	status = acpi_get_handle(handle, "_STA", &dummy_handle);
-	if (ACPI_SUCCESS(status)) {
-		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
-		if (ACPI_FAILURE(status)) {
-			dbg("%s: _STA evaluation failure", __FUNCTION__);
-			return 0;
-		}
-		sta = tmp;
-	}
-
-	if (sta >= 0 && !(sta & ACPI_STA_PRESENT))
-		/* don't register this object */
-		return 0;
-
-	dbg("%s: _STA: 0x%x", __FUNCTION__, (unsigned int)sta);
-
-	/* check if this bridge has ejectable slots */
-
-	detect_ejectable_slots(handle);
-	//if (detect_ejectable_slots(handle) == 0)
-	//return 0;
-
-	/* allocate per-bridge data structure and fill in */
-
-	bridge = kmalloc(sizeof(struct pcihp_acpi_bridge), GFP_KERNEL);
-	if (bridge == NULL)
-		return -ENOMEM;
-
-	memset(bridge, 0, sizeof(struct pcihp_acpi_bridge));
-
-	if (sta >= 0)
-		bridge->flags |= BRIDGE_HAS_STA;
-
-	/* get PCI segment number */
-	status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
-
-	if (ACPI_SUCCESS(status)) {
-		bridge->seg = tmp;
-	} else {
-		bridge->seg = 0;
-	}
-
-	/* get PCI bus number */
-	status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
-
-	if (ACPI_SUCCESS(status)) {
-		bridge->bus = tmp;
-	} else {
-		bridge->bus = 0;
-	}
-
-	/* to be overridden when we decode _CRS	*/
-	bridge->sub = bridge->bus;
-
-	/* register all slot objects under this bridge */
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX,
-				     register_slot, bridge, NULL);
-
-	/* decode resources */
-	buffer.length = 0;
-	buffer.pointer = NULL;
-
-	
-	/* TBD use new ACPI_ALLOCATE_BUFFER */
-	status = acpi_get_current_resources(handle, &buffer);
-	if (status != AE_BUFFER_OVERFLOW) {
-		return -1;
-	}
-
-	buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
-	if (!buffer.pointer) {
-		return -1;
-	}
-
-	status = acpi_get_current_resources(handle, &buffer);
-	if (ACPI_FAILURE(status)) {
-		return -1;
-	}
-
-	decode_acpi_resource(buffer.pointer, bridge);
-
-	/* TBD decode _HPP (hot plug parameters) */
-	// decode_hpp(bridge);
-
-	kfree(buffer.pointer);
-
-	/* check already allocated resources */
-	/* TBD */
-
-	/* install notify handler */
-	dbg("installing notify handler");
-	status = acpi_install_notify_handler(handle,
-					     ACPI_SYSTEM_NOTIFY,
-					     handle_hotplug_event, NULL);
-
-	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
-	}
-
-	list_add(&bridge->list, &bridge_list);
-
-	return 0;
-}
-
-
-/* callback routine to enumerate all the bridges in ACPI namespace */
-static acpi_status
-check_pci_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	acpi_status status;
-	acpi_device_info info;
-	char objname[5];
-	acpi_buffer buffer = { sizeof(objname), objname };
-
-	status = acpi_get_object_info(handle, &info);
-	if (ACPI_FAILURE(status)) {
-		dbg("%s: failed to get bridge information", __FUNCTION__);
-		return AE_OK;		/* continue */
-	}
-
-	info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
-
-	if (strcmp(info.hardware_id, ACPI_PCI_ROOT_HID) == 0) {
-
-		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-		dbg("%s: found PCI root bridge[%s]", __FUNCTION__, objname);
-
-		add_bridge(handle);
-	}
-	return AE_OK;
-}
-
-
-/* interrupt handler */
-static void handle_hotplug_event (acpi_handle handle, u32 type, void *data)
-{
-	char objname[5];
-	acpi_buffer buffer = { sizeof(objname), objname };
-
-	acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* hot insertion/surprise removal */
-		/* TBD */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		/* TBD */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		/* eject button pushed */
-		/* TBD */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x", type);
-		break;
-	}
-}
-
-
-/*
- * external interfaces
- */
-
-int pcihp_acpi_glue_init (void)
-{
-	acpi_status status;
-
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-				     ACPI_UINT32_MAX, check_pci_bridge,
-				     NULL, NULL);
-
-	if (ACPI_FAILURE(status)) {
-		dbg("%s: acpi_walk_namespace() failed", __FUNCTION__);
-	}
-
-	return 0;
-}
-
-static void free_all_resources (struct pcihp_acpi_bridge *bridge)
-{
-	struct pci_resource *res, *next;;
-
-	for (res = bridge->free_io; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-
-	for (res = bridge->free_mem; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-
-	for (res = bridge->free_prefetch; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-
-	for (res = bridge->free_bus; res; ) {
-		next = res->next;
-		kfree(res);
-		res = next;
-	}
-}
-
-
-void pcihp_acpi_glue_exit (void)
-{
-	struct list_head *node;
-	struct pcihp_acpi_bridge *bridge;
-	struct pcihp_acpi_slot *slot, *next;
-
-	list_for_each(node, &bridge_list) {
-		bridge = (struct pcihp_acpi_bridge *)node;
-		slot = bridge->slots;
-		while (slot) {
-			next = slot->next;
-			kfree(slot);
-			slot = next;
-		}
-		free_all_resources(bridge);
-		kfree(bridge);
-	}
-}
-
-
-int pcihp_acpi_get_num_slots (void)
-{
-	struct list_head *node;
-	struct pcihp_acpi_bridge *bridge;
-	int num_slots;
-
-	num_slots = 0;
-
-	list_for_each(node, &bridge_list) {
-		bridge = (struct pcihp_acpi_bridge *)node;
-		dbg("Bus:%d num_slots:%d", bridge->bus, bridge->nr_slots);
-		num_slots += bridge->nr_slots;
-	}
-
-	dbg("num_slots = %d", num_slots);
-	return num_slots;
-}
-
-
-/*  TBD: improve performance */
-struct pcihp_acpi_slot *get_slot_from_id (int id)
-{
-	struct list_head *node;
-	struct pcihp_acpi_bridge *bridge;
-	struct pcihp_acpi_slot *slot;
-
-	list_for_each(node, &bridge_list) {
-		bridge = (struct pcihp_acpi_bridge *)node;
-		for (slot = bridge->slots; slot; slot = slot->next)
-			if (slot->id == id)
-				return slot;
-	}
-
-	/* should never happen! */
-	dbg("%s: no object for id %d",__FUNCTION__, id);
-	return 0;
-}
-
-
-/* power on slot */
-int pcihp_acpi_enable_slot (struct pcihp_acpi_slot *slot)
-{
-	acpi_status status;
-
-	if (slot->flags & SLOT_HAS_PS0) {
-		dbg("%s: powering on bus%d/dev%d.", __FUNCTION__,
-		    slot->bridge->bus, slot->device);
-		status = acpi_evaluate_object(slot->handle, "_PS0", NULL, NULL);
-		if (ACPI_FAILURE(status)) {
-			warn("%s: powering on bus%d/dev%d failed",
-			     __FUNCTION__, slot->bridge->bus, slot->device);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-/* power off slot */
-int pcihp_acpi_disable_slot (struct pcihp_acpi_slot *slot)
-{
-	acpi_status status;
-
-	if (slot->flags & SLOT_HAS_PS3) {
-		dbg("%s: powering off bus%d/dev%d.", __FUNCTION__,
-		    slot->bridge->bus, slot->device);
-		status = acpi_evaluate_object(slot->handle, "_PS3", NULL, NULL);
-		if (ACPI_FAILURE(status)) {
-			warn("%s: _PS3 on bus%d/dev%d failed",
-			     __FUNCTION__, slot->bridge->bus, slot->device);
-			return -1;
-		}
-	}
-
-	if (slot->flags & SLOT_HAS_EJ0) {
-		dbg("%s: eject bus%d/dev%d.", __FUNCTION__,
-		    slot->bridge->bus, slot->device);
-		status = acpi_evaluate_object(slot->handle, "_EJ0", NULL, NULL);
-		if (ACPI_FAILURE(status)) {
-			warn("%s: _EJ0 bus%d/dev%d failed",
-			     __FUNCTION__, slot->bridge->bus, slot->device);
-			return -1;
-		}
-	}
-
-	/* TBD
-	 * evaluate _STA to check if state is successfully changed
-	 * and update status
-	 */
-
-	return 0;
-}
-
-
-static unsigned int get_slot_status(struct pcihp_acpi_slot *slot)
-{
-	acpi_status status;
-	unsigned long sta;
-
-	status = acpi_evaluate_integer(slot->handle, "_STA", NULL, &sta);
-
-	if (ACPI_FAILURE(status)) {
-		err("%s: _STA evaluation failed", __FUNCTION__);
-		return 0;
-	}
-
-	return (int)sta;
-}
-
-
-/*
- * slot enabled:  1
- * slot disabled: 0
- */
-u8 pcihp_acpi_get_power_status (struct pcihp_acpi_slot *slot)
-{
-	unsigned int sta;
-
-	/* TBD
-	 * . guarantee check _STA on function# 0
-	 * . check configuration space before _STA?
-	 */
-
-	sta = get_slot_status(slot);
-
-	return (sta & ACPI_STA_ENABLED) ? 1 : 0;
-}
-
-
-/* XXX this function is not used */
-/* 
- * attention LED ON: 1
- *              OFF: 0
- */
-u8 pcihp_acpi_get_attention_status (struct pcihp_acpi_slot *slot)
-{
-	/* TBD
-	 * no direct attention led status information via ACPI
-	 */
-
-	return 0;
-}
-
-
-/*
- * latch closed:  1
- * latch   open:  0
- */
-u8 pcihp_acpi_get_latch_status (struct pcihp_acpi_slot *slot)
-{
-	unsigned int sta;
-
-	/* TBD
-	 * no direct latch information via ACPI
-	 */
-
-	sta = get_slot_status(slot);
-
-	return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;
-}
-
-
-/*
- * adapter presence : 2
- *          absence : 0
- */
-u8 pcihp_acpi_get_adapter_status (struct pcihp_acpi_slot *slot)
-{
-	unsigned int sta;
-
-	/* TBD
-	 * is this information correct?
-	 */
-
-	sta = get_slot_status(slot);
-
-	return (sta == 0) ? 0 : 2;
-}
diff -urN linux-2.4.20-pre1/drivers/ide/Config.in linux-2.4.20-pre2/drivers/ide/Config.in
--- linux-2.4.20-pre1/drivers/ide/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/ide/Config.in	Mon Aug 12 16:34:16 2002
@@ -210,8 +210,8 @@
    define_bool CONFIG_BLK_DEV_IDE_MODES n
 fi
 
-dep_tristate 'Support for IDE Raid controllers' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
-dep_tristate '   Support Promise software RAID (Fasttrak(tm))' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
-dep_tristate '   Highpoint 370 software RAID' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
+dep_tristate '   Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+dep_tristate '   Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 
 endmenu
diff -urN linux-2.4.20-pre1/drivers/ide/ide-disk.c linux-2.4.20-pre2/drivers/ide/ide-disk.c
--- linux-2.4.20-pre1/drivers/ide/ide-disk.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/ide/ide-disk.c	Mon Aug 12 16:34:16 2002
@@ -29,6 +29,7 @@
  * Version 1.10		request queue changes, Ultra DMA 100
  * Version 1.11		added 48-bit lba
  * Version 1.12		adding taskfile io access method
+ *			Highmem I/O support, Jens Axboe <axboe@suse.de>
  */
 
 #define IDEDISK_VERSION	"1.12"
@@ -158,7 +159,9 @@
 	byte stat;
 	int i;
 	unsigned int msect, nsect;
+	unsigned long flags;
 	struct request *rq;
+	char *to;
 
 	/* new way for dealing with premature shared PCI interrupts */
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
@@ -169,8 +172,8 @@
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
 		return ide_started;
 	}
+
 	msect = drive->mult_count;
-	
 read_next:
 	rq = HWGROUP(drive)->rq;
 	if (msect) {
@@ -179,14 +182,15 @@
 		msect -= nsect;
 	} else
 		nsect = 1;
-	idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+	to = ide_map_buffer(rq, &flags);
+	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
 #ifdef DEBUG
 	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
 		drive->name, rq->sector, rq->sector+nsect-1,
 		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
 #endif
+	ide_unmap_buffer(to, &flags);
 	rq->sector += nsect;
-	rq->buffer += nsect<<9;
 	rq->errors = 0;
 	i = (rq->nr_sectors -= nsect);
 	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
@@ -220,14 +224,16 @@
 #endif
 		if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) {
 			rq->sector++;
-			rq->buffer += 512;
 			rq->errors = 0;
 			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
 			if (((long)rq->current_nr_sectors) <= 0)
 				ide_end_request(1, hwgroup);
 			if (i > 0) {
-				idedisk_output_data (drive, rq->buffer, SECTOR_WORDS);
+				unsigned long flags;
+				char *to = ide_map_buffer(rq, &flags);
+				idedisk_output_data (drive, to, SECTOR_WORDS);
+				ide_unmap_buffer(to, &flags);
 				ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
                                 return ide_started;
 			}
@@ -257,14 +263,14 @@
   	do {
   		char *buffer;
   		int nsect = rq->current_nr_sectors;
- 
+		unsigned long flags;
+
 		if (nsect > mcount)
 			nsect = mcount;
 		mcount -= nsect;
-		buffer = rq->buffer;
 
+		buffer = ide_map_buffer(rq, &flags);
 		rq->sector += nsect;
-		rq->buffer += nsect << 9;
 		rq->nr_sectors -= nsect;
 		rq->current_nr_sectors -= nsect;
 
@@ -278,7 +284,7 @@
 			} else {
 				rq->bh = bh;
 				rq->current_nr_sectors = bh->b_size >> 9;
-				rq->buffer             = bh->b_data;
+				rq->hard_cur_sectors = rq->current_nr_sectors;
 			}
 		}
 
@@ -287,6 +293,7 @@
 		 * re-entering us on the last transfer.
 		 */
 		idedisk_output_data(drive, buffer, nsect<<7);
+		ide_unmap_buffer(buffer, &flags);
 	} while (mcount);
 
         return 0;
@@ -695,8 +702,11 @@
 				return ide_stopped;
 			}
 		} else {
+			unsigned long flags;
+			char *buffer = ide_map_buffer(rq, &flags);
 			ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
-			idedisk_output_data(drive, rq->buffer, SECTOR_WORDS);
+			idedisk_output_data(drive, buffer, SECTOR_WORDS);
+			ide_unmap_buffer(buffer, &flags);
 		}
 		return ide_started;
 	}
diff -urN linux-2.4.20-pre1/drivers/ide/ide-dma.c linux-2.4.20-pre2/drivers/ide/ide-dma.c
--- linux-2.4.20-pre1/drivers/ide/ide-dma.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/ide/ide-dma.c	Mon Aug 12 16:34:16 2002
@@ -252,33 +252,53 @@
 {
 	struct buffer_head *bh;
 	struct scatterlist *sg = hwif->sg_table;
+	unsigned long lastdataend = ~0UL;
 	int nents = 0;
 
 	if (hwif->sg_dma_active)
 		BUG();
-		
+
 	if (rq->cmd == READ)
 		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
 	else
 		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+
 	bh = rq->bh;
 	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
+		struct scatterlist *sge;
+
+		/*
+		 * continue segment from before?
+		 */
+		if (bh_phys(bh) == lastdataend) {
+			sg[nents - 1].length += bh->b_size;
+			lastdataend += bh->b_size;
+			continue;
+		}
 
+		/*
+		 * start new segment
+		 */
 		if (nents >= PRD_ENTRIES)
 			return 0;
 
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *) bh->b_data)
-				break;
-			size += bh->b_size;
+		sge = &sg[nents];
+		memset(sge, 0, sizeof(*sge));
+
+		if (bh->b_page) {
+			sge->page = bh->b_page;
+			sge->offset = bh_offset(bh);
+		} else {
+			if (((unsigned long) bh->b_data) < PAGE_SIZE)
+				BUG();
+
+			sge->address = bh->b_data;
 		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
+
+		sge->length = bh->b_size;
+		lastdataend = bh_phys(bh) + bh->b_size;
 		nents++;
-	} while (bh != NULL);
+	} while ((bh = bh->b_reqnext) != NULL);
 
 	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
@@ -340,7 +360,7 @@
 		return 0;
 
 	sg = HWIF(drive)->sg_table;
-	while (i && sg_dma_len(sg)) {
+	while (i) {
 		u32 cur_addr;
 		u32 cur_len;
 
@@ -354,36 +374,35 @@
 		 */
 
 		while (cur_len) {
-			if (count++ >= PRD_ENTRIES) {
-				printk("%s: DMA table too small\n", drive->name);
-				goto use_pio_instead;
-			} else {
-				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
-
-				if (bcount > cur_len)
-					bcount = cur_len;
-				*table++ = cpu_to_le32(cur_addr);
-				xcount = bcount & 0xffff;
-				if (is_trm290_chipset)
-					xcount = ((xcount >> 2) - 1) << 16;
-				if (xcount == 0x0000) {
-					/* 
-					 * Most chipsets correctly interpret a length of 0x0000 as 64KB,
-					 * but at least one (e.g. CS5530) misinterprets it as zero (!).
-					 * So here we break the 64KB entry into two 32KB entries instead.
-					 */
-					if (count++ >= PRD_ENTRIES) {
-						printk("%s: DMA table too small\n", drive->name);
-						goto use_pio_instead;
-					}
-					*table++ = cpu_to_le32(0x8000);
-					*table++ = cpu_to_le32(cur_addr + 0x8000);
-					xcount = 0x8000;
-				}
-				*table++ = cpu_to_le32(xcount);
-				cur_addr += bcount;
-				cur_len -= bcount;
+			u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
+			
+			if (count++ >= PRD_ENTRIES)
+				BUG();
+
+			if (bcount > cur_len)
+				bcount = cur_len;
+			*table++ = cpu_to_le32(cur_addr);
+			xcount = bcount & 0xffff;
+			if (is_trm290_chipset)
+				xcount = ((xcount >> 2) - 1) << 16;
+			if (xcount == 0x0000) {
+				/* 
+				 * Most chipsets correctly interpret a length
+				 * of 0x0000 as 64KB, but at least one
+				 * (e.g. CS5530) misinterprets it as zero (!).
+				 * So here we break the 64KB entry into two
+				 * 32KB entries instead.
+				 */
+				if (count++ >= PRD_ENTRIES)
+					goto use_pio_instead;
+
+				*table++ = cpu_to_le32(0x8000);
+				*table++ = cpu_to_le32(cur_addr + 0x8000);
+				xcount = 0x8000;
 			}
+			*table++ = cpu_to_le32(xcount);
+			cur_addr += bcount;
+			cur_len -= bcount;
 		}
 
 		sg++;
@@ -584,6 +603,23 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 
+static inline void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	dma64_addr_t addr = BLK_BOUNCE_HIGH;
+
+	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
+		return;
+
+	if (on && drive->media == ide_disk) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
 /*
  * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
  *
@@ -606,18 +642,20 @@
 	ide_hwif_t *hwif		= HWIF(drive);
 	unsigned long dma_base		= hwif->dma_base;
 	byte unit			= (drive->select.b.unit & 0x01);
-	unsigned int count, reading	= 0;
+	unsigned int count, reading = 0, set_high = 1;
 	byte dma_stat;
 
 	switch (func) {
 		case ide_dma_off:
 			printk("%s: DMA disabled\n", drive->name);
 		case ide_dma_off_quietly:
+			set_high = 0;
 			outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
 		case ide_dma_on:
 			drive->using_dma = (func == ide_dma_on);
 			if (drive->using_dma)
 				outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+			ide_toggle_bounce(drive, set_high);
 			return 0;
 		case ide_dma_check:
 			return config_drive_for_dma (drive);
@@ -759,8 +797,8 @@
 	request_region(dma_base, num_ports, hwif->name);
 	hwif->dma_base = dma_base;
 	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
-						  PRD_ENTRIES * PRD_BYTES,
-						  &hwif->dmatable_dma);
+						    PRD_ENTRIES * PRD_BYTES,
+						    &hwif->dmatable_dma);
 	if (hwif->dmatable_cpu == NULL)
 		goto dma_alloc_failure;
 
diff -urN linux-2.4.20-pre1/drivers/ide/ide-geometry.c linux-2.4.20-pre2/drivers/ide/ide-geometry.c
--- linux-2.4.20-pre1/drivers/ide/ide-geometry.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/ide/ide-geometry.c	Mon Aug 12 16:34:16 2002
@@ -32,7 +32,7 @@
  * for us during initialization.  I have the necessary docs -- any takers?  -ml
  */
 /*
- * I did this, but it doesnt work - there is no reasonable way to find the
+ * I did this, but it doesn't work - there is no reasonable way to find the
  * correspondence between the BIOS numbering of the disks and the Linux
  * numbering. -aeb
  *
diff -urN linux-2.4.20-pre1/drivers/ide/ide.c linux-2.4.20-pre2/drivers/ide/ide.c
--- linux-2.4.20-pre1/drivers/ide/ide.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/ide/ide.c	Mon Aug 12 16:34:16 2002
@@ -3418,7 +3418,7 @@
 		const char *ide_words[] = {
 			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
 			"minus8", "minus9", "minus10",
-			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
+			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "nohighio", NULL };
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -3437,6 +3437,10 @@
 		}
 
 		switch (i) {
+			case -19: /* nohighio */
+				hwif->no_highio = 1;
+				printk("%s: disabled high i/o capability\n", hwif->name);
+				goto done;
 #ifdef CONFIG_BLK_DEV_PDC4030
 			case -18: /* "dc4030" */
 			{
diff -urN linux-2.4.20-pre1/drivers/ieee1394/nodemgr.c linux-2.4.20-pre2/drivers/ieee1394/nodemgr.c
--- linux-2.4.20-pre1/drivers/ieee1394/nodemgr.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/ieee1394/nodemgr.c	Mon Aug 12 16:34:16 2002
@@ -1300,10 +1300,12 @@
 	}
 
 	if (hi != NULL)
+	{
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-	HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name);
+		HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name);
 #endif
 		up(&hi->reset_sem);
+	}
 	else
 		HPSB_ERR ("NodeMgr: could not process reset of non-existent host");
 
diff -urN linux-2.4.20-pre1/drivers/isdn/Config.in linux-2.4.20-pre2/drivers/isdn/Config.in
--- linux-2.4.20-pre1/drivers/isdn/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/isdn/Config.in	Mon Aug 12 16:34:16 2002
@@ -47,15 +47,15 @@
    int  '  Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
    comment '  HiSax supported cards'
    if [ "$CONFIG_ISA" != "n" ]; then
-   bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0
-   bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
-   bool '  AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
-   bool '  ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
-   bool '  ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
-   bool '  TELEINT cards' CONFIG_HISAX_TELEINT
-   bool '  HFC-S based cards' CONFIG_HISAX_HFCS
-   bool '  USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
-   bool '  MIC card' CONFIG_HISAX_MIC
+      bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0
+      bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+      bool '  AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+      bool '  ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+      bool '  ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
+      bool '  TELEINT cards' CONFIG_HISAX_TELEINT
+      bool '  HFC-S based cards' CONFIG_HISAX_HFCS
+      bool '  USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+      bool '  MIC card' CONFIG_HISAX_MIC
       bool '  Siemens I-Surf card' CONFIG_HISAX_ISURF
       bool '  HST Saphir card' CONFIG_HISAX_HSTSAPHIR
    fi
diff -urN linux-2.4.20-pre1/drivers/isdn/hisax/st5481.h linux-2.4.20-pre2/drivers/isdn/hisax/st5481.h
--- linux-2.4.20-pre1/drivers/isdn/hisax/st5481.h	Sun Sep 30 12:26:06 2001
+++ linux-2.4.20-pre2/drivers/isdn/hisax/st5481.h	Mon Aug 12 16:34:16 2002
@@ -309,7 +309,7 @@
 typedef void (*ctrl_complete_t)(void *);
 
 typedef struct ctrl_msg {
-	devrequest dr;
+	struct usb_ctrlrequest dr;
 	ctrl_complete_t complete;
 	void *context;
 } ctrl_msg; 
@@ -478,7 +478,7 @@
   if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
 
 static void __attribute__((unused))
-dump_iso_packet(const char *name,urb_t *urb)
+dump_iso_packet(const char *name,struct urb *urb)
 {
 	int i,j;
 	int len,ofs;
diff -urN linux-2.4.20-pre1/drivers/isdn/hisax/st5481_d.c linux-2.4.20-pre2/drivers/isdn/hisax/st5481_d.c
--- linux-2.4.20-pre1/drivers/isdn/hisax/st5481_d.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre2/drivers/isdn/hisax/st5481_d.c	Mon Aug 12 16:34:16 2002
@@ -297,7 +297,7 @@
 	unsigned int num_packets, packet_offset;
 	int len, buf_size, bytes_sent;
 	struct sk_buff *skb;
-	iso_packet_descriptor_t *desc;
+	struct iso_packet_descriptor *desc;
 
 	if (d_out->fsm.state != ST_DOUT_NORMAL)
 		return;
diff -urN linux-2.4.20-pre1/drivers/isdn/hisax/st5481_usb.c linux-2.4.20-pre2/drivers/isdn/hisax/st5481_usb.c
--- linux-2.4.20-pre1/drivers/isdn/hisax/st5481_usb.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.20-pre2/drivers/isdn/hisax/st5481_usb.c	Mon Aug 12 16:34:16 2002
@@ -235,7 +235,7 @@
 	struct usb_interface_descriptor *altsetting;
 	struct usb_endpoint_descriptor *endpoint;
 	int status;
-	urb_t *urb;
+	struct urb *urb;
 	u_char *buf;
 	
 	DBG(1,"");
@@ -560,7 +560,8 @@
  */
 int st5481_isoc_flatten(struct urb *urb)
 {
-	piso_packet_descriptor_t pipd,pend;
+	struct iso_packet_descriptor *pipd;
+	struct iso_packet_descriptor *pend;
 	unsigned char *src,*dst;
 	unsigned int len;
 	
diff -urN linux-2.4.20-pre1/drivers/isdn/isdn_ppp.c linux-2.4.20-pre2/drivers/isdn/isdn_ppp.c
--- linux-2.4.20-pre1/drivers/isdn/isdn_ppp.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/isdn/isdn_ppp.c	Mon Aug 12 16:34:16 2002
@@ -2230,7 +2230,7 @@
 				return;
 			}
 			rs->state = CCPResetSentReq;
-			/* We always expect an Ack if the decompressor doesnt
+			/* We always expect an Ack if the decompressor doesn't
 			   know	better */
 			rs->expra = 1;
 			rs->dlen = 0;
diff -urN linux-2.4.20-pre1/drivers/isdn/pcbit/drv.c linux-2.4.20-pre2/drivers/isdn/pcbit/drv.c
--- linux-2.4.20-pre1/drivers/isdn/pcbit/drv.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.20-pre2/drivers/isdn/pcbit/drv.c	Mon Aug 12 16:34:16 2002
@@ -430,7 +430,7 @@
 	switch(dev->l2_state) {
 	case L2_LWMODE:
 		/* check (size <= rdp_size); write buf into board */
-		if (len > BANK4 + 1)
+		if (len < 0 || len > BANK4 + 1)
 		{
 			printk("pcbit_writecmd: invalid length %d\n", len);
 			return -EINVAL;
diff -urN linux-2.4.20-pre1/drivers/media/radio/Config.in linux-2.4.20-pre2/drivers/media/radio/Config.in
--- linux-2.4.20-pre1/drivers/media/radio/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/media/radio/Config.in	Mon Aug 12 16:34:16 2002
@@ -5,52 +5,52 @@
 comment 'Radio Adapters'
 
 if [ "$CONFIG_ISA" = "y" ]; then
-dep_tristate '  ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
-dep_tristate '  AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
-   hex '  RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f
-fi
-dep_tristate '  AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then
-   hex '    RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c
-fi
-dep_tristate '  Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
-   hex '    Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
-fi
-dep_tristate '  GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
-   hex '    GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
-fi
+   dep_tristate '  ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
+   dep_tristate '  AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
+      hex '  RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f
+   fi
+   dep_tristate '  AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then
+      hex '    RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c
+   fi
+   dep_tristate '  Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
+      hex '    Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
+  fi
+   dep_tristate '  GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
+      hex '    GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
+   fi
 fi
 dep_tristate '  GemTek PCI Radio Card support' CONFIG_RADIO_GEMTEK_PCI $CONFIG_VIDEO_DEV $CONFIG_PCI
 dep_tristate '  Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV
 dep_tristate '  Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
 dep_tristate '  miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER
 if [ "$CONFIG_ISA" = "y" ]; then
-dep_tristate '    miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)' CONFIG_RADIO_MIROPCM20_RDS $CONFIG_RADIO_MIROPCM20 $CONFIG_EXPERIMENTAL
-dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
-dep_tristate '  TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
-   hex '    Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
-fi
-dep_tristate '  Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
-   hex '    Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350
-fi
-dep_tristate '  Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV
-if [ "$CONFIG_PROC_FS" = "y" ]; then
-   if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then
-      bool '    Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS
+   dep_tristate '    miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)' CONFIG_RADIO_MIROPCM20_RDS $CONFIG_RADIO_MIROPCM20 $CONFIG_EXPERIMENTAL
+   dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
+   dep_tristate '  TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
+      hex '    Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
+   fi
+   dep_tristate '  Trust FM radio card' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
+      hex '    Trust i/o port (usually 0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350
+   fi
+   dep_tristate '  Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_PROC_FS" = "y" ]; then
+      if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then
+         bool '    Support for /proc/radio-typhoon' CONFIG_RADIO_TYPHOON_PROC_FS
+      fi
+   fi
+   if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then
+      hex '  Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316
+      int '  Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500
+   fi
+   dep_tristate '  Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
+      hex '    ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
    fi
-fi
-if [ "$CONFIG_RADIO_TYPHOON" = "y" ]; then
-   hex '  Typhoon I/O port (0x316 or 0x336)' CONFIG_RADIO_TYPHOON_PORT 316
-   int '  Typhoon frequency set when muting the device (kHz)' CONFIG_RADIO_TYPHOON_MUTEFREQ 87500
-fi
-dep_tristate '  Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV
-if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
-   hex '    ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
-fi
 fi
 endmenu
diff -urN linux-2.4.20-pre1/drivers/media/radio/radio-gemtek.c linux-2.4.20-pre2/drivers/media/radio/radio-gemtek.c
--- linux-2.4.20-pre1/drivers/media/radio/radio-gemtek.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.20-pre2/drivers/media/radio/radio-gemtek.c	Mon Aug 12 16:34:16 2002
@@ -281,14 +281,14 @@
 	printk(KERN_INFO "GemTek Radio Card driver.\n");
 
 	spin_lock_init(&lock);
- 	/* mute card - prevents noisy bootups */
-	outb(0x10, io);
-	udelay(5);
-	gemtek_unit.muted = 1;
 
 	/* this is _maybe_ unnecessary */
 	outb(0x01, io);
 
+ 	/* mute card - prevents noisy bootups */
+	gemtek_unit.muted = 0;
+	gemtek_mute(&gemtek_unit);
+
 	return 0;
 }
 
diff -urN linux-2.4.20-pre1/drivers/media/video/bttv-cards.c linux-2.4.20-pre2/drivers/media/video/bttv-cards.c
--- linux-2.4.20-pre1/drivers/media/video/bttv-cards.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/bttv-cards.c	Mon Aug 12 16:34:16 2002
@@ -63,9 +63,9 @@
 static int triton1=0;
 static int vsfx=0;
 int no_overlay=-1;
-static unsigned int card[4]  = { -1, -1, -1, -1 };
-static unsigned int pll[4]   = { -1, -1, -1, -1 };
-static unsigned int tuner[4] = { -1, -1, -1, -1 };
+static unsigned int card[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = -1};
+static unsigned int pll[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = -1};
+static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1};
 #ifdef MODULE
 static unsigned int autoload = 1;
 #else
@@ -83,11 +83,11 @@
 MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
 		 "[yet another chipset flaw workaround]");
 MODULE_PARM(no_overlay,"i");
-MODULE_PARM(card,"1-4i");
+MODULE_PARM(card,"1-" __stringify(BTTV_MAX) "i");
 MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
-MODULE_PARM(pll,"1-4i");
+MODULE_PARM(pll,"1-" __stringify(BTTV_MAX) "i");
 MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
-MODULE_PARM(tuner,"1-4i");
+MODULE_PARM(tuner,"1-" __stringify(BTTV_MAX) "i");
 MODULE_PARM_DESC(tuner,"specify installed tuner type");
 MODULE_PARM(autoload,"i");
 MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
@@ -127,7 +127,7 @@
 } cards[] __devinitdata = {
 	{ 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
 	{ 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
-	{ 0x45000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV/PVR" },
+	{ 0x45000070, BTTV_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
 	{ 0xff000070, BTTV_HAUPPAUGE878,  "Osprey-100" },
 	{ 0xff010070, BTTV_HAUPPAUGE878,  "Osprey-200" },
 
@@ -135,9 +135,10 @@
 	{ 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
 
 	{ 0x6606107d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x6607107d, BTTV_WINFAST2000,   "Leadtek WinFast VC 100" },
 	{ 0x263610b4, BTTV_STB2,          "STB TV PCI FM, P/N 6000704" },
- 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
-	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCV4/PCI" },
+ 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
+	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
 
 	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
@@ -163,6 +164,8 @@
 	{ 0x111a153b, BTTV_TERRATVALUE,   "Terratec TValue" },
 	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV Radio+" },
 	{ 0x1127153b, BTTV_TERRATV,       "Terratec TV+"    },
+	// clashes with FlyVideo
+	//{ 0x18521852, BTTV_TERRATV,     "Terratec TV+"    },
 	{ 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue" },
 	{ 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" },
 	{ 0x5018153b, BTTV_TERRATVALUE,   "Terratec TValue" },
@@ -174,13 +177,14 @@
 
     	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
 	{ 0x010114c7, BTTV_MODTEC_205,    "Modular Technology MM205 PCTV" },
-	{ 0x18501851, BTTV_CHRONOS_VS2,   "Flyvideo 98 (LR50)/ Chronos Video Shuttle II" },
-	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "Flyvideo 98EZ (LR51)/ CyberMail AV" },
-	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Flyvideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
+	{ 0x18501851, BTTV_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
+	{ 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
 	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
 	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
 	{ 0x03116000, BTTV_SENSORAY311,   "Sensoray 311" },
 	{ 0x00790e11, BTTV_WINDVR,        "Canopus WinDVR PCI" },
+	{ 0xa0fca1a0, BTTV_ZOLTRIX,       "Face to Face Tvmax" },
 
 	{ 0, -1, NULL }
 };
@@ -235,16 +239,16 @@
 },{
 
 /* ---- card 0x04 ---------------------------------- */
-	name:		"Intel",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		-1,
-	gpiomask:	7,
+	name:		"Intel Create and Share PCI/ Smart Video Recorder III",
+	video_inputs:	4,
+	audio_inputs:	0,
+	tuner:		-1,
+	svhs:		2,
+	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 1, 2, 3, 4},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	audiomux:	{ 0 },
+	needs_tvaudio:	0,
+	tuner_type:	4,
 },{
 	name:		"Diamond DTV2000",
 	video_inputs:	4,
@@ -283,7 +287,7 @@
 },{
 
 /* ---- card 0x08 ---------------------------------- */
-	name:		"FlyVideo II (Bt848) LR26",
+	name:		"Lifeview FlyVideo II (Bt848) LR26",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -295,7 +299,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"IXMicro TurboTV",
+	name:		"IMS/IXmicro TurboTV",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -303,8 +307,9 @@
 	gpiomask:	3,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 1, 1, 2, 3, 0},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	needs_tvaudio:	0,
+	pll:		PLL_28,
+	tuner_type:	TUNER_TEMIC_PAL,
 },{
 	name:		"Hauppauge (bt878)",
 	video_inputs:	4,
@@ -331,7 +336,7 @@
 },{
 
 /* ---- card 0x0c ---------------------------------- */
-	name:		"ADS Technologies Channel Surfer TV",
+	name:		"ADS Technologies Channel Surfer TV (bt848)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -352,7 +357,7 @@
 	audiomux:	{ 13, 14, 11, 7, 0, 0},
 	needs_tvaudio:	1,
 	pll:		PLL_28,
-	tuner_type:	-1,
+	tuner_type:	TUNER_PHILIPS_PAL,
 },{
 	name:		"Aimslab Video Highway Xtreme (VHX)",
 	video_inputs:	3,
@@ -363,6 +368,7 @@
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
 	needs_tvaudio:	1,
+	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 	name:		"Zoltrix TV-Max",
@@ -378,7 +384,7 @@
 },{
 
 /* ---- card 0x10 ---------------------------------- */
-	name:		"Pixelview PlayTV (bt878)",
+	name:		"Prolink Pixelview PlayTV (bt878)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -414,8 +420,8 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"LifeView FlyKit w/o Tuner",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		-1,
 	svhs:		-1,
@@ -435,19 +441,18 @@
 	muxsel:		{2, 3, 1, 1},
 	tuner_type:	-1,
 },{
-	name:		"Lucky Star Image World ConferenceTV",
-	video_inputs:	3,
-	audio_inputs:	1,
+	name:		"Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+	video_inputs:	4,
+	audio_inputs:	2,  // tuner, line in
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0x00fffe07,
+	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 131072, 1, 1638400, 3, 4},
-	needs_tvaudio:	1,
+	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL_I,
 },{
-	name:		"Phoebe Tv Master + FM (CPH050)",
+	name:		"Askey CPH050/ Phoebe Tv Master + FM",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -456,6 +461,7 @@
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{0, 1, 0x800, 0x400, 0xc00, 0},
 	needs_tvaudio:	1,
+	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 	name:		"Modular Technology MM205 PCTV, bt878",
@@ -472,7 +478,7 @@
 },{
 
 /* ---- card 0x18 ---------------------------------- */
-	name:		"[many vendors] CPH05X/06X (bt878)",
+	name:		"Askey CPH05X/06X (bt878) [many vendors]",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -484,7 +490,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"Terratec/Vobis TV-Boostar",
+	name:		"Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -495,7 +501,7 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"Newer Hauppauge WinCam (bt878)",
+	name:		"Hauppauge WinCam newer (bt878)",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -506,15 +512,15 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"MAXI TV Video PCI2",
-	video_inputs:	3,
-	audio_inputs:	1,
+	name:		"Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+	video_inputs:	4,
+	audio_inputs:	2,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0xffff,
+	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 1, 2, 3, 0xc00},
-	needs_tvaudio:	1,
+	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
+	pll:            PLL_28,
 	tuner_type:	TUNER_PHILIPS_SECAM,
 },{
 
@@ -543,18 +549,18 @@
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
-	name:		"FlyVideo 98",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo 98 LR50",
+	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,  //0x8dfe00
-	muxsel:		{2, 3, 1, 1},
+	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
-	needs_tvaudio:	1,
+	pll:            PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"iProTV",
+	name:		"Formac iProTV",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -566,16 +572,16 @@
 },{
 
 /* ---- card 0x20 ---------------------------------- */
-	name:		"Intel Create and Share PCI",
+	name:		"Intel Create and Share PCI/ Smart Video Recorder III",
 	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
+	audio_inputs:	0,
+	tuner:		-1,
 	svhs:		2,
-	gpiomask:	7,
+	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 4, 4, 4, 4, 4},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	audiomux:	{ 0 },
+	needs_tvaudio:	0,
+	tuner_type:	4,
 },{
 	name:		"Terratec TerraTValue",
 	video_inputs:	3,
@@ -589,47 +595,57 @@
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL,
 },{
-	name:		"Leadtek WinFast 2000",
-	video_inputs:	3,
+	name:		"Leadtek WinFast 2000/ WinFast 2000 XP",
+	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0xc33000,
-	muxsel:		{ 2, 3, 1, 1,0},
-	audiomux:	{ 0x422000,0x001000,0x621100,0x620000,0x800000,0x620000},
+	muxsel:		{ 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector
+	audiomux:	{ 0x422000,0x1000,0x0000,0x620000,0x800000},
+	/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
+		gpio23 -- hef4052:nEnable (0x800000)
+		gpio12 -- hef4052:A1
+	        gpio13 -- hef4052:A0
+	    0x0000: external audio
+	    0x1000: FM
+	    0x2000: TV
+	    0x3000: n.c.
+          Note: There exists another variant "Winfast 2000" with tv stereo !?
+	  Note: eeprom only contains FF and pci subsystem id 107d:6606
+	 */
 	needs_tvaudio:	0,
 	pll:		PLL_28,
-	tuner_type:	-1,
+	has_radio:	1,
+	tuner_type:	5, // default for now, gpio reads BFFF06 for Pal bg+dk
 	audio_hook:	winfast2000_audio,
 },{
-	name:		"Flyvideo 98 (LR50Q) / Chronos Video Shuttle II",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+	video_inputs:	4,
 	audio_inputs:	3,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
-	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
 
 /* ---- card 0x24 ---------------------------------- */
-	name:		"Flyvideo 98FM (LR50Q) / Typhoon TView TV/FM Tuner",
-	video_inputs:	3,
+	name:		"Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+	video_inputs:	4,
 	audio_inputs:	3,
 	tuner:		0,
 	svhs:		2,
 	gpiomask:	0x1800,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	needs_tvaudio:	1,
 	pll:		PLL_28,
 	tuner_type:	-1,
 	has_radio:	1,
 },{
-	name:		"PixelView PlayTV pro",
+	name:		"Prolink PixelView PlayTV pro",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -641,7 +657,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"TView99 CPH06X",
+	name:		"Askey CPH06X TView99",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -684,7 +700,7 @@
 	audio_inputs:	4,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	12,
+	gpiomask:	15,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 13, 4, 11, 7, 0, 0},
 	needs_tvaudio:	1,
@@ -700,6 +716,7 @@
 	gpiomask:	0,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0, 0, 0, 0, 0},
+	needs_tvaudio:	1,
 	no_msp34xx:	1,
 	pll:		PLL_28,
 	tuner_type:	1,
@@ -758,9 +775,9 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0x1f0000,
+	gpiomask:	0x70000,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },
+	audiomux:	{ 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
 	needs_tvaudio:	1,
 	no_msp34xx:	1,
 	pll:		PLL_35,
@@ -769,7 +786,7 @@
 },{
 
 /* ---- card 0x30 ---------------------------------- */
-	name:		"Dynalink Magic TView ",
+	name:		"Askey CPH03x/ Dynalink Magic TView",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -781,7 +798,7 @@
 	pll:		PLL_28,
 	tuner_type:	-1,
 },{
-	name:		"GV-BCTV3",
+	name:		"IODATA GV-BCTV3/PCI",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -828,6 +845,15 @@
 	gpiomask:       0x03000F,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 1, 0x10001, 0, 0, 10},
+			/* sound path (5 sources):
+			   MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
+				0= ext. Audio IN
+				1= from MUX2
+				2= Mono TV sound from Tuner
+				3= not connected
+			   MUX2 (mask 0x30000):
+				0,2,3= from MSP34xx
+				1= FM stereo Radio from Tuner */
 	needs_tvaudio:  1,
 	pll:            PLL_28,
 	tuner_type:     -1,
@@ -852,7 +878,7 @@
 		options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
 		audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
 		options tuner type=5 */
-	name:		"Lifetec LT 9415 TV (LR90 Rev.F)",
+	name:		"Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -860,17 +886,16 @@
 	gpiomask:	0x18e0,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x18e0 },
-		       /* 0x0000: Tuner normal stereo
+		       /* For cards with tda9820/tda9821:
+			  0x0000: Tuner normal stereo
 			  0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
 			  0x0880: Tuner A2 stereo */
 	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL,
-	audio_hook:	lt9415_audio,
-	has_radio:	1,
+	tuner_type:	-1,
 },{
 	/* Miguel Angel Alvarez <maacruz@navegalia.com>
 	   old Easy TV BT848 version (model CPH031) */
-	name:           "BESTBUY Easy TV (CPH031)",
+	name:           "Askey CPH031/ BESTBUY Easy TV",
 	video_inputs:	4,
 	audio_inputs:   1,
 	tuner:          0,
@@ -885,15 +910,14 @@
 
 /* ---- card 0x38 ---------------------------------- */
 	/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
-	name:           "FlyVideo '98/FM",
-	video_inputs:   3,
+	name:           "Lifeview FlyVideo 98FM LR50",
+	video_inputs:   4,
 	audio_inputs:   3,
 	tuner:          0,
 	svhs:           2,
 	gpiomask:       0x1800,
-	muxsel:         { 2, 3, 0, 1},
+	muxsel:         { 2, 3, 1, 1},
 	audiomux:       { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	needs_tvaudio:  1,
 	pll:            PLL_28,
 	tuner_type:     5,
 },{
@@ -914,7 +938,7 @@
 	tuner_type:     -1,
 },{
         /* Daniel Herrington <daniel.herrington@home.com> */
-        name:           "Phoebe TV Master Only (No FM) CPH060",
+        name:           "Askey CPH060/ Phoebe TV Master Only (No FM)",
         video_inputs:   3,
         audio_inputs:   1,
         tuner:          0,
@@ -923,11 +947,11 @@
         muxsel:         { 2, 3, 1, 1},
         audiomux:       { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
         needs_tvaudio:  1,
-        pll:            PLL_NONE,
+        pll:            PLL_28,
         tuner_type:     TUNER_TEMIC_4036FY5_NTSC,
 },{
 	/* Matti Mottus <mottus@physic.ut.ee> */
-	name:		"TV Capturer (CPH03X)",
+	name:		"Askey CPH03x TV Capturer",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -944,10 +968,12 @@
 	name:           "Modular Technology MM100PCTV",
 	video_inputs:   2,
 	audio_inputs:   2,
+	tuner:		0,
+	svhs:		-1,
 	gpiomask:       11,
 	muxsel:         { 2, 3, 1, 1},
 	audiomux:       { 2, 0, 0, 1, 8},
-	pll:            PLL_NONE,
+	pll:            PLL_35,
 	tuner_type:     TUNER_TEMIC_PAL,
 
 },{
@@ -968,7 +994,7 @@
 	/* Miguel Angel Alvarez <maacruz@navegalia.com>
 	   new Easy TV BT878 version (model CPH061) 
 	   special thanks to Informatica Mieres for providing the card */
-	name:           "BESTBUY Easy TV (bt878)",
+	name:           "Askey CPH061/ BESTBUY Easy TV (bt878)",
 	video_inputs:	3,
 	audio_inputs:   2,
 	tuner:          0,
@@ -1008,7 +1034,7 @@
 	tuner_type:	TUNER_TEMIC_4006FN5_MULTI_PAL,
 },{
 	/* DeeJay <deejay@westel900.net (2000S) */
-	name:           "FlyVideo 2000S",
+	name:           "Lifeview FlyVideo 2000S LR90",
 	video_inputs:   3,
 	audio_inputs:   3,
 	tuner:          0,
@@ -1016,7 +1042,7 @@
 	gpiomask:	0x18e0,
 	muxsel:		{ 2, 3, 0, 1},
 			/* Radio changed from 1e80 to 0x800 to make
-			   Flyvideo2000S in .hu happy (gm)*/
+			   FlyVideo2000S in .hu happy (gm)*/
 			/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
 	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
 	audio_hook:	fv2000s_audio,
@@ -1040,7 +1066,7 @@
 	has_radio:	1,
 },{
 	/* TANAKA Kei <peg00625@nifty.com> */
-	name:           "GV-BCTV4/PCI",
+	name:           "IODATA GV-BCTV4/PCI",
 	video_inputs:   3,
 	audio_inputs:   1,
 	tuner:          0,
@@ -1084,7 +1110,7 @@
 	gpiomask:       0
 },{
         /* Tomasz Pyra <hellfire@sedez.iq.pl> */
-        name:           "PV-BT878P+",
+        name:           "Prolink Pixelview PV-BT878P+ (Rev.4C)",
         video_inputs:   3,
         audio_inputs:   4,
         tuner:          0,
@@ -1096,7 +1122,7 @@
         pll:            PLL_28,
         tuner_type:     25,
 },{
-	name:		"Flyvideo 98EZ (capture only)",
+	name:		"Lifeview FlyVideo 98EZ (capture only) LR51",
 	video_inputs:	4,
 	audio_inputs:   0,
 	tuner:		-1,
@@ -1108,7 +1134,7 @@
 
 /* ---- card 0x48 ---------------------------------- */
 	/* Dariusz Kowalewski <darekk@automex.pl> */
-	name:		"Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+	name:		"Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
 	video_inputs:	3,
 	audio_inputs:	1,
 	tuner:		0,
@@ -1141,8 +1167,8 @@
 	name:           "RemoteVision MX (RV605)",
 	video_inputs:   16,
 	audio_inputs:   0,
-	tuner:          0,
-	svhs:           0,
+	tuner:          -1,
+	svhs:           -1,
 	gpiomask:       0x00,
 	gpiomask2:      0x07ff,
 	muxsel:         { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
@@ -1155,6 +1181,7 @@
         name:           "Powercolor MTV878/ MTV878R/ MTV878F",
         video_inputs:   3,
         audio_inputs:   2, 
+	tuner:		0,
         svhs:           2,
         gpiomask:       0x1C800F,  // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset
         muxsel:         { 2, 1, 1, },
@@ -1191,15 +1218,57 @@
         pll:            PLL_28,
         tuner_type:     -1,
 },{
-	/* http://www.aopen.com/products/video/va1000.htm */
-	name:           "AOPEN VA1000",
-	video_inputs:   3, /* coax, AV, s-vid */
-	audio_inputs:   1,
-	tuner:          0,
-	tuner_type:     TUNER_LG_PAL, /* actually TP18PSB12P (PAL B/G) */
-	audiomux:       { 2, 0, 0, 0 },
-	muxsel:         { 2, 3, 1, 0 },
-	pll:            PLL_28,
+        name:           "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+        video_inputs:   4,
+        audio_inputs:   3, 
+        tuner:          0,
+        svhs:           2,
+        gpiomask:       7,
+        muxsel:         { 2, 3, 1, 1 },   // Tuner, SVid, SVHS, SVid to SVHS connector
+        audiomux:       { 0 ,0 ,4, 4,4,4},// Yes, this tuner uses the same audio output for TV and FM radio!
+					  // This card lacks external Audio In, so we mute it on Ext. & Int.
+					  // The PCB can take a sbx1637/sbx1673, wiring unknown.
+					  // This card lacks PCI subsystem ID, sigh.
+					  // audiomux=1: lower volume, 2+3: mute
+					  // btwincap uses 0x80000/0x80003
+        needs_tvaudio:  0,
+        no_msp34xx:     1,
+        pll:            PLL_28,
+        tuner_type:     5, // Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+			   // radio signal strength indicators work fine.
+	has_radio:		1,
+	/* GPIO Info:
+		GPIO0,1:   HEF4052 A0,A1
+		GPIO2:     HEF4052 nENABLE
+		GPIO3-7:   n.c.
+		GPIO8-13:  IRDC357 data0,5 (data6 n.c. ?) [chip not present on my card]
+		GPIO14,15: ??
+		GPIO16-21: n.c.
+		GPIO22,23: ??
+		??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
+},{
+        /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+        name:           "DSP Design TCVIDEO",
+        video_inputs:   4,
+        svhs:           -1,
+        muxsel:         { 2, 3, 1, 0},
+        pll:            PLL_28,
+        tuner_type:     -1,
+},{
+
+        /* ---- card 0x50 ---------------------------------- */
+	name:           "Hauppauge WinTV PVR",
+        video_inputs:   4,
+        audio_inputs:   1,
+        tuner:          0,
+        svhs:           2,
+        muxsel:         { 2, 0, 1, 1},
+        needs_tvaudio:  1,
+        pll:            PLL_28,
+        tuner_type:     -1,
+
+	gpiomask:       7,
+	audiomux:       {7},
 }};
 
 const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
@@ -1289,8 +1358,8 @@
  */
 
 static void flyvideo_gpio(struct bttv *btv)
-{
-	int gpio,outbits;
+{ 
+	int gpio,outbits,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
 	int tuner=-1,ttype;
 	
 	outbits = btread(BT848_GPIO_OUT_EN);
@@ -1299,29 +1368,56 @@
 	gpio=btread(BT848_GPIO_DATA);
 	btwrite(outbits, BT848_GPIO_OUT_EN);
 	// all cards provide GPIO info, some have an additional eeprom
+	// LR50: GPIO coding can be found lower right CP1 .. CP9
+	//       CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1.
+	//       GPIO14-12: n.c.
+	// LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878)
 	
 	// lowest 3 bytes are remote control codes (no handshake needed)
+        // xxxFFF: No remote control chip soldered
+        // xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered 
+	// Note: Some bits are Audio_Mask !
+
 	ttype=(gpio&0x0f0000)>>16;
 	switch(ttype) {
-	case 0: tuner=4; // None
+	case 0x0: tuner=4; // None
+		break;
+        case 0x2: tuner=39;// LG NTSC (newer TAPC series) TAPC-H701P
 		break;
-	case 4: tuner=5; // Philips PAL
+	case 0x4: tuner=5; // Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216
 		break;
-	case 6: tuner=37; // LG PAL (newer TAPC series)
+	case 0x6: tuner=37; // LG PAL (newer TAPC series) TAPC-G702P
 		break;
-	case 0xC: tuner=3; // Philips SECAM(+PAL)
+	case 0xC: tuner=3; // Philips SECAM(+PAL) FQ1216ME or FI1216MF
 		break;
 	default:
-		printk(KERN_INFO "bttv%d: flyvideo_gpio: unknown tuner type.\n", btv->nr);
+		printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->nr);
 	}
-	
-	printk(KERN_INFO "bttv%d: Flyvideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", 
-	       btv->nr,
-	       gpio&0x400000? "yes":"no",
-	       gpio&0x800000? "yes":"no", tuner, gpio);
-	
-	btv->tuner_type = tuner;
-	btv->has_radio = gpio&0x400000? 1:0; 
+
+	has_remote          =   gpio & 0x800000;
+	has_radio	    =   gpio & 0x400000;
+	//   unknown                   0x200000;
+	//   unknown2                  0x100000;
+        is_capture_only     = !(gpio & 0x008000); //GPIO15
+	has_tda9820_tda9821 = !(gpio & 0x004000);
+	is_lr90             = !(gpio & 0x002000); // else LR26/LR50 (LR38/LR51 f. capture only)
+        //		        gpio & 0x001000 // output bit for audio routing
+
+	printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", 
+	       btv->nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); 
+	printk(KERN_INFO "bttv%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
+		btv->nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", 
+		is_capture_only?"yes":"no ");
+
+	if(tuner!= -1) // only set if known tuner autodetected, else let insmod option through
+		btv->tuner_type = tuner;
+	btv->has_radio = has_radio;  
+
+	// LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
+        // LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
+	// Audio options: from tuner, from tda9821/tda9821(mono,stereo.sap), from tda9874, ext., mute
+	if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
+	//todo: if(has_tda9874) btv->audio_hook = fv2000s_audio;
 }
 
 int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
@@ -1329,86 +1425,98 @@
 int miro_fmtuner[]  = { 0,0,0,0,   0,0,0,0,  0,0,0,0,  0,0,0,1,
 			1,1,1,1,   1,1,1,0,  0,0,0,0,  0,0,0,0 };
 
+static void miro_pinnacle_gpio(struct bttv *btv)
+{
+	int id,msp;
+	
+	id  = ((btread(BT848_GPIO_DATA)>>10) & 31) -1;
+	msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
+	btv->tuner_type = miro_tunermap[id];
+	if (0 == (btread(BT848_GPIO_DATA) & 0x20)) {
+		btv->has_radio = 1;
+		if (!miro_fmtuner[id]) {
+			btv->has_matchbox = 1;
+			btv->mbox_we    = (1<<6);
+			btv->mbox_most  = (1<<7);
+			btv->mbox_clk   = (1<<8);
+			btv->mbox_data  = (1<<9);
+			btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+		}
+	} else {
+		btv->has_radio = 0;
+	}
+	if (-1 != msp) {
+		if (btv->type == BTTV_MIRO)
+			btv->type = BTTV_MIROPRO;
+		if (btv->type == BTTV_PINNACLE)
+			btv->type = BTTV_PINNACLEPRO;
+	}
+	printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
+	       btv->nr, id+1, btv->tuner_type,
+	       !btv->has_radio ? "no" :
+	       (btv->has_matchbox ? "matchbox" : "fmtuner"),
+	       (-1 == msp) ? "no" : "yes");
+}
+
 /* initialization part one -- before registering i2c bus */
 void __devinit bttv_init_card1(struct bttv *btv)
 {
-        if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878)
+	switch (btv->type) {
+	case BTTV_HAUPPAUGE:
+	case BTTV_HAUPPAUGE878:
                 boot_msp34xx(btv,5);
-	if (btv->type == BTTV_VOODOOTV_FM)
-		boot_msp34xx(btv,20);
+		break;
+	case BTTV_VOODOOTV_FM:
+                boot_msp34xx(btv,20);
+		break;
+	case BTTV_HAUPPAUGEPVR:
+		pvr_boot(btv);
+		break;
+	}
 }
 
-/* initialization part one -- after registering i2c bus */
+/* initialization part two -- after registering i2c bus */
 void __devinit bttv_init_card2(struct bttv *btv)
 {
-	/* miro/pinnacle */
-        if (btv->type == BTTV_MIRO      ||
-	    btv->type == BTTV_MIROPRO   ||
-	    btv->type == BTTV_PINNACLE  ||
-	    btv->type == BTTV_PINNACLEPRO) {
-		int id,msp;
-		id  = ((btread(BT848_GPIO_DATA)>>10) & 31) -1;
-		msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
-		btv->tuner_type = miro_tunermap[id];
-		if (0 == (btread(BT848_GPIO_DATA) & 0x20)) {
-			btv->has_radio = 1;
-			if (!miro_fmtuner[id]) {
-				btv->has_matchbox = 1;
-				btv->mbox_we    = (1<<6);
-				btv->mbox_most  = (1<<7);
-				btv->mbox_clk   = (1<<8);
-				btv->mbox_data  = (1<<9);
-				btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
-			}
-		} else {
-			btv->has_radio = 0;
-		}
-		if (-1 != msp) {
-			if (btv->type == BTTV_MIRO)
-				btv->type = BTTV_MIROPRO;
-			if (btv->type == BTTV_PINNACLE)
-				btv->type = BTTV_PINNACLEPRO;
-		}
-		if (bttv_verbose)
-			printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d "
-			       "radio=%s stereo=%s\n",
-			       btv->nr, id+1, btv->tuner_type,
-			       !btv->has_radio ? "no" :
-				   (btv->has_matchbox ? "matchbox" : "fmtuner"),
-			       (-1 == msp) ? "no" : "yes");
-#if 0
-		if (btv->has_matchbox) {
-			if (bttv_verbose)
-				printk(KERN_INFO "Initializing TEA5757...\n");
-			init_tea5757(btv);
-		}
-#endif
-	}
+        btv->tuner_type = -1;
 
-	if (btv->type == BTTV_FLYVIDEO_98    ||
-	    btv->type == BTTV_FLYVIDEO       ||
-	    btv->type == BTTV_TYPHOON_TVIEW  ||
-	    btv->type == BTTV_CHRONOS_VS2    ||
-	    btv->type == BTTV_FLYVIDEO_98FM  ||
-	    btv->type == BTTV_FLYVIDEO2000   ||
-	    btv->type == BTTV_FLYVIDEO98EZ)
+	switch (btv->type) {
+	case BTTV_MIRO:
+	case BTTV_MIROPRO:
+	case BTTV_PINNACLE:
+	case BTTV_PINNACLEPRO: 
+		/* miro/pinnacle */
+		miro_pinnacle_gpio(btv);
+		break;
+	case BTTV_FLYVIDEO_98:
+	case BTTV_MAXI:
+	case BTTV_LIFE_FLYKIT:
+	case BTTV_FLYVIDEO:
+	case BTTV_TYPHOON_TVIEW:
+	case BTTV_CHRONOS_VS2:
+	case BTTV_FLYVIDEO_98FM:
+	case BTTV_FLYVIDEO2000:
+	case BTTV_FLYVIDEO98EZ:
+	case BTTV_CONFERENCETV:
+	case BTTV_LIFETEC_9415:
 		flyvideo_gpio(btv);
-
-        if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
+		break;
+	case BTTV_HAUPPAUGE:
+	case BTTV_HAUPPAUGE878:
+	case BTTV_HAUPPAUGEPVR:
 		/* pick up some config infos from the eeprom */
 		bttv_readee(btv,eeprom_data,0xa0);
                 hauppauge_eeprom(btv);
-        }
-
-	if (btv->type == BTTV_AVERMEDIA98 || btv->type == BTTV_AVPHONE98) {
+		break;
+	case BTTV_AVERMEDIA98:
+	case BTTV_AVPHONE98:
 		bttv_readee(btv,eeprom_data,0xa0);
 		avermedia_eeprom(btv);
-	}
-
- 	if (btv->type == BTTV_PXC200)
+		break;
+	case BTTV_PXC200:
 		init_PXC200(btv);
-
-	if (btv->type == BTTV_VHX) {
+		break;
+	case BTTV_VHX:
 		btv->has_radio    = 1;
 		btv->has_matchbox = 1;
 		btv->mbox_we      = 0x20;
@@ -1416,20 +1524,13 @@
 		btv->mbox_clk     = 0x08;
 		btv->mbox_data    = 0x10;
 		btv->mbox_mask    = 0x38;
-	}
-
-	if (btv->type == BTTV_LIFETEC_9415) {
-		if (btread(BT848_GPIO_DATA) & 0x4000)
-			printk("bttv%d: lifetec: tv mono/fm stereo card\n", btv->nr);
-		else
-			printk("bttv%d: lifetec: stereo(TDA9821) card\n",btv->nr);
-	}
-
-	if (btv->type == BTTV_MAGICTVIEW061) {
-		if(btv->cardid == 0x4002144f) {
+		break;
+	case BTTV_MAGICTVIEW061:
+		if (btv->cardid == 0x4002144f) {
 			btv->has_radio=1;
 			printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->nr);
 		}
+		break;
 	}
 
 	/* pll configuration */
@@ -1465,17 +1566,22 @@
                 }
         }
 
-	/* tuner configuration (from card list / insmod option) */
+	/* tuner configuration (from card list / autodetect / insmod option) */
  	if (-1 != bttv_tvcards[btv->type].tuner_type)
-                btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
+		if( -1 == btv->tuner_type) 
+                	btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
 	if (-1 != tuner[btv->nr])
 		btv->tuner_type = tuner[btv->nr];
 	if (btv->tuner_type != -1)
 		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
+	printk("bttv%d: using tuner=%d\n",btv->nr,btv->tuner_type);
 
 	if (bttv_tvcards[btv->type].has_radio)
 		btv->has_radio=1;
 
+	if (bttv_tvcards[btv->type].audio_hook)
+		btv->audio_hook=bttv_tvcards[btv->type].audio_hook;
+
 	/* try to detect audio/fader chips */
 	if (!bttv_tvcards[btv->type].no_msp34xx &&
 	    bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
@@ -1597,6 +1703,85 @@
 		       btv->tuner_type, radio ? "yes" : "no");
 }
 
+/* ----------------------------------------------------------------------- */
+
+/*
+ * minimal bootstrap for the WinTV/PVR -- upload altera firmware.
+ *
+ * The hcwamc.rbf firmware file is on the Hauppauge driver CD.  Have
+ * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be
+ * unpacked with unzip).
+ */
+static char *firm_altera = "/usr/lib/video4linux/hcwamc.rbf";
+MODULE_PARM(firm_altera,"s");
+MODULE_PARM_DESC(firm_altera,"WinTV/PVR firmware "
+		 "(driver CD => unzip pvr45xxx.exe => hcwamc.rbf)");
+
+/* drivers/sound/sound_firmware.c => soundcore.o */
+extern int mod_firmware_load(const char *fn, char **fp);
+
+#define PVR_GPIO_DELAY		10
+
+#define BTTV_ALT_DATA		0x000001
+#define BTTV_ALT_DCLK		0x100000
+#define BTTV_ALT_NCONFIG	0x800000
+
+static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
+{
+	u32 n;
+  	u8 bits;
+	int i;
+ 
+	btwrite(BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG,
+		BT848_GPIO_OUT_EN);
+	btwrite(0,BT848_GPIO_DATA);
+	udelay(PVR_GPIO_DELAY);
+	
+	btwrite(BTTV_ALT_NCONFIG,BT848_GPIO_DATA);
+	udelay(PVR_GPIO_DELAY);
+
+	for (n = 0; n < microlen; n++) {
+		bits = micro[n];
+		for ( i = 0 ; i < 8 ; i++ ) {
+			btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
+			if (bits & 0x01) 
+				btor(BTTV_ALT_DATA,BT848_GPIO_DATA);
+			else 
+				btand(~BTTV_ALT_DATA,BT848_GPIO_DATA);
+			btor(BTTV_ALT_DCLK,BT848_GPIO_DATA);
+			bits >>= 1;
+		}
+	}
+	btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
+	udelay(PVR_GPIO_DELAY);
+	
+	/* begin Altera init loop (Not necessary,but doesn't hurt) */
+	for (i = 0 ; i < 30 ; i++) {
+		btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
+		btor(BTTV_ALT_DCLK,BT848_GPIO_DATA);
+	}
+	btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA);
+	return 0;
+}
+
+int __devinit pvr_boot(struct bttv *btv)
+{
+	u32 microlen;
+	u8 *micro;
+	int result;
+
+	microlen = mod_firmware_load(firm_altera, (char**) &micro);
+	if (!microlen)
+		return -1;
+	
+	printk(KERN_INFO "bttv%d: uploading altera firmware [%s] ...\n",
+	       btv->nr, firm_altera);
+	result = pvr_altera_load(btv, micro, microlen);
+	printk(KERN_INFO "bttv%d: ... upload %s\n",
+	       btv->nr, (result < 0) ? "failed" : "ok");
+	vfree(micro);
+	return result;
+}
 
 /* ----------------------------------------------------------------------- */
 /* AVermedia specific stuff, from  bktr_card.c                             */
diff -urN linux-2.4.20-pre1/drivers/media/video/bttv-driver.c linux-2.4.20-pre2/drivers/media/video/bttv-driver.c
--- linux-2.4.20-pre1/drivers/media/video/bttv-driver.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/bttv-driver.c	Mon Aug 12 16:34:16 2002
@@ -43,6 +43,7 @@
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/pagemap.h>
 
 #include "bttvp.h"
 #include "tuner.h"
@@ -65,8 +66,10 @@
 static unsigned int radio[BTTV_MAX];
 static unsigned int fieldnr = 0;
 static unsigned int irq_debug = 0;
-static unsigned int gbuffers = 2;
+static unsigned int gbuffers = 4;
 static unsigned int gbufsize = BTTV_MAX_FBUF;
+static int latency = -1;
+
 static unsigned int combfilter = 0;
 static unsigned int lumafilter = 0;
 static unsigned int automute = 1;
@@ -80,7 +83,7 @@
 unsigned int bttv_gpio = 0;
 
 /* insmod options */
-MODULE_PARM(radio,"1-4i");
+MODULE_PARM(radio,"1-" __stringify(BTTV_MAX) "i");
 MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
 MODULE_PARM(bigendian,"i");
 MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
@@ -98,6 +101,8 @@
 MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)");
 MODULE_PARM(gbufsize,"i");
 MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM(latency,"i");
+MODULE_PARM_DESC(latency,"pci latency timer");
 
 MODULE_PARM(combfilter,"i");
 MODULE_PARM(lumafilter,"i");
@@ -137,64 +142,14 @@
 /* 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 unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-        unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-  
-	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  = (unsigned long) page_address(pte_page(pte));
-				ret |= (adr & (PAGE_SIZE - 1));
-				
-			}
-                }
-        }
-        MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr) 
-{
-        unsigned long kva, ret;
-
-        kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
-        MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
-        return ret;
-}
 
 static inline unsigned long kvirt_to_bus(unsigned long adr) 
 {
-        unsigned long va, kva, ret;
+        unsigned long kva;
 
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-        MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
-        return ret;
+	kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */   
+	return virt_to_bus((void *)kva);
 }
 
 /* Here we want the physical address of the memory.
@@ -203,19 +158,18 @@
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
-        unsigned long va, kva, ret;
+        unsigned long kva;
 
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = __pa(kva);
-        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
-        return ret;
+	kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	return __pa(kva);
 }
 
 static void * rvmalloc(signed long size)
 {
+	struct page *page;
 	void * mem;
-	unsigned long adr, page;
+	unsigned long adr;
 
 	mem=vmalloc_32(size);
 	if (NULL == mem)
@@ -224,10 +178,9 @@
 		/* Clear the ram out, no junk to the user */
 		memset(mem, 0, size);
 	        adr=(unsigned long) mem;
-		while (size > 0) 
-                {
-	                page = kvirt_to_pa(adr);
-			mem_map_reserve(virt_to_page(__va(page)));
+		while (size > 0) {
+			page = vmalloc_to_page((void *)adr);
+			mem_map_reserve(page);
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -237,15 +190,14 @@
 
 static void rvfree(void * mem, signed long size)
 {
-        unsigned long adr, page;
+	struct page *page;
+        unsigned long adr;
         
-	if (mem) 
-	{
+	if (mem) {
 	        adr=(unsigned long) mem;
-		while (size > 0) 
-                {
-	                page = kvirt_to_pa(adr);
-			mem_map_unreserve(virt_to_page(__va(page)));
+		while (size > 0) {
+			page = vmalloc_to_page((void *)adr);
+			mem_map_unreserve(page);
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -290,8 +242,10 @@
 
 static void audio(struct bttv *btv, int mode)
 {
-	btaor(bttv_tvcards[btv->type].gpiomask, ~bttv_tvcards[btv->type].gpiomask,
-              BT848_GPIO_OUT_EN);
+	if (bttv_tvcards[btv->type].gpiomask)
+		btaor(bttv_tvcards[btv->type].gpiomask,
+		      ~bttv_tvcards[btv->type].gpiomask,
+		      BT848_GPIO_OUT_EN);
 
 	switch (mode)
 	{
@@ -318,8 +272,10 @@
 	        mode=AUDIO_OFF;
         if ((mode == AUDIO_TUNER) && (btv->radio))
 		mode = AUDIO_RADIO;
-	btaor(bttv_tvcards[btv->type].audiomux[mode],
-              ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
+	if (bttv_tvcards[btv->type].gpiomask)
+		btaor(bttv_tvcards[btv->type].audiomux[mode],
+		      ~bttv_tvcards[btv->type].gpiomask,
+		      BT848_GPIO_DATA);
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,audio_modes[mode]);
 	if (!in_interrupt())
@@ -435,8 +391,10 @@
 static void bt848_muxsel(struct bttv *btv, unsigned int input)
 {
         /* needed by RemoteVideo MX */
-	btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_tvcards[btv->type].gpiomask2,
-              BT848_GPIO_OUT_EN);
+	if (bttv_tvcards[btv->type].gpiomask2)
+		btaor(bttv_tvcards[btv->type].gpiomask2,
+		      ~bttv_tvcards[btv->type].gpiomask2,
+		      BT848_GPIO_OUT_EN);
 
 	/* This seems to get rid of some synchronization problems */
 	btand(~(3<<5), BT848_IFORM);
@@ -458,12 +416,14 @@
 	audio(btv, (input!=bttv_tvcards[btv->type].tuner) ?
               AUDIO_EXTERN : AUDIO_TUNER);
 
-	btaor(bttv_tvcards[btv->type].muxsel[input]>>4,
-		~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
+	if (bttv_tvcards[btv->type].gpiomask2)
+		btaor(bttv_tvcards[btv->type].muxsel[input]>>4,
+		      ~bttv_tvcards[btv->type].gpiomask2,
+		      BT848_GPIO_DATA);
 
 	/* card specific hook */
-	if( bttv_tvcards[btv->type].muxsel_hook )
-		bttv_tvcards[btv->type].muxsel_hook ( btv, input );
+	if (bttv_tvcards[btv->type].muxsel_hook)
+		bttv_tvcards[btv->type].muxsel_hook(btv, input);
 
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,"muxsel");
@@ -1583,7 +1543,7 @@
 		bt848_muxsel(btv, v.channel);
 		btv->channel=v.channel;
 		if (btv->win.norm != v.norm) {
-			if(btv->type== BTTV_VOODOOTV_FM)
+			if (btv->type == BTTV_VOODOOTV_FM)
 				bttv_tda9880_setnorm(btv,v.norm);
 			btv->win.norm = v.norm;
 			make_vbitab(btv);
@@ -1874,8 +1834,8 @@
 		bttv_call_i2c_clients(btv,cmd,&v);
 
 		/* card specific hooks */
-		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,&v,0);
+		if (btv->audio_hook)
+			btv->audio_hook(btv,&v,0);
 
 		if(copy_to_user(arg,&v,sizeof(v)))
 			return -EFAULT;
@@ -1902,8 +1862,8 @@
 		bttv_call_i2c_clients(btv,cmd,&v);
 		
 		/* card specific hooks */
-		if (bttv_tvcards[btv->type].audio_hook)
-			bttv_tvcards[btv->type].audio_hook(btv,&v,1);
+		if (btv->audio_hook)
+			btv->audio_hook(btv,&v,1);
 
 		btv->audio_dev=v;
 		up(&btv->lock);
@@ -2483,27 +2443,22 @@
 		bt848_dma(btv, 0);
 }
 
-# define do_video_register(dev,type,nr) video_register_device(dev,type,nr)
-
 static int __devinit init_video_dev(struct bttv *btv)
 {
 	audio(btv, AUDIO_MUTE);
         
-	if(do_video_register(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+	if (video_register_device(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
 		return -1;
 	printk(KERN_INFO "bttv%d: registered device video%d\n",
 	       btv->nr,btv->video_dev.minor & 0x1f);
-	if(do_video_register(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) 
-        {
+	if (video_register_device(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) {
 	        video_unregister_device(&btv->video_dev);
 		return -1;
 	}
 	printk(KERN_INFO "bttv%d: registered device vbi%d\n",
 	       btv->nr,btv->vbi_dev.minor & 0x1f);
-	if (btv->has_radio)
-	{
-		if(do_video_register(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) 
-                {
+	if (btv->has_radio) {
+		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) {
 		        video_unregister_device(&btv->vbi_dev);
 		        video_unregister_device(&btv->video_dev);
 			return -1;
@@ -2524,13 +2479,14 @@
 
 	/* dump current state of the gpio registers before changing them,
 	 * might help to make a new card work */
-	if (bttv_gpio)
+	if (bttv_gpio) {
 		bttv_gpio_tracking(btv,"init #1");
+		bttv_gpio_tracking(btv,"init #1");
+	}
 
 	/* reset the bt848 */
 	btwrite(0, BT848_SRESET);
-	DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n", btv->nr, (unsigned long) btv->bt848_mem));
-
+	
 	/* not registered yet */
 	btv->video_dev.minor = -1;
 	btv->radio_dev.minor = -1;
@@ -2973,12 +2929,17 @@
         else
                 btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
+	if (-1 != latency) {
+		printk(KERN_INFO "bttv%d: setting pci latency timer to %d\n",
+		       bttv_num,latency);
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
+	}
         pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
         pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
         printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %02x:%02x.%x, ",
                bttv_num,btv->id, btv->revision, dev->bus->number,
 	       PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));
-        printk("irq: %d, latency: %d, memory: 0x%lx\n",
+        printk("irq: %d, latency: %d, mmio: 0x%lx\n",
 	       btv->dev->irq, lat, btv->bt848_adr);
 	
 	bttv_idcard(btv);
diff -urN linux-2.4.20-pre1/drivers/media/video/bttv-if.c linux-2.4.20-pre2/drivers/media/video/bttv-if.c
--- linux-2.4.20-pre1/drivers/media/video/bttv-if.c	Wed Oct 17 14:19:20 2001
+++ linux-2.4.20-pre2/drivers/media/video/bttv-if.c	Mon Aug 12 16:34:16 2002
@@ -41,11 +41,13 @@
 static struct i2c_client bttv_i2c_client_template;
 
 EXPORT_SYMBOL(bttv_get_cardinfo);
+EXPORT_SYMBOL(bttv_get_pcidev);
 EXPORT_SYMBOL(bttv_get_id);
 EXPORT_SYMBOL(bttv_gpio_enable);
 EXPORT_SYMBOL(bttv_read_gpio);
 EXPORT_SYMBOL(bttv_write_gpio);
 EXPORT_SYMBOL(bttv_get_gpio_queue);
+EXPORT_SYMBOL(bttv_i2c_call);
 
 /* ----------------------------------------------------------------------- */
 /* Exported functions - for other modules which want to access the         */
@@ -62,6 +64,13 @@
 	return 0;
 }
 
+struct pci_dev* bttv_get_pcidev(unsigned int card)
+{
+	if (card >= bttv_num)
+		return NULL;
+	return bttvs[card].dev;
+}
+
 int bttv_get_id(unsigned int card)
 {
 	printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n");
@@ -245,6 +254,13 @@
 	}
 }
 
+void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
+{
+	if (card >= bttv_num)
+		return;
+	bttv_call_i2c_clients(&bttvs[card], cmd, arg);
+}
+
 static struct i2c_algo_bit_data bttv_i2c_algo_template = {
 	setsda:  bttv_bit_setsda,
 	setscl:  bttv_bit_setscl,
diff -urN linux-2.4.20-pre1/drivers/media/video/bttv.h linux-2.4.20-pre2/drivers/media/video/bttv.h
--- linux-2.4.20-pre1/drivers/media/video/bttv.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/bttv.h	Mon Aug 12 16:34:16 2002
@@ -90,6 +90,7 @@
 #define BTTV_SENSORAY311    0x49
 #define BTTV_RV605          0x4a
 #define BTTV_WINDVR         0x4c
+#define BTTV_HAUPPAUGEPVR   0x50
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -174,6 +175,7 @@
    returns negative value if error occurred 
 */
 extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid);
+extern struct pci_dev* bttv_get_pcidev(unsigned int card);
 
 /* obsolete, use bttv_get_cardinfo instead */
 extern int bttv_get_id(unsigned int card);
@@ -208,6 +210,11 @@
 */
 extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
 
+/* call i2c clients
+*/
+extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg);
+
+
 /* i2c */
 #define I2C_CLIENTS_MAX 16
 extern void bttv_bit_setscl(void *data, int state);
diff -urN linux-2.4.20-pre1/drivers/media/video/bttvp.h linux-2.4.20-pre2/drivers/media/video/bttvp.h
--- linux-2.4.20-pre1/drivers/media/video/bttvp.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/bttvp.h	Mon Aug 12 16:34:16 2002
@@ -25,8 +25,7 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,91)
-
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,96)
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -49,6 +48,7 @@
 extern unsigned int bttv_gpio;
 extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
 extern int init_bttv_i2c(struct bttv *btv);
+extern int pvr_boot(struct bttv *btv);
 
 #define dprintk		if (bttv_debug) printk
 
@@ -195,6 +195,7 @@
 
 	wait_queue_head_t gpioq;
 	int shutdown;
+        void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
 };
 #endif
 
diff -urN linux-2.4.20-pre1/drivers/media/video/cpia_usb.c linux-2.4.20-pre2/drivers/media/video/cpia_usb.c
--- linux-2.4.20-pre1/drivers/media/video/cpia_usb.c	Thu Oct 25 13:53:47 2001
+++ linux-2.4.20-pre2/drivers/media/video/cpia_usb.c	Mon Aug 12 16:34:16 2002
@@ -46,7 +46,7 @@
 
 struct cpia_sbuf {
 	char *data;
-	urb_t *urb;
+	struct urb *urb;
 };
 
 #define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
@@ -168,7 +168,7 @@
 static int cpia_usb_open(void *privdata)
 {
 	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
-	urb_t *urb;
+	struct urb *urb;
 	int ret, retval = 0, fx, err;
   
 	if (!ucpia)
diff -urN linux-2.4.20-pre1/drivers/media/video/msp3400.c linux-2.4.20-pre2/drivers/media/video/msp3400.c
--- linux-2.4.20-pre1/drivers/media/video/msp3400.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/msp3400.c	Mon Aug 12 16:34:16 2002
@@ -1266,6 +1266,7 @@
 
 	if (-1 == msp3400c_reset(c)) {
 		kfree(msp);
+		kfree(c);
 		dprintk("msp3400: no chip found\n");
 		return -1;
 	}
@@ -1275,6 +1276,7 @@
 		rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
 	if ((-1 == rev1) || (0 == rev1 && 0 == rev2)) {
 		kfree(msp);
+		kfree(c);
 		printk("msp3400: error while reading chip version\n");
 		return -1;
 	}
diff -urN linux-2.4.20-pre1/drivers/media/video/pms.c linux-2.4.20-pre2/drivers/media/video/pms.c
--- linux-2.4.20-pre1/drivers/media/video/pms.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/pms.c	Mon Aug 12 16:34:16 2002
@@ -11,7 +11,7 @@
  *
  *	Most of this code is directly derived from his userspace driver.
  *	His driver works so send any reports to alan@redhat.com unless the
- *	userspace driver also doesnt work for you...
+ *	userspace driver also doesn't work for you...
  */
 
 #include <linux/module.h>
diff -urN linux-2.4.20-pre1/drivers/media/video/tda7432.c linux-2.4.20-pre2/drivers/media/video/tda7432.c
--- linux-2.4.20-pre1/drivers/media/video/tda7432.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/tda7432.c	Mon Aug 12 16:34:16 2002
@@ -18,8 +18,12 @@
  *
  * loudness - set between 0 and 15 for varying degrees of loudness effect
  *
+ * maxvol   - set maximium volume to +20db (1), default is 0db(0)
  *
  *
+ *  Revision: 0.7 - maxvol module parm to set maximium volume 0db or +20db
+ *  				store if muted so we can return it
+ *  				change balance only if flaged to
  *  Revision: 0.6 - added tone controls
  *  Revision: 0.5 - Fixed odd balance problem
  *  Revision: 0.4 - added muting
@@ -54,6 +58,9 @@
 
 MODULE_PARM(debug,"i");
 MODULE_PARM(loudness,"i");
+MODULE_PARM_DESC(maxvol,"Set maximium volume to +20db (0), default is 0db(1)");
+MODULE_PARM(maxvol,"i");
+static int maxvol = 0;
 static int loudness = 0; /* disable loudness by default */
 static int debug = 0;	 /* insmod parameter */
 
@@ -81,12 +88,12 @@
 	int addr;
 	int input;
 	int volume;
+	int muted;
 	int bass, treble;
 	int lf, lr, rf, rr;
 	int loud;
 	struct i2c_client c;
 };
-
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
@@ -291,9 +298,10 @@
 	t->input  = TDA7432_STEREO_IN |  /* Main (stereo) input   */
 		    TDA7432_BASS_SYM  |  /* Symmetric bass cut    */
 		    TDA7432_BASS_NORM;   /* Normal bass range     */ 
-	t->volume = TDA7432_VOL_0DB;	 /* 0dB Volume            */
+	t->volume =  0x3b ;				 /* -27dB Volume            */
 	if (loudness)			 /* Turn loudness on?     */
 		t->volume |= TDA7432_LD_ON;	
+	t->muted    = VIDEO_AUDIO_MUTE;
 	t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
 	t->bass		= TDA7432_BASS_0DB; 	 /* 0dB Bass              */
 	t->lf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
@@ -374,17 +382,24 @@
 
 		va->flags |= VIDEO_AUDIO_VOLUME |
 			VIDEO_AUDIO_BASS |
-			VIDEO_AUDIO_TREBLE;
+			VIDEO_AUDIO_TREBLE |
+			VIDEO_AUDIO_MUTABLE;
+		if (t->muted)
+			va->flags |= VIDEO_AUDIO_MUTE;
 		va->mode |= VIDEO_SOUND_STEREO;
 		/* Master volume control
 		 * V4L volume is min 0, max 65535
 		 * TDA7432 Volume: 
 		 * Min (-79dB) is 0x6f
-		 * Max (+20dB) is 0x07
+		 * Max (+20dB) is 0x07 (630)
+		 * Max (0dB) is 0x20 (829)
 		 * (Mask out bit 7 of vol - it's for the loudness setting)
 		 */
-
-		va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
+		if(!maxvol){  /* max +20db */
+			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
+		} else {     /* max 0db   */
+			va->volume = (int )(( 0x6f - (t->volume & 0x7F) ) * 829.557);
+		}
 		
 		/* Balance depends on L,R attenuation
 		 * V4L balance is 0 to 65535, middle is 32768
@@ -401,15 +416,15 @@
 			/* left is attenuated, balance shifted right */
 			va->balance = (32768 + 1057*(t->lf));
 		
-		/* Bass/treble */	
+		/* Bass/treble 4 bits each */	
 		va->bass=t->bass;
 		if(va->bass >= 0x8)
-				va->bass = ~(va->bass - 0x8) & 0xf;
-		va->bass = va->bass << 12;
+			va->bass = ~(va->bass - 0x8) & 0xf;
+		va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass);
 		va->treble=t->treble;
 		if(va->treble >= 0x8)
-				va->treble = ~(va->treble - 0x8) & 0xf;
-		va->treble = va->treble << 12;
+			va->treble = ~(va->treble - 0x8) & 0xf;
+		va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble);
 								
 		break; /* VIDIOCGAUDIO case */
 	}
@@ -420,26 +435,36 @@
 		struct video_audio *va = arg;
 		dprintk("tda7432: VIDEOCSAUDIO\n");
 
-		t->volume = 0x6f - ( (va->volume)/630 );
+		if(va->flags & VIDEO_AUDIO_VOLUME){
+				
+			if(!maxvol){ /* max +20db */
+				t->volume = 0x6f - ( (va->volume)/630 );
+			} else {    /* max 0db   */
+				t->volume = 0x6f - ((int) (va->volume)/829.557 );
+			}
 		
 		if (loudness)		/* Turn on the loudness bit */
 			t->volume |= TDA7432_LD_ON;
 		
+			tda7432_write(client,TDA7432_VL, t->volume);
+		}
+		
 		if(va->flags & VIDEO_AUDIO_BASS)
 		{
 			t->bass = va->bass >> 12;
 			if(t->bass>= 0x8)
 					t->bass = (~t->bass & 0xf) + 0x8 ;
-			t->bass = t->bass | 0x10;
 		}
 		if(va->flags & VIDEO_AUDIO_TREBLE)
 		{
 			t->treble= va->treble >> 12;
 			if(t->treble>= 0x8)
 					t->treble = (~t->treble & 0xf) + 0x8 ;
-						
 		}
+		if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS))
+			tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
 		
+		if(va->flags & VIDEO_AUDIO_BALANCE)	{
 		if (va->balance < 32768) 
 		{
 			/* shifted to left, attenuate right */
@@ -464,20 +489,17 @@
 			t->lf = TDA7432_ATTEN_0DB;
 			t->lr = TDA7432_ATTEN_0DB;
 		}
+		}
 					
-		tda7432_write(client,TDA7432_TN, (t->bass << 4)| t->treble );		
-		tda7432_write(client,TDA7432_VL, t->volume);
-		
-		if (va->flags & VIDEO_AUDIO_MUTE)
+	 	t->muted=(va->flags & VIDEO_AUDIO_MUTE);	
+		if (t->muted)
 		{
 			/* Mute & update balance*/	
 			tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
 			tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
 			tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
 			tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
-		}
-		else
-		{	
+		} else {
 			tda7432_write(client,TDA7432_LF, t->lf);
 			tda7432_write(client,TDA7432_LR, t->lr);
 			tda7432_write(client,TDA7432_RF, t->rf);
diff -urN linux-2.4.20-pre1/drivers/media/video/tda9875.c linux-2.4.20-pre2/drivers/media/video/tda9875.c
--- linux-2.4.20-pre1/drivers/media/video/tda9875.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/tda9875.c	Mon Aug 12 16:34:16 2002
@@ -28,6 +28,7 @@
 #include <linux/videodev.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
 
 #include "bttv.h"
 #include "audiochip.h"
diff -urN linux-2.4.20-pre1/drivers/media/video/tuner.c linux-2.4.20-pre2/drivers/media/video/tuner.c
--- linux-2.4.20-pre1/drivers/media/video/tuner.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/tuner.c	Mon Aug 12 16:34:16 2002
@@ -101,10 +101,16 @@
 
 /* system switching for Philips FI1216MF MK2
    from datasheet "1996 Jul 09",
+    standard         BG     L      L'
+    picture carrier  38.90  38.90  33.95
+    colour	     34.47  34.37  38.38
+    sound 1          33.40  32.40  40.45
+    sound 2          33.16  -      -
+    NICAM            33.05  33.05  39.80
  */
 #define PHILIPS_MF_SET_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
-#define PHILIPS_MF_SET_PAL_L	0x03
-#define PHILIPS_MF_SET_PAL_L2	0x02
+#define PHILIPS_MF_SET_PAL_L	0x03 // France
+#define PHILIPS_MF_SET_PAL_L2	0x02 // L'
 
 
 /* ---------------------------------------------------------------------- */
@@ -132,16 +138,16 @@
 static struct tunertype tuners[] = {
         { "Temic PAL (4002 FH5)", TEMIC, PAL,
 	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
-	{ "Philips PAL_I", Philips, PAL_I,
+	{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
 	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-	{ "Philips NTSC", Philips, NTSC,
+	{ "Philips NTSC (FI1236 and compatibles)", Philips, NTSC,
 	  16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
-	{ "Philips SECAM", Philips, SECAM,
+	{ "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM,
 	  16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623},
 
 	{ "NoTuner", NoTuner, NOTUNER,
 	  0,0,0x00,0x00,0x00,0x00,0x00},
-	{ "Philips PAL", Philips, PAL,
+	{ "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL,
 	  16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623},
 	{ "Temic NTSC (4032 FY5)", TEMIC, NTSC,
 	  16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
@@ -181,7 +187,7 @@
           16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
         { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
           16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Philips PAL_DK", Philips, PAL,
+        { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
 
 	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
@@ -200,7 +206,7 @@
 	{ "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL,
 	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
 	{ "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
-	  16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940},
+	  16*137.25,16*317.25,0x01,0x02,0x08,0x8e,732 }, // Corrected to NTSC=732 (was:940)
 
 	{ "Samsung PAL TCPM9091PD27", Samsung, PAL,  /* from sourceforge v3tv */
           16*169,16*464,0xA0,0x90,0x30,0x8e,623},
@@ -215,7 +221,10 @@
           16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
         { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
           16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
-	
+	{ "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
+	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
+	{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
+          16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
 };
 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
 
@@ -253,7 +262,7 @@
 	return (tuner_getstatus (c) & TUNER_STEREO);
 }
 
-
+#if 0 /* unused */
 static int tuner_islocked (struct i2c_client *c)
 {
         return (tuner_getstatus (c) & TUNER_FL);
@@ -264,12 +273,12 @@
         return (tuner_getstatus (c) & TUNER_AFC) - 2;
 }
 
-#if 0 /* unused */
 static int tuner_mode (struct i2c_client *c)
 {
         return (tuner_getstatus (c) & TUNER_MODE) >> 3;
 }
 #endif
+
 // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
 static int mt2032_init(struct i2c_client *c)
 {
@@ -620,7 +629,7 @@
 
 	/* tv norm specific stuff for multi-norm tuners */
 	switch (t->type) {
-	case TUNER_PHILIPS_SECAM:
+	case TUNER_PHILIPS_SECAM: // FI1216MF
 		/* 0x01 -> ??? no change ??? */
 		/* 0x02 -> PAL BDGHI / SECAM L */
 		/* 0x04 -> ??? PAL others / SECAM others ??? */
@@ -651,8 +660,9 @@
 		default:
 			config |= TEMIC_SET_PAL_BG;
 			break;
-		break;
 		}
+		break;
+
 	case TUNER_PHILIPS_FQ1216ME:
 		config &= ~0x0f;
 		switch (pal[0]) {
@@ -672,8 +682,8 @@
 		case 'G':
 			config |= PHILIPS_SET_PAL_BGDK;
 			break;
-		break;
 		}
+		break;
 	}
 
 	
@@ -703,6 +713,8 @@
 		buffer[2] = tun->config;
 		buffer[3] = config;
 	}
+	dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		buffer[0],buffer[1],buffer[2],buffer[3]);
 
         if (4 != (rc = i2c_master_send(c,buffer,4)))
                 printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
@@ -720,12 +732,10 @@
 
 static void set_radio_freq(struct i2c_client *c, int freq)
 {
-	u8 config;
-	u16 div;
 	struct tunertype *tun;
 	struct tuner *t = (struct tuner*)c->data;
         unsigned char buffer[4];
-	int rc;
+	int rc,div;
 
 	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
 		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",
@@ -744,35 +754,27 @@
 	}
 
 	tun=&tuners[t->type];
-	config = 0xa4 /* 0xa5 */; /* bit 0 is AFC (set) vs. RF-Signal (clear) */
-	div=freq + (int)(16*10.7);
-  	div&=0x7fff;
-
+	div = freq + (int)(16*10.7);
         buffer[0] = (div>>8) & 0x7f;
         buffer[1] = div      & 0xff;
-        buffer[2] = tun->config;
-        buffer[3] = config;
-        if (4 != (rc = i2c_master_send(c,buffer,4)))
-                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
+	buffer[2] = tun->config;
+	switch (t->type) {
+	case TUNER_PHILIPS_FM1216ME_MK3:
+		buffer[3] = 0x19;
+		break;
+	default:
+		buffer[3] = 0xa4;
+		break;
+	}
 
-	if (debug) {
-		current->state   = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ/10);
-		
-		if (tuner_islocked (c))
-			printk ("tuner: PLL locked\n");
-		else
-			printk ("tuner: PLL not locked\n");
+	dprintk("tuner: radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		buffer[0],buffer[1],buffer[2],buffer[3]);
 
-		if (config & 1) {
-			printk ("tuner: AFC: %d\n", tuner_afcstatus(c));
-		} else {
-			printk ("tuner: Signal: %d\n", tuner_signal(c));
-		}
-	}
+        if (4 != (rc = i2c_master_send(c,buffer,4)))
+                printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
 }
-/* ---------------------------------------------------------------------- */
 
+/* ---------------------------------------------------------------------- */
 
 static int tuner_attach(struct i2c_adapter *adap, int addr,
 			unsigned short flags, int kind)
@@ -824,6 +826,7 @@
 	this_adap = 0;
 	switch (adap->id) {
 	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
 	case I2C_ALGO_SAA7134:
 		printk("tuner: probing %s i2c adapter [id=0x%x]\n",
 		       adap->name,adap->id);
@@ -988,7 +991,6 @@
 
 module_init(tuner_init_module);
 module_exit(tuner_cleanup_module);
-EXPORT_NO_SYMBOLS;
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -urN linux-2.4.20-pre1/drivers/media/video/tuner.h linux-2.4.20-pre2/drivers/media/video/tuner.h
--- linux-2.4.20-pre1/drivers/media/video/tuner.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/tuner.h	Mon Aug 12 16:34:16 2002
@@ -62,6 +62,9 @@
 #define TUNER_TEMIC_4012FY5	35	/* 4012 FY5 (3X 0971, 1099)*/
 #define TUNER_TEMIC_4136FY5	36	/* 4136 FY5 (3X 7708, 7746)*/
 #define TUNER_LG_PAL_NEW_TAPC   37
+#define TUNER_PHILIPS_FM1216ME_MK3  38
+#define TUNER_LG_NTSC_NEW_TAPC   39
+
 
 
 
diff -urN linux-2.4.20-pre1/drivers/media/video/tvaudio.c linux-2.4.20-pre2/drivers/media/video/tvaudio.c
--- linux-2.4.20-pre1/drivers/media/video/tvaudio.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/tvaudio.c	Mon Aug 12 16:34:16 2002
@@ -1070,10 +1070,46 @@
 #define TDA8425_S1         0x08  /* switch functions */
                                  /* values for those registers: */
 #define TDA8425_S1_OFF     0xEE  /* audio off (mute on) */
-#define TDA8425_S1_ON      0xCE  /* audio on (mute off) - "linear stereo" mode */
+#define TDA8425_S1_CH1     0xCE  /* audio channel 1 (mute off) - "linear stereo" mode */
+#define TDA8425_S1_CH2     0xCF  /* audio channel 2 (mute off) - "linear stereo" mode */
+#define TDA8425_S1_MU      0x20  /* mute bit */
+#define TDA8425_S1_STEREO  0x18  /* stereo bits */
+#define TDA8425_S1_STEREO_SPATIAL 0x18 /* spatial stereo */
+#define TDA8425_S1_STEREO_LINEAR  0x08 /* linear stereo */
+#define TDA8425_S1_STEREO_PSEUDO  0x10 /* pseudo stereo */
+#define TDA8425_S1_STEREO_MONO    0x00 /* forced mono */
+#define TDA8425_S1_ML      0x06        /* language selector */
+#define TDA8425_S1_ML_SOUND_A 0x02     /* sound a */
+#define TDA8425_S1_ML_SOUND_B 0x04     /* sound b */
+#define TDA8425_S1_ML_STEREO  0x06     /* stereo */
+#define TDA8425_S1_IS      0x01        /* channel selector */
 
-static int tda8425_shift10(int val) { return val >> 10 | 0xc0; }
-static int tda8425_shift12(int val) { return val >> 12 | 0xf0; }
+
+static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
+static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
+
+static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
+{
+	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
+	
+	if (mode & VIDEO_SOUND_LANG1) {
+		s1 |= TDA8425_S1_ML_SOUND_A;
+		s1 |= TDA8425_S1_STEREO_PSEUDO;
+
+	} else if (mode & VIDEO_SOUND_LANG2) {
+		s1 |= TDA8425_S1_ML_SOUND_B;
+		s1 |= TDA8425_S1_STEREO_PSEUDO;
+		
+	} else {
+		s1 |= TDA8425_S1_ML_STEREO;
+		
+		if (mode & VIDEO_SOUND_MONO)
+			s1 |= TDA8425_S1_STEREO_MONO;
+		if (mode & VIDEO_SOUND_STEREO)
+			s1 |= TDA8425_S1_STEREO_SPATIAL;
+	}
+	chip_write(chip,TDA8425_S1,s1);
+}
 
 
 /* ---------------------------------------------------------------------- */
@@ -1190,8 +1226,8 @@
 		registers:  11,
 		flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
 
-		leftreg:    TDA9855_VR,
-		rightreg:   TDA9855_VL,
+		leftreg:    TDA9855_VL,
+		rightreg:   TDA9855_VR,
 		bassreg:    TDA9855_BA,
 		treblereg:  TDA9855_TR,
 		volfunc:    tda9855_volume,
@@ -1258,8 +1294,10 @@
 		treblefunc: tda8425_shift12,
 
 		inputreg:   TDA8425_S1,
-		inputmap:   { TDA8425_S1_ON, TDA8425_S1_ON, TDA8425_S1_ON },
+		inputmap:   { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
 		inputmute:  TDA8425_S1_OFF,
+
+		setmode:    tda8425_setmode,
 	},
 	{
 		name:       "pic16c54 (PV951)",
@@ -1338,8 +1376,8 @@
 		chip_cmd(chip,"init",&desc->init);
 
 	if (desc->flags & CHIP_HAS_VOLUME) {
-		chip->left   = desc->leftinit   ? desc->leftinit   : 65536;
-		chip->right  = desc->rightinit  ? desc->rightinit  : 65536;
+		chip->left   = desc->leftinit   ? desc->leftinit   : 65535;
+		chip->right  = desc->rightinit  ? desc->rightinit  : 65535;
 		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
 		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
 	}
@@ -1367,9 +1405,14 @@
 
 static int chip_probe(struct i2c_adapter *adap)
 {
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+	switch (adap->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
 		return i2c_probe(adap, &addr_data, chip_attach);
-	return 0;
+	default:
+		/* ignore this i2c bus */
+		return 0;
+	}
 }
 
 static int chip_detach(struct i2c_client *client)
diff -urN linux-2.4.20-pre1/drivers/media/video/tvmixer.c linux-2.4.20-pre2/drivers/media/video/tvmixer.c
--- linux-2.4.20-pre1/drivers/media/video/tvmixer.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/tvmixer.c	Mon Aug 12 16:34:16 2002
@@ -215,7 +215,6 @@
 	return 0;
 }
 
-
 static struct i2c_driver driver = {
 	name:            "tv card mixer driver",
         id:              I2C_DRIVERID_TVMIXER,
@@ -254,7 +253,13 @@
 	int i,minor;
 
 	/* TV card ??? */
-	if (client->adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) {
+	switch (client->adapter->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+		/* ok, have a look ... */
+		break;
+	default:
+		/* ignore that one */
 		if (debug)
 			printk("tvmixer: %s is not a tv card\n",
 			       client->adapter->name);
diff -urN linux-2.4.20-pre1/drivers/media/video/zr36067.c linux-2.4.20-pre2/drivers/media/video/zr36067.c
--- linux-2.4.20-pre1/drivers/media/video/zr36067.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/media/video/zr36067.c	Mon Aug 12 16:34:16 2002
@@ -4163,7 +4163,6 @@
 		{
 			struct zoran_status bs;
 			int norm, input, status;
-			unsigned long timeout;
 
 			if (zr->codec_mode != BUZ_MODE_IDLE) {
 				DEBUG1(printk(KERN_ERR
diff -urN linux-2.4.20-pre1/drivers/message/i2o/i2o_pci.c linux-2.4.20-pre2/drivers/message/i2o/i2o_pci.c
--- linux-2.4.20-pre1/drivers/message/i2o/i2o_pci.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/message/i2o/i2o_pci.c	Mon Aug 12 16:34:16 2002
@@ -35,6 +35,7 @@
 
 static int dpt = 0;
 
+extern void i2o_sys_init(void);
 
 /**
  *	i2o_pci_dispose		-	Free bus specific resources
diff -urN linux-2.4.20-pre1/drivers/mtd/devices/blkmtd.c linux-2.4.20-pre2/drivers/mtd/devices/blkmtd.c
--- linux-2.4.20-pre1/drivers/mtd/devices/blkmtd.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.20-pre2/drivers/mtd/devices/blkmtd.c	Mon Aug 12 16:34:16 2002
@@ -225,7 +225,7 @@
     return err;
   }
 
-  /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ 
+  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
   blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
   if(blocks == NULL) {
@@ -320,7 +320,7 @@
     return 0;
   }
 
-  /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ 
+  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
   blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
   if(blocks == NULL) {
@@ -360,7 +360,7 @@
       int max_sectors = KIO_MAX_SECTORS >> (item->rawdevice->sector_bits - 9);
       kdev_t dev = to_kdev_t(item->rawdevice->binding->bd_dev);
 
-      /* If we are writing to the last page on the device and it doesnt end
+      /* If we are writing to the last page on the device and it doesn't end
        * on a page boundary, subtract the number of sectors that dont exist.
        */
       if(item->rawdevice->partial_last_page && 
diff -urN linux-2.4.20-pre1/drivers/net/3c505.c linux-2.4.20-pre2/drivers/net/3c505.c
--- linux-2.4.20-pre1/drivers/net/3c505.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.20-pre2/drivers/net/3c505.c	Mon Aug 12 16:34:16 2002
@@ -1397,7 +1397,7 @@
 	int timeout;
 	int addr = dev->base_addr;
 	const char *name = dev->name;
-	long flags;
+	unsigned long flags;
 	byte orig_HSR;
 
 	if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
diff -urN linux-2.4.20-pre1/drivers/net/3c509.c linux-2.4.20-pre2/drivers/net/3c509.c
--- linux-2.4.20-pre1/drivers/net/3c509.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/3c509.c	Mon Aug 12 16:34:16 2002
@@ -230,8 +230,6 @@
 };
 
 MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
-MODULE_LICENSE("GPL");
-
 
 static u16 el3_isapnp_phys_addr[8][3];
 static int nopnp;
@@ -1265,6 +1263,7 @@
 MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
 #endif	/* CONFIG_ISAPNP */
 MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B) ISA/PnP ethernet driver");
+MODULE_LICENSE("GPL");
 
 int
 init_module(void)
diff -urN linux-2.4.20-pre1/drivers/net/8139cp.c linux-2.4.20-pre2/drivers/net/8139cp.c
--- linux-2.4.20-pre1/drivers/net/8139cp.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/8139cp.c	Mon Aug 12 16:34:16 2002
@@ -18,23 +18,22 @@
 
 	See the file COPYING in this distribution for more information.
 
-	Contribuitors:
+	Contributors:
 	
 		Wake-on-LAN support - Felipe Damasio <felipewd@terra.com.br>
 		PCI suspend/resume  - Felipe Damasio <felipewd@terra.com.br>
 			
 	TODO, in rough priority order:
+	* Test Tx checksumming thoroughly
 	* dev->tx_timeout
 	* LinkChg interrupt
 	* Support forcing media type with a module parameter,
 	  like dl2k.c/sundance.c
 	* Constants (module parms?) for Rx work limit
-	* support 64-bit PCI DMA
 	* Complete reset on PciErr
 	* Consider Rx interrupt mitigation using TimerIntr
 	* Implement 8139C+ statistics dump; maybe not...
 	  h/w stats can be reset only by software reset
-	* Tx checksumming
 	* Handle netif_rx return value
 	* Investigate using skb->priority with h/w VLAN priority
 	* Investigate using High Priority Tx Queue with skb->priority
@@ -50,8 +49,8 @@
  */
 
 #define DRV_NAME		"8139cp"
-#define DRV_VERSION		"0.1.0"
-#define DRV_RELDATE		"Jun 14, 2002"
+#define DRV_VERSION		"0.2.1"
+#define DRV_RELDATE		"Aug 9, 2002"
 
 
 #include <linux/config.h>
@@ -67,9 +66,17 @@
 #include <linux/mii.h>
 #include <linux/if_vlan.h>
 #include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
+/* experimental TX checksumming feature enable/disable */
+#undef CP_TX_CHECKSUM
+
+/* VLAN tagging feature enable/disable */
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define CP_VLAN_TAG_USED 1
 #define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
@@ -188,8 +195,8 @@
 	NormalTxPoll	= (1 << 6),  /* One or more normal Tx packets to send */
 	PID1		= (1 << 17), /* 2 protocol id bits:  0==non-IP, */
 	PID0		= (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */
-	RxProtoTCP	= 2,
-	RxProtoUDP	= 1,
+	RxProtoTCP	= 1,
+	RxProtoUDP	= 2,
 	RxProtoIP	= 3,
 	TxFIFOUnder	= (1 << 25), /* Tx FIFO underrun */
 	TxOWC		= (1 << 22), /* Tx Out-of-window collision */
@@ -245,6 +252,7 @@
 	/* C+ mode command register */
 	RxVlanOn	= (1 << 6),  /* Rx VLAN de-tagging enable */
 	RxChkSum	= (1 << 5),  /* Rx checksum offload enable */
+	PCIDAC		= (1 << 4),  /* PCI Dual Address Cycle (64-bit PCI) */
 	PCIMulRW	= (1 << 3),  /* Enable PCI read/write multiple */
 	CpRxOn		= (1 << 1),  /* Rx mode enable */
 	CpTxOn		= (1 << 0),  /* Tx mode enable */
@@ -301,7 +309,7 @@
 
 struct ring_info {
 	struct sk_buff		*skb;
-	dma_addr_t		mapping;
+	dma64_addr_t		mapping;
 	unsigned		frag;
 };
 
@@ -357,6 +365,7 @@
 
 	struct sk_buff		*frag_skb;
 	unsigned		dropping_frag : 1;
+	unsigned		pci_using_dac : 1;
 	unsigned int		board_type;
 
 	unsigned int		wol_enabled : 1; /* Is Wake-on-LAN enabled? */
@@ -570,7 +579,7 @@
 
 	while (rx_work--) {
 		u32 status, len;
-		dma_addr_t mapping;
+		dma64_addr_t mapping;
 		struct sk_buff *skb, *new_skb;
 		struct cp_desc *desc;
 		unsigned buflen;
@@ -637,7 +646,8 @@
 		else
 			desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
 		cp->rx_ring[rx_tail].opts2 = 0;
-		cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping);
+		cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping & 0xffffffff);
+		cp->rx_ring[rx_tail].addr_hi = cpu_to_le32(mapping >> 32);
 		rx_tail = NEXT_RX(rx_tail);
 	}
 
@@ -768,22 +778,34 @@
 	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 	if (skb_shinfo(skb)->nr_frags == 0) {
 		struct cp_desc *txd = &cp->tx_ring[entry];
-		u32 mapping, len;
+		u32 len;
+		dma64_addr_t mapping;
 
 		len = skb->len;
 		mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
 		eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 		CP_VLAN_TX_TAG(txd, vlan_tag);
-		txd->addr_lo = cpu_to_le32(mapping);
+		txd->addr_lo = cpu_to_le32(mapping & 0xffffffff);
+		txd->addr_hi = cpu_to_le32(mapping >> 32);
 		wmb();
 
 #ifdef CP_TX_CHECKSUM
-		txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag |
-			LastFrag | IPCS | UDPCS | TCPCS);
-#else
-		txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag |
-			LastFrag);
+		if (skb->ip_summed == CHECKSUM_HW) {
+			const struct iphdr *ip = skb->nh.iph;
+			if (ip->protocol == IPPROTO_TCP)
+				txd->opts1 = cpu_to_le32(eor | len | DescOwn |
+							 FirstFrag | LastFrag |
+							 IPCS | TCPCS);
+			else if (ip->protocol == IPPROTO_UDP)
+				txd->opts1 = cpu_to_le32(eor | len | DescOwn |
+							 FirstFrag | LastFrag |
+							 IPCS | UDPCS);
+			else
+				BUG();
+		} else
 #endif
+			txd->opts1 = cpu_to_le32(eor | len | DescOwn |
+						 FirstFrag | LastFrag);
 		wmb();
 
 		cp->tx_skb[entry].skb = skb;
@@ -792,8 +814,12 @@
 		entry = NEXT_TX(entry);
 	} else {
 		struct cp_desc *txd;
-		u32 first_len, first_mapping;
+		u32 first_len;
+		dma64_addr_t first_mapping;
 		int frag, first_entry = entry;
+#ifdef CP_TX_CHECKSUM
+		const struct iphdr *ip = skb->nh.iph;
+#endif
 
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
@@ -808,8 +834,9 @@
 
 		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
 			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
-			u32 len, mapping;
+			u32 len;
 			u32 ctrl;
+			dma64_addr_t mapping;
 
 			len = this_frag->size;
 			mapping = pci_map_single(cp->pdev,
@@ -818,16 +845,25 @@
 						 len, PCI_DMA_TODEVICE);
 			eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 #ifdef CP_TX_CHECKSUM
-			ctrl = eor | len | DescOwn | IPCS | UDPCS | TCPCS;
-#else
-			ctrl = eor | len | DescOwn;
+			if (skb->ip_summed == CHECKSUM_HW) {
+				ctrl = eor | len | DescOwn | IPCS;
+				if (ip->protocol == IPPROTO_TCP)
+					ctrl |= TCPCS;
+				else if (ip->protocol == IPPROTO_UDP)
+					ctrl |= UDPCS;
+				else
+					BUG();
+			} else
 #endif
+				ctrl = eor | len | DescOwn;
+
 			if (frag == skb_shinfo(skb)->nr_frags - 1)
 				ctrl |= LastFrag;
 
 			txd = &cp->tx_ring[entry];
 			CP_VLAN_TX_TAG(txd, vlan_tag);
-			txd->addr_lo = cpu_to_le32(mapping);
+			txd->addr_lo = cpu_to_le32(mapping & 0xffffffff);
+			txd->addr_hi = cpu_to_le32(mapping >> 32);
 			wmb();
 
 			txd->opts1 = cpu_to_le32(ctrl);
@@ -841,14 +877,24 @@
 
 		txd = &cp->tx_ring[first_entry];
 		CP_VLAN_TX_TAG(txd, vlan_tag);
-		txd->addr_lo = cpu_to_le32(first_mapping);
+		txd->addr_lo = cpu_to_le32(first_mapping & 0xffffffff);
+		txd->addr_hi = cpu_to_le32(first_mapping >> 32);
 		wmb();
 
 #ifdef CP_TX_CHECKSUM
-		txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn | IPCS | UDPCS | TCPCS);
-#else
-		txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn);
+		if (skb->ip_summed == CHECKSUM_HW) {
+			if (ip->protocol == IPPROTO_TCP)
+				txd->opts1 = cpu_to_le32(first_len | FirstFrag |
+							DescOwn | IPCS | TCPCS);
+			else if (ip->protocol == IPPROTO_UDP)
+				txd->opts1 = cpu_to_le32(first_len | FirstFrag |
+							DescOwn | IPCS | UDPCS);
+			else
+				BUG();
+		} else
 #endif
+			txd->opts1 = cpu_to_le32(first_len | FirstFrag |
+						 DescOwn);
 		wmb();
 	}
 	cp->tx_head = entry;
@@ -975,10 +1021,11 @@
 
 static inline void cp_start_hw (struct cp_private *cp)
 {
+	u16 pci_dac = cp->pci_using_dac ? PCIDAC : 0;
 	if (cp->board_type == RTL8169)
-		cpw16(CpCmd, PCIMulRW | RxChkSum);
+		cpw16(CpCmd, pci_dac | PCIMulRW | RxChkSum);
 	else
-		cpw16(CpCmd, PCIMulRW | RxChkSum | CpRxOn | CpTxOn);
+		cpw16(CpCmd, pci_dac | PCIMulRW | RxChkSum | CpRxOn | CpTxOn);
 	cpw8(Cmd, RxOn | TxOn);
 }
 
@@ -1051,8 +1098,10 @@
 			cp->rx_ring[i].opts1 =
 				cpu_to_le32(DescOwn | cp->rx_buf_sz);
 		cp->rx_ring[i].opts2 = 0;
-		cp->rx_ring[i].addr_lo = cpu_to_le32(cp->rx_skb[i].mapping);
-		cp->rx_ring[i].addr_hi = 0;
+		cp->rx_ring[i].addr_lo =
+			cpu_to_le32(cp->rx_skb[i].mapping & 0xffffffff);
+		cp->rx_ring[i].addr_hi =
+			cpu_to_le32(cp->rx_skb[i].mapping >> 32);
 	}
 
 	return 0;
@@ -1716,7 +1765,7 @@
 	int rc;
 	void *regs;
 	long pciaddr;
-	unsigned addr_len, i;
+	unsigned int addr_len, i;
 	u8 pci_rev, cache_size;
 	u16 pci_command;
 	unsigned int board_type = (unsigned int) ent->driver_data;
@@ -1781,6 +1830,19 @@
 		goto err_out_res;
 	}
 
+	/* Configure DMA attributes. */
+	if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) {
+		cp->pci_using_dac = 1;
+	} else {
+		rc = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+		if (rc) {
+			printk(KERN_ERR PFX "No usable DMA configuration, "
+			       "aborting.\n");
+			goto err_out_res;
+		}
+		cp->pci_using_dac = 0;
+	}
+
 	regs = ioremap_nocache(pciaddr, CP_REGS_SIZE);
 	if (!regs) {
 		rc = -EIO;
diff -urN linux-2.4.20-pre1/drivers/net/8139too.c linux-2.4.20-pre2/drivers/net/8139too.c
--- linux-2.4.20-pre1/drivers/net/8139too.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/8139too.c	Mon Aug 12 16:34:16 2002
@@ -92,7 +92,7 @@
 */
 
 #define DRV_NAME	"8139too"
-#define DRV_VERSION	"0.9.25"
+#define DRV_VERSION	"0.9.26"
 
 
 #include <linux/config.h>
@@ -221,6 +221,8 @@
 	FE2000VX,
 	ALLIED8139,
 	RTL8129,
+	FNW3603TX,
+	FNW3800TX,
 } board_t;
 
 
@@ -240,6 +242,8 @@
 	{ "AboCom FE2000VX (RealTek RTL8139)", RTL8139_CAPS },
 	{ "Allied Telesyn 8139 CardBus", RTL8139_CAPS },
 	{ "RealTek RTL8129", RTL8129_CAPS },
+	{ "Planex FNW-3603-TX 10/100 CardBus", RTL8139_CAPS },
+	{ "Planex FNW-3800-TX 10/100 CardBus", RTL8139_CAPS },
 };
 
 
@@ -254,6 +258,8 @@
 	{0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE690TXD },
 	{0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FE2000VX },
 	{0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALLIED8139 },
+	{0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3603TX },
+	{0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3800TX },
 
 #ifdef CONFIG_8139TOO_8129
 	{0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
@@ -456,7 +462,7 @@
 
 
 /* Twister tuning parameters from RealTek.
-   Completely undocumented, but required to tune bad links. */
+   Completely undocumented, but required to tune bad links on some boards. */
 enum CSCRBits {
 	CSCR_LinkOKBit = 0x0400,
 	CSCR_LinkChangeBit = 0x0800,
@@ -471,10 +477,14 @@
 	Cfg9346_Unlock = 0xC0,
 };
 
+#ifdef CONFIG_8139TOO_TUNE_TWISTER
+
+enum TwisterParamVals {
+	PARA78_default	= 0x78fa8388,
+	PARA7c_default	= 0xcb38de43,	/* param[0][3] */
+	PARA7c_xxx	= 0xcb38de43,
+};
 
-#define PARA78_default	0x78fa8388
-#define PARA7c_default	0xcb38de43	/* param[0][3] */
-#define PARA7c_xxx		0xcb38de43
 static const unsigned long param[4][4] = {
 	{0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
 	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
@@ -482,6 +492,8 @@
 	{0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
 };
 
+#endif /* CONFIG_8139TOO_TUNE_TWISTER */
+
 typedef enum {
 	CH_8139 = 0,
 	CH_8139_K,
@@ -1296,7 +1308,7 @@
 
 	tp->mii.full_duplex = tp->mii.duplex_lock;
 	tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
-	tp->twistie = 1;
+	tp->twistie = (tp->chipset == CH_8139_K) ? 1 : 0;
 	tp->time_to_die = 0;
 
 	rtl8139_init_ring (dev);
@@ -1778,7 +1790,7 @@
 			    struct rtl8139_private *tp, void *ioaddr)
 {
 	u8 tmp8;
-#ifndef CONFIG_8139_NEW_RX_RESET
+#ifdef CONFIG_8139_OLD_RX_RESET
 	int tmp_work;
 #endif
 
@@ -1801,7 +1813,7 @@
 		tp->xstats.rx_lost_in_ring++;
 	}
 
-#ifdef CONFIG_8139_NEW_RX_RESET
+#ifndef CONFIG_8139_OLD_RX_RESET
 	tmp8 = RTL_R8 (ChipCmd);
 	RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
 	RTL_W8 (ChipCmd, tmp8);
@@ -2612,13 +2624,13 @@
 
 
 static struct pci_driver rtl8139_pci_driver = {
-	name:		DRV_NAME,
-	id_table:	rtl8139_pci_tbl,
-	probe:		rtl8139_init_one,
-	remove:		__devexit_p(rtl8139_remove_one),
+	.name		= DRV_NAME,
+	.id_table	= rtl8139_pci_tbl,
+	.probe		= rtl8139_init_one,
+	.remove		= __devexit_p(rtl8139_remove_one),
 #ifdef CONFIG_PM
-	suspend:	rtl8139_suspend,
-	resume:		rtl8139_resume,
+	.suspend	= rtl8139_suspend,
+	.resume		= rtl8139_resume,
 #endif /* CONFIG_PM */
 };
 
diff -urN linux-2.4.20-pre1/drivers/net/Config.in linux-2.4.20-pre2/drivers/net/Config.in
--- linux-2.4.20-pre1/drivers/net/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/Config.in	Mon Aug 12 16:34:16 2002
@@ -129,7 +129,7 @@
       tristate '    EtherExpress 16 support' CONFIG_EEXPRESS
       tristate '    EtherExpressPro support/EtherExpress 10 (i82595) support' CONFIG_EEXPRESS_PRO
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
-         tristate '    FMV-181/182/183/184 support' CONFIG_FMV18X
+         tristate '    FMV-181/182/183/184 support (OBSOLETE)' CONFIG_FMV18X
       fi
       tristate '    HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
       tristate '    HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
@@ -177,18 +177,15 @@
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
       dep_tristate '    National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
-      if [ "$CONFIG_NATSEMI" = "y" -o "$CONFIG_NATSEMI" = "m" ]; then
-        bool       '      NatSemi workaround for high errors' CONFIG_NATSEMI_CABLE_MAGIC
-      fi
       dep_tristate '    PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI
       dep_tristate '    Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_8139CP $CONFIG_PCI $CONFIG_EXPERIMENTAL
       dep_tristate '    RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI
       dep_mbool '      Use PIO instead of MMIO' CONFIG_8139TOO_PIO $CONFIG_8139TOO
-      dep_mbool '      Support for automatic channel equalization (EXPERIMENTAL)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO $CONFIG_EXPERIMENTAL
+      dep_mbool '      Support for uncommon RTL-8139 rev. K (automatic channel equalization)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO
       dep_mbool '      Support for older RTL-8129/8130 boards' CONFIG_8139TOO_8129 $CONFIG_8139TOO
-      dep_mbool '      Experiment for better RX reset (EXPERIMENTAL)' CONFIG_8139_NEW_RX_RESET $CONFIG_8139TOO $CONFIG_EXPERIMENTAL
+      dep_mbool '      Use older RX-reset method' CONFIG_8139_OLD_RX_RESET $CONFIG_8139TOO
       dep_tristate '    SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI
       dep_tristate '    SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI
       dep_tristate '    Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI
@@ -200,7 +197,7 @@
       dep_mbool '      Use MMIO instead of PIO (EXPERIMENTAL)' CONFIG_VIA_RHINE_MMIO $CONFIG_VIA_RHINE $CONFIG_EXPERIMENTAL
       dep_tristate '    Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
-	 dep_bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET $CONFIG_ISA
+	 dep_bool '    Zenith Z-Note support (OBSOLETE)' CONFIG_ZNET $CONFIG_ISA
       fi
       if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_MIPS" = "y" ]; then
 	 bool '    Philips SAA9730 Ethernet support (EXPERIMENTAL)' CONFIG_LAN_SAA9730
@@ -268,9 +265,9 @@
    if [ "$CONFIG_INET" = "y" ]; then
       bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
       if [ "$CONFIG_HIPPI" = "y" -a "$CONFIG_PCI" = "y" ]; then
-         dep_tristate '  Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER $CONFIG_PCI
+         dep_tristate '  Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)' CONFIG_ROADRUNNER $CONFIG_PCI
          if [ "$CONFIG_ROADRUNNER" != "n" ]; then
-   	    bool '    Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
+   	    bool '    Use large TX/RX rings (EXPERIMENTAL)' CONFIG_ROADRUNNER_LARGE_RINGS
          fi
       fi
    fi
@@ -309,7 +306,7 @@
    dep_tristate '  STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
    tristate '  AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
    if [ "$CONFIG_X86_64" != "y" ]; then
-   tristate '  Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
+      tristate '  Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
    fi
    tristate '  Aironet 4500/4800 series adapters' CONFIG_AIRONET4500
    dep_tristate '   Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500
diff -urN linux-2.4.20-pre1/drivers/net/acenic.c linux-2.4.20-pre2/drivers/net/acenic.c
--- linux-2.4.20-pre1/drivers/net/acenic.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/acenic.c	Mon Aug 12 16:34:16 2002
@@ -1164,14 +1164,8 @@
 	 * This will most likely need BYTE_SWAP once we switch
 	 * to using __raw_writel()
 	 */
-#ifdef __parisc__
-	writel((WORD_SWAP | BYTE_SWAP | CLR_INT |
-		((WORD_SWAP | BYTE_SWAP | CLR_INT) << 24)),
-	       &regs->HostCtrl);
-#else
 	writel((WORD_SWAP | CLR_INT | ((WORD_SWAP | CLR_INT) << 24)),
 	       &regs->HostCtrl);
-#endif
 #else
 	writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)),
 	       &regs->HostCtrl);
diff -urN linux-2.4.20-pre1/drivers/net/aironet4500_rid.c linux-2.4.20-pre2/drivers/net/aironet4500_rid.c
--- linux-2.4.20-pre1/drivers/net/aironet4500_rid.c	Fri Mar 10 09:43:04 2000
+++ linux-2.4.20-pre2/drivers/net/aironet4500_rid.c	Mon Aug 12 16:34:16 2002
@@ -20,7 +20,7 @@
 #define awc_RID_gen_RidLen 				{(const struct aironet4500_rid_selector *)&aironet4500_RID_Select_General_Config,0x0000, 8,1,1,1,0, 0xffffffff,0x0000, "Length of RID" }
 #define awc_RID_gen_OperatingMode_adhoc 		{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0000,"Opmode IBSS Adhoc operation" } // Without AP
 #define awc_RID_gen_OperatingMode_Infrastructure 	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0001,"Opmode Infrastructure Station operation" }// With AP
-#define awc_RID_gen_OperatingMode_AP			{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0002,"Opmode Access Point" } // Aironet doesnt release info on use 
+#define awc_RID_gen_OperatingMode_AP			{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0002,"Opmode Access Point" } // Aironet doesn't release info on use 
 #define awc_RID_gen_OperatingMode_AP_and_repeater 	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000003,0x0003,"Opmode Access Point and Repeater" } // no info
 #define awc_RID_gen_OperatingMode_No_payload_modify	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000100,0x0100,"Opmode Payload without modify" } 
 #define awc_RID_gen_OperatingMode_LLC_802_3_convert	{&aironet4500_RID_Select_General_Config,0x0002,16,1,1,0,0, 0x00000100,0x0000,"Opmode LLC -> 802.3 convert" }
diff -urN linux-2.4.20-pre1/drivers/net/arcnet/arcnet.c linux-2.4.20-pre2/drivers/net/arcnet/arcnet.c
--- linux-2.4.20-pre1/drivers/net/arcnet/arcnet.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/arcnet/arcnet.c	Mon Aug 12 16:34:16 2002
@@ -186,7 +186,7 @@
 void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
 {
 	int i;
-	long flags;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -212,7 +212,7 @@
 {
 	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
 	int i, length;
-	long flags;
+	unsigned long flags;
 	static uint8_t buf[512];
 
 	save_flags(flags);
diff -urN linux-2.4.20-pre1/drivers/net/at1700.c linux-2.4.20-pre2/drivers/net/at1700.c
--- linux-2.4.20-pre1/drivers/net/at1700.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/at1700.c	Mon Aug 12 16:34:16 2002
@@ -811,7 +811,7 @@
 	int ioaddr = dev->base_addr;
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned char mc_filter[8];		 /* Multicast hash filter */
-	long flags;
+	unsigned long flags;
 	int i;
 
 	if (dev->flags & IFF_PROMISC) {
diff -urN linux-2.4.20-pre1/drivers/net/au1000_eth.c linux-2.4.20-pre2/drivers/net/au1000_eth.c
--- linux-2.4.20-pre1/drivers/net/au1000_eth.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/au1000_eth.c	Mon Aug 12 16:34:16 2002
@@ -811,9 +811,9 @@
 				MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS));
 	if (dev->priv != NULL)
 		kfree(dev->priv);
-	kfree(dev);
 	printk(KERN_ERR "%s: au1000_probe1 failed.  Returns %d\n",
 	       dev->name, retval);
+	kfree(dev);
 	return retval;
 }
 
diff -urN linux-2.4.20-pre1/drivers/net/bonding.c linux-2.4.20-pre2/drivers/net/bonding.c
--- linux-2.4.20-pre1/drivers/net/bonding.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/bonding.c	Mon Aug 12 16:34:16 2002
@@ -399,7 +399,7 @@
 {
 	static int (* ioctl)(struct net_device *, struct ifreq *, int);
 	struct ifreq ifr;
-	struct mii_ioctl_data mii;
+	struct mii_ioctl_data *mii;
 	struct ethtool_value etool;
 
 	if ((ioctl = dev->do_ioctl) != NULL)  { /* ioctl to access MII */
@@ -425,21 +425,24 @@
 			} 
 		}
 
-		ifr.ifr_data = (char*)&mii;
-                /* try MIIPHY first then, if that doesn't work, try MIIREG */
-		if (ioctl(dev, &ifr, SIOCGMIIPHY) == 0) {
-			/* now, mii.phy_id contains info about link status :
-			- mii.phy_id & 0x04 means link up
-			- mii.phy_id & 0x20 means end of auto-negociation
-			*/
-			return mii.phy_id;
+		/*
+		 * We cannot assume that SIOCGMIIPHY will also read a
+		 * register; not all network drivers support that.
+		 */
+
+		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */
+		mii = (struct mii_ioctl_data *)&ifr.ifr_data;
+		if (ioctl(dev, &ifr, SIOCGMIIPHY) != 0) {
+			return MII_LINK_READY;	 /* can't tell */
 		}
 
-		mii.reg_num = 1; /* the MII register we want to read */  
+		mii->reg_num = 1;
 		if (ioctl(dev, &ifr, SIOCGMIIREG) == 0) {
-			/* mii.val_out contians the same link info as phy_id */
-			/* above                                             */
-			return mii.val_out;
+			/*
+			 * mii->val_out contains MII reg 1, BMSR
+			 * 0x0004 means link established
+			 */
+			return mii->val_out;
 		}
 
 	}
@@ -641,12 +644,6 @@
 	 */
 	write_lock_irqsave(&bond->lock, flags);
 
-	/*
-	 * Lock the master device so that noone trys to transmit
-	 * while we're changing things
-	 */
-	spin_lock_bh(&master->xmit_lock);
-
 	/* set promiscuity flag to slaves */
 	if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) )
 		bond_set_promiscuity(bond, 1); 
@@ -680,7 +677,6 @@
 	bond_mc_list_destroy (bond);
 	bond_mc_list_copy (master->mc_list, bond, GFP_KERNEL);
 
-	spin_unlock_bh(&master->xmit_lock);
 	write_unlock_irqrestore(&bond->lock, flags);
 }
 
diff -urN linux-2.4.20-pre1/drivers/net/de600.c linux-2.4.20-pre2/drivers/net/de600.c
--- linux-2.4.20-pre1/drivers/net/de600.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.20-pre2/drivers/net/de600.c	Mon Aug 12 16:34:16 2002
@@ -718,7 +718,7 @@
 adapter_init(struct net_device *dev)
 {
 	int	i;
-	long flags;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
diff -urN linux-2.4.20-pre1/drivers/net/depca.c linux-2.4.20-pre2/drivers/net/depca.c
--- linux-2.4.20-pre1/drivers/net/depca.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/depca.c	Mon Aug 12 16:34:16 2002
@@ -1913,7 +1913,8 @@
 			dev->dev_addr[i] = tmp.addr[i];
 		}
 		netif_stop_queue(dev);
-		while (lp->tx_old != lp->tx_new);	/* Wait for the ring to empty */
+		while (lp->tx_old != lp->tx_new)
+			cpu_relax();	/* Wait for the ring to empty */
 
 		STOP_DEPCA;	/* Temporarily stop the depca.  */
 		depca_init_ring(dev);	/* Initialize the descriptor rings */
@@ -1926,7 +1927,8 @@
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		netif_stop_queue(dev);
-		while (lp->tx_old != lp->tx_new);	/* Wait for the ring to empty */
+		while (lp->tx_old != lp->tx_new)
+			cpu_relax();	/* Wait for the ring to empty */
 
 		STOP_DEPCA;	/* Temporarily stop the depca.  */
 		depca_init_ring(dev);	/* Initialize the descriptor rings */
@@ -1941,7 +1943,8 @@
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		netif_stop_queue(dev);
-		while (lp->tx_old != lp->tx_new);	/* Wait for the ring to empty */
+		while (lp->tx_old != lp->tx_new)
+			cpu_relax();	/* Wait for the ring to empty */
 
 		STOP_DEPCA;	/* Temporarily stop the depca.  */
 		depca_init_ring(dev);	/* Initialize the descriptor rings */
@@ -1953,6 +1956,8 @@
 		break;
 
 	case DEPCA_SAY_BOO:	/* Say "Boo!" to the kernel log file */
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		printk("%s: Boo!\n", dev->name);
 		break;
 
@@ -1965,6 +1970,8 @@
 	case DEPCA_SET_MCA:	/* Set a multicast address */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
+		if (ioc->len >= HASH_TABLE_LEN || ioc->len < 0)
+			return -EINVAL;
 		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
 			return -EFAULT;
 		set_multicast_list(dev);
diff -urN linux-2.4.20-pre1/drivers/net/dl2k.c linux-2.4.20-pre2/drivers/net/dl2k.c
--- linux-2.4.20-pre1/drivers/net/dl2k.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/dl2k.c	Mon Aug 12 16:34:16 2002
@@ -1108,7 +1108,6 @@
 	u16 rx_mode = 0;
 	int i;
 	int bit;
-	int index, crc;
 	struct dev_mc_list *mclist;
 	struct netdev_private *np = dev->priv;
 	
@@ -1130,13 +1129,14 @@
 		for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; 
 			i++, mclist=mclist->next) {
 
-			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
+			int index = 0;
+			int crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
 
 			/* 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);
+			for (bit = 0; bit < 6; bit++)
+				if (crc & (1 << (31 - bit)))
+					index |= (1 << bit);
 
 			hash_table[index / 32] |= (1 << (index % 32));
 		}
diff -urN linux-2.4.20-pre1/drivers/net/e100/e100.h linux-2.4.20-pre2/drivers/net/e100/e100.h
--- linux-2.4.20-pre1/drivers/net/e100/e100.h	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/e100/e100.h	Mon Aug 12 16:34:16 2002
@@ -97,6 +97,7 @@
 #include <asm/processor.h>
 #include <linux/ethtool.h>
 #include <linux/inetdevice.h>
+#include <linux/bitops.h>
 
 #include <linux/if.h>
 #include <asm/uaccess.h>
diff -urN linux-2.4.20-pre1/drivers/net/e100/e100_main.c linux-2.4.20-pre2/drivers/net/e100/e100_main.c
--- linux-2.4.20-pre1/drivers/net/e100/e100_main.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/e100/e100_main.c	Mon Aug 12 16:34:16 2002
@@ -3532,7 +3532,7 @@
 		       GFP_ATOMIC);
 
 	if (!info)
-		return -EFAULT;
+		return -ENOMEM;
 
 	memset((void *) info, 0, sizeof(*info) +
 				 E100_MAX_TEST_RES * sizeof(u64));
@@ -3616,6 +3616,10 @@
 		(u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data));
 
         max_len = bdp->eeprom_size * 2;
+        
+        if (ecmd.offset > ecmd.offset + ecmd.len)
+        	return -EINVAL;
+        	
 	if ((ecmd.offset + ecmd.len) > max_len)
 		ecmd.len = (max_len - ecmd.offset);
 
@@ -3929,7 +3933,7 @@
 			info.len = E100_MAX_TEST_RES;
 		strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
 		if (!strings)
-			return -EFAULT;
+			return -ENOMEM;
 		memset(strings, 0, info.len * ETH_GSTRING_LEN);
 
 		for (i = 0; i < info.len; i++) {
diff -urN linux-2.4.20-pre1/drivers/net/e1000/e1000_ethtool.c linux-2.4.20-pre2/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.20-pre1/drivers/net/e1000/e1000_ethtool.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/e1000/e1000_ethtool.c	Mon Aug 12 16:34:16 2002
@@ -244,7 +244,7 @@
 	return;
 }
 
-static void
+static int
 e1000_ethtool_geeprom(struct e1000_adapter *adapter,
                       struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
 {
@@ -257,6 +257,9 @@
 
 	max_len = e1000_eeprom_size(hw);
 
+	if(eeprom->offset > eeprom->offset + eeprom->len)
+		return -EINVAL;
+	
 	if((eeprom->offset + eeprom->len) > max_len)
 		eeprom->len = (max_len - eeprom->offset);
 
@@ -265,6 +268,7 @@
 
 	for(i = 0; i <= (last_word - first_word); i++)
 		e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
+	return 0;
 }
 
 static int 
@@ -546,11 +550,13 @@
 		struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
 		uint16_t eeprom_buff[256];
 		void *ptr;
+		int err;
 
 		if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
 			return -EFAULT;
 
-		e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff);
+		if((err = e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff))<0)
+			return err;
 
 		if(copy_to_user(addr, &eeprom, sizeof(eeprom)))
 			return -EFAULT;
diff -urN linux-2.4.20-pre1/drivers/net/e1000/e1000_hw.c linux-2.4.20-pre2/drivers/net/e1000/e1000_hw.c
--- linux-2.4.20-pre1/drivers/net/e1000/e1000_hw.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/e1000/e1000_hw.c	Mon Aug 12 16:34:16 2002
@@ -152,7 +152,7 @@
     /* Force a reload from the EEPROM if necessary */
     if(hw->mac_type < e1000_82540) {
         /* Wait for reset to complete */
-        usec_delay(10);
+        udelay(10);
         ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
         ctrl_ext |= E1000_CTRL_EXT_EE_RST;
         E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
@@ -761,7 +761,7 @@
             DEBUGOUT("Valid link established!!!\n");
             return 0;
         }
-        usec_delay(10);
+        udelay(10);
     }
 
     DEBUGOUT("Unable to establish link!!!\n");
@@ -1014,7 +1014,7 @@
         DEBUGOUT("PHY Write Error\n");
         return -E1000_ERR_PHY;
     }
-    usec_delay(1);
+    udelay(1);
 
     /* The wait_autoneg_complete flag may be a little misleading here.
      * Since we are forcing speed and duplex, Auto-Neg is not enabled.
@@ -1718,7 +1718,7 @@
      */
     E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
     E1000_WRITE_FLUSH(hw);
-    usec_delay(2);
+    udelay(2);
 }
 
 /******************************************************************************
@@ -1736,7 +1736,7 @@
      */
     E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
     E1000_WRITE_FLUSH(hw);
-    usec_delay(2);
+    udelay(2);
 }
 
 /******************************************************************************
@@ -1780,7 +1780,7 @@
         E1000_WRITE_REG(hw, CTRL, ctrl);
         E1000_WRITE_FLUSH(hw);
 
-        usec_delay(2);
+        udelay(2);
 
         e1000_raise_mdi_clk(hw, &ctrl);
         e1000_lower_mdi_clk(hw, &ctrl);
@@ -1876,7 +1876,7 @@
 
         /* Poll the ready bit to see if the MDI read completed */
         for(i = 0; i < 64; i++) {
-            usec_delay(10);
+            udelay(10);
             mdic = E1000_READ_REG(hw, MDIC);
             if(mdic & E1000_MDIC_READY) break;
         }
@@ -1958,7 +1958,7 @@
 
         /* Poll the ready bit to see if the MDI read completed */
         for(i = 0; i < 64; i++) {
-            usec_delay(10);
+            udelay(10);
             mdic = E1000_READ_REG(hw, MDIC);
             if(mdic & E1000_MDIC_READY) break;
         }
@@ -2029,7 +2029,7 @@
         E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
         E1000_WRITE_FLUSH(hw);
     }
-    usec_delay(150);
+    udelay(150);
 }
 
 /******************************************************************************
@@ -2055,7 +2055,7 @@
         DEBUGOUT("PHY Write Error\n");
         return -E1000_ERR_PHY;
     }
-    usec_delay(1);
+    udelay(1);
     return 0;
 }
 
@@ -2078,7 +2078,7 @@
         return -E1000_ERR_PHY;
     }
     hw->phy_id = (uint32_t) (phy_id_high << 16);
-    usec_delay(2);
+    udelay(2);
     if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
         DEBUGOUT("PHY Read Error\n");
         return -E1000_ERR_PHY;
@@ -2231,7 +2231,7 @@
     *eecd = *eecd | E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, *eecd);
     E1000_WRITE_FLUSH(hw);
-    usec_delay(50);
+    udelay(50);
 }
 
 /******************************************************************************
@@ -2250,7 +2250,7 @@
     *eecd = *eecd & ~E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, *eecd);
     E1000_WRITE_FLUSH(hw);
-    usec_delay(50);
+    udelay(50);
 }
 
 /******************************************************************************
@@ -2289,7 +2289,7 @@
         E1000_WRITE_REG(hw, EECD, eecd);
         E1000_WRITE_FLUSH(hw);
 
-        usec_delay(50);
+        udelay(50);
 
         e1000_raise_ee_clk(hw, &eecd);
         e1000_lower_ee_clk(hw, &eecd);
@@ -2383,25 +2383,25 @@
     eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
     E1000_WRITE_REG(hw, EECD, eecd);
     E1000_WRITE_FLUSH(hw);
-    usec_delay(50);
+    udelay(50);
 
     /* Clock high */
     eecd |= E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, eecd);
     E1000_WRITE_FLUSH(hw);
-    usec_delay(50);
+    udelay(50);
 
     /* Select EEPROM */
     eecd |= E1000_EECD_CS;
     E1000_WRITE_REG(hw, EECD, eecd);
     E1000_WRITE_FLUSH(hw);
-    usec_delay(50);
+    udelay(50);
 
     /* Clock low */
     eecd &= ~E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, eecd);
     E1000_WRITE_FLUSH(hw);
-    usec_delay(50);
+    udelay(50);
 }
 
 /******************************************************************************
@@ -2420,13 +2420,13 @@
     eecd |= E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, eecd);
     E1000_WRITE_FLUSH(hw);
-    usec_delay(50);
+    udelay(50);
 
     /* Falling edge of clock */
     eecd &= ~E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, eecd);
     E1000_WRITE_FLUSH(hw);
-    usec_delay(50);
+    udelay(50);
 }
 
 /******************************************************************************
@@ -2475,7 +2475,7 @@
         eecd = E1000_READ_REG(hw, EECD);
         while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
             i++;
-            usec_delay(5);
+            udelay(5);
             eecd = E1000_READ_REG(hw, EECD);
         }
         if(!(eecd & E1000_EECD_GNT)) {
@@ -2610,7 +2610,7 @@
         eecd = E1000_READ_REG(hw, EECD);
         while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
             i++;
-            usec_delay(5);
+            udelay(5);
             eecd = E1000_READ_REG(hw, EECD);
         }
         if(!(eecd & E1000_EECD_GNT)) {
@@ -2661,7 +2661,7 @@
     for(i = 0; i < 200; i++) {
         eecd = E1000_READ_REG(hw, EECD);
         if(eecd & E1000_EECD_DO) break;
-        usec_delay(50);
+        udelay(50);
     }
     if(i == 200) {
         DEBUGOUT("EEPROM Write did not complete\n");
diff -urN linux-2.4.20-pre1/drivers/net/e1000/e1000_osdep.h linux-2.4.20-pre2/drivers/net/e1000/e1000_osdep.h
--- linux-2.4.20-pre1/drivers/net/e1000/e1000_osdep.h	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/e1000/e1000_osdep.h	Mon Aug 12 16:34:16 2002
@@ -84,8 +84,8 @@
 #include <linux/delay.h>
 #include <asm/io.h>
 #include <linux/interrupt.h>
+#include <linux/sched.h>
 
-#define usec_delay(x) udelay(x)
 #ifndef msec_delay
 #define msec_delay(x)	do { if(in_interrupt()) { \
 				/* Don't mdelay in interrupt context! */ \
diff -urN linux-2.4.20-pre1/drivers/net/e2100.c linux-2.4.20-pre2/drivers/net/e2100.c
--- linux-2.4.20-pre1/drivers/net/e2100.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/e2100.c	Mon Aug 12 16:34:16 2002
@@ -72,7 +72,7 @@
 #define E21_SAPROM		0x10	/* Offset to station address data. */
 #define E21_IO_EXTENT	 0x20
 
-extern inline void mem_on(short port, volatile char *mem_base,
+static inline void mem_on(short port, volatile char *mem_base,
 						  unsigned char start_page )
 {
 	/* This is a little weird: set the shared memory window by doing a
@@ -82,7 +82,7 @@
 	outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
 }
 
-extern inline void mem_off(short port)
+static inline void mem_off(short port)
 {
 	inb(port + E21_MEM_ENABLE);
 	outb(0x00, port + E21_MEM_ENABLE);
diff -urN linux-2.4.20-pre1/drivers/net/eepro.c linux-2.4.20-pre2/drivers/net/eepro.c
--- linux-2.4.20-pre1/drivers/net/eepro.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/eepro.c	Mon Aug 12 16:34:16 2002
@@ -23,6 +23,8 @@
 	This is a compatibility hardware problem.
 
 	Versions:
+	0.13a   in memory shortage, drop packets also in board
+		(Michael Westermann <mw@microdata-pos.de>, 07/30/2002)
 	0.13    irq sharing, rewrote probe function, fixed a nasty bug in
 		hardware_send_packet and a major cleanup (aris, 11/08/2001)
 	0.12d	fixing a problem with single card detected as eight eth devices
@@ -665,37 +667,37 @@
 
 	i = inb(dev->base_addr + ID_REG);
 	printk(KERN_DEBUG " id: %#x ",i);
-	printk(KERN_DEBUG " io: %#x ", (unsigned)dev->base_addr);
+	printk(" io: %#x ", (unsigned)dev->base_addr);
 
 	switch (lp->eepro) {
 		case LAN595FX_10ISA:
-			printk(KERN_INFO "%s: Intel EtherExpress 10 ISA\n at %#x,",
+			printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
 					dev->name, (unsigned)dev->base_addr);
 			break;
 		case LAN595FX:
-			printk(KERN_INFO "%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", 
+			printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", 
 					dev->name, (unsigned)dev->base_addr);
 			break;
 		case LAN595TX:
-			printk(KERN_INFO "%s: Intel EtherExpress Pro/10 ISA at %#x,",
+			printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
 					dev->name, (unsigned)dev->base_addr);
 			break;
 		case LAN595:
-			printk(KERN_INFO "%s: Intel 82595-based lan card at %#x,", 
+			printk("%s: Intel 82595-based lan card at %#x,", 
 					dev->name, (unsigned)dev->base_addr);
 	}
 
 	for (i=0; i < 6; i++)
-		printk(KERN_INFO "%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
 
 	if (net_debug > 3)
 		printk(KERN_DEBUG ", %dK RCV buffer",
 				(int)(lp->rcv_ram)/1024);
 
 	if (dev->irq > 2)
-		printk(KERN_INFO ", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
+		printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
 	else 
-		printk(KERN_INFO ", %s.\n", ifmap[dev->if_port]);
+		printk(", %s.\n", ifmap[dev->if_port]);
 
 	if (net_debug > 3) {
 		i = read_eeprom(dev->base_addr, 5, dev);
@@ -1580,6 +1582,10 @@
 			if (skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
 				lp->stats.rx_dropped++;
+				rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
+				lp->rx_start = rcv_next_frame;
+				outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
+
 				break;
 			}
 			skb->dev = dev;
diff -urN linux-2.4.20-pre1/drivers/net/eepro100.c linux-2.4.20-pre2/drivers/net/eepro100.c
--- linux-2.4.20-pre1/drivers/net/eepro100.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/eepro100.c	Mon Aug 12 16:34:16 2002
@@ -1,7 +1,5 @@
 /* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
 /*
-   NOTICE: For use with late 2.3 kernels only.
-   May not compile for kernels 2.3.43-47.
 	Written 1996-1999 by Donald Becker.
 
 	The driver also contains updates by different kernel developers
@@ -25,8 +23,8 @@
 		Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
 	2000 Jul 17 Goutham Rao <goutham.rao@intel.com>
 		PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary
-    2000 Aug 31 David Mosberger <davidm@hpl.hp.com>
-	    RX_ALIGN support: enables rx DMA without causing unaligned accesses.
+	2000 Aug 31 David Mosberger <davidm@hpl.hp.com>
+		rx_align support: enables rx DMA without causing unaligned accesses.
 */
 
 static const char *version =
@@ -46,9 +44,10 @@
 #if defined(__ia64__) || defined(__alpha__) || defined(__sparc__) || defined(__mips__) || \
 	defined(__arm__)
   /* align rx buffers to 2 bytes so that IP header is aligned */
-# define RX_ALIGN
+# define rx_align(skb)		skb_reserve((skb), 2)
 # define RxFD_ALIGNMENT		__attribute__ ((aligned (2), packed))
 #else
+# define rx_align(skb)
 # define RxFD_ALIGNMENT
 #endif
 
@@ -530,10 +529,6 @@
 static int eepro100_init_one(struct pci_dev *pdev,
 		const struct pci_device_id *ent);
 static void eepro100_remove_one (struct pci_dev *pdev);
-#ifdef CONFIG_PM
-static int eepro100_suspend (struct pci_dev *pdev, u32 state);
-static int eepro100_resume (struct pci_dev *pdev);
-#endif
 
 static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
 static int mdio_read(long ioaddr, int phy_id, int location);
@@ -1239,9 +1234,8 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb;
 		skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#ifdef RX_ALIGN
-		skb_reserve(skb, 2);	/* Align IP on 16 byte boundary */
-#endif
+		/* XXX: do we really want to call this before the NULL check? --hch */
+		rx_align(skb);			/* Align IP on 16 byte boundary */
 		sp->rx_skbuff[i] = skb;
 		if (skb == NULL)
 			break;			/* OK.  Just initially short of Rx bufs. */
@@ -1633,9 +1627,8 @@
 	struct sk_buff *skb;
 	/* Get a fresh skbuff to replace the consumed one. */
 	skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#ifdef RX_ALIGN
-	skb_reserve(skb, 2);	/* Align IP on 16 byte boundary */
-#endif
+	/* XXX: do we really want to call this before the NULL check? --hch */
+	rx_align(skb);				/* Align IP on 16 byte boundary */
 	sp->rx_skbuff[entry] = skb;
 	if (skb == NULL) {
 		sp->rx_ringp[entry] = NULL;
@@ -2321,9 +2314,7 @@
 	name:		"eepro100",
 	id_table:	eepro100_pci_tbl,
 	probe:		eepro100_init_one,
-# if defined(MODULE) || defined(CONFIG_HOTPLUG)
 	remove:		__devexit_p(eepro100_remove_one),
-# endif
 #ifdef CONFIG_PM
 	suspend:	eepro100_suspend,
 	resume:		eepro100_resume,
diff -urN linux-2.4.20-pre1/drivers/net/eexpress.c linux-2.4.20-pre2/drivers/net/eexpress.c
--- linux-2.4.20-pre1/drivers/net/eexpress.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/eexpress.c	Mon Aug 12 16:34:16 2002
@@ -341,7 +341,7 @@
 int __init express_probe(struct net_device *dev)
 {
 	unsigned short *port;
-	static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 };
+	static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
 	unsigned short ioaddr = dev->base_addr;
 
 	SET_MODULE_OWNER(dev);
diff -urN linux-2.4.20-pre1/drivers/net/epic100.c linux-2.4.20-pre2/drivers/net/epic100.c
--- linux-2.4.20-pre1/drivers/net/epic100.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/epic100.c	Mon Aug 12 16:34:16 2002
@@ -63,11 +63,15 @@
 	LK1.1.13:
 	* revert version 1.1.12, power-up sequence "fix"
 
+	LK1.1.14 (Kryzsztof Halasa):
+	* fix spurious bad initializations
+	* pound phy a la SMSC's app note on the subject
+
 */
 
 #define DRV_NAME	"epic100"
-#define DRV_VERSION	"1.11+LK1.1.13"
-#define DRV_RELDATE	"Mar 20, 2002"
+#define DRV_VERSION	"1.11+LK1.1.14"
+#define DRV_RELDATE	"Aug 4, 2002"
 
 
 /* The user-configurable values.
@@ -457,7 +461,9 @@
 	/* Bring the chip out of low-power mode. */
 	outl(0x4200, ioaddr + GENCTL);
 	/* Magic?!  If we don't set this bit the MII interface won't work. */
-	outl(0x0008, ioaddr + TEST1);
+	/* This magic is documented in SMSC app note 7.15 */
+	for (i = 16; i > 0; i--)
+		outl(0x0008, ioaddr + TEST1);
 
 	/* Turn on the MII transceiver. */
 	outl(0x12, ioaddr + MIICfg);
@@ -674,7 +680,8 @@
 
 	outl(0x4000, ioaddr + GENCTL);
 	/* This magic is documented in SMSC app note 7.15 */
-	outl(0x0008, ioaddr + TEST1);
+	for (i = 16; i > 0; i--)
+		outl(0x0008, ioaddr + TEST1);
 
 	/* Pull the chip out of low-power mode, enable interrupts, and set for
 	   PCI read multiple.  The MIIcfg setting and strange write order are
@@ -697,6 +704,8 @@
 	outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
 #endif
 
+	udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */
+	
 	for (i = 0; i < 3; i++)
 		outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
 
diff -urN linux-2.4.20-pre1/drivers/net/hamachi.c linux-2.4.20-pre2/drivers/net/hamachi.c
--- linux-2.4.20-pre1/drivers/net/hamachi.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.20-pre2/drivers/net/hamachi.c	Mon Aug 12 16:34:16 2002
@@ -210,8 +210,10 @@
 /* Condensed bus+endian portability operations. */
 #if ADDRLEN == 64
 #define cpu_to_leXX(addr)	cpu_to_le64(addr)
+#define desc_to_virt(addr) bus_to_virt(le64_to_cpu(addr))
 #else 
 #define cpu_to_leXX(addr)	cpu_to_le32(addr)
+#define desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
 #endif   
 
 
@@ -1544,7 +1546,7 @@
 			break;
 		pci_dma_sync_single(hmp->pci_dev, desc->addr, hmp->rx_buf_sz, 
 			PCI_DMA_FROMDEVICE);
-		buf_addr = (u8 *)hmp->rx_ring + entry*sizeof(*desc);
+		buf_addr = desc_to_virt(desc->addr);
 		frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12])));
 		if (hamachi_debug > 4)
 			printk(KERN_DEBUG "  hamachi_rx() status was %8.8x.\n",
diff -urN linux-2.4.20-pre1/drivers/net/hamradio/scc.c linux-2.4.20-pre2/drivers/net/hamradio/scc.c
--- linux-2.4.20-pre1/drivers/net/hamradio/scc.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.20-pre2/drivers/net/hamradio/scc.c	Mon Aug 12 16:34:16 2002
@@ -2128,7 +2128,7 @@
 
 static void __exit scc_cleanup_driver(void)
 {
-	long flags;
+	unsigned long flags;
 	io_port ctrl;
 	int k;
 	struct scc_channel *scc;
diff -urN linux-2.4.20-pre1/drivers/net/hp100.c linux-2.4.20-pre2/drivers/net/hp100.c
--- linux-2.4.20-pre1/drivers/net/hp100.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/hp100.c	Mon Aug 12 16:34:16 2002
@@ -237,6 +237,9 @@
 	/* 10/100 ISA card with Cascade chip */
 	{0x5019F022, "HP J2573", HP100_BUS_ISA},
 
+	/* 10/100 EISA card with AT&T chip */
+	{0x9019f022, "HP J2577", HP100_BUS_EISA },
+
 	/* 10/100 PCI card - old J2585A */
 	{0x1030103c, "HP J2585A", HP100_BUS_PCI},
 
@@ -1880,7 +1883,7 @@
 #endif
 
 		/* Now we allocate the skb and transfer the data into it. */
-		skb = dev_alloc_skb(pkt_len);
+		skb = dev_alloc_skb(pkt_len+2);
 		if (skb == NULL) {	/* Not enough memory->drop packet */
 #ifdef HP100_DEBUG
 			printk("hp100: %s: rx: couldn't allocate a sk_buff of size %d\n",
@@ -1891,10 +1894,12 @@
 
 			u_char *ptr;
 
+			skb_reserve(skb,2);
 			skb->dev = dev;
 
 			/* ptr to start of the sk_buff data area */
-			ptr = (u_char *) skb_put(skb, pkt_len);
+			skb_put(skb, pkt_len);
+			ptr = skb->data;
 
 			/* Now transfer the data from the card into that area */
 			if (lp->mode == 2) {
diff -urN linux-2.4.20-pre1/drivers/net/irda/Config.in linux-2.4.20-pre2/drivers/net/irda/Config.in
--- linux-2.4.20-pre1/drivers/net/irda/Config.in	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/irda/Config.in	Mon Aug 12 16:34:16 2002
@@ -13,10 +13,15 @@
    dep_tristate '  Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA
    dep_tristate '  Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA
    dep_tristate '  Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA
+   dep_tristate '  Microchip MCP2120' CONFIG_MCP2120_DONGLE $CONFIG_IRDA
    dep_tristate '  Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA   
    if [ "$CONFIG_ARCH_EP7211" = "y" ]; then
       dep_tristate '  EP7211 I/R support' CONFIG_EP7211_IR $CONFIG_IRDA
    fi
+   if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+      dep_tristate '  ACTiSYS IR-200L dongle (Experimental)' CONFIG_ACT200L_DONGLE $CONFIG_IRDA
+      dep_tristate '  Mobile Action MA600 dongle (Experimental)' CONFIG_MA600_DONGLE $CONFIG_IRDA
+   fi
 fi
 
 comment 'FIR device drivers'
diff -urN linux-2.4.20-pre1/drivers/net/irda/Makefile linux-2.4.20-pre2/drivers/net/irda/Makefile
--- linux-2.4.20-pre1/drivers/net/irda/Makefile	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/irda/Makefile	Mon Aug 12 16:34:16 2002
@@ -29,5 +29,8 @@
 obj-$(CONFIG_OLD_BELKIN_DONGLE)	+= old_belkin.o
 obj-$(CONFIG_EP7211_IR)		+= ep7211_ir.o
 obj-$(CONFIG_AU1000_FIR)	+= au1k_ir.o
+obj-$(CONFIG_MCP2120_DONGLE)	+= mcp2120.o
+obj-$(CONFIG_ACT200L_DONGLE)	+= act200l.o
+obj-$(CONFIG_MA600_DONGLE)	+= ma600.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/drivers/net/irda/act200l.c linux-2.4.20-pre2/drivers/net/irda/act200l.c
--- linux-2.4.20-pre1/drivers/net/irda/act200l.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/net/irda/act200l.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,299 @@
+/*********************************************************************
+ *
+ * Filename:      act200l.c
+ * Version:       0.8
+ * Description:   Implementation for the ACTiSYS ACT-IR200L dongle
+ * Status:        Experimental.
+ * Author:        SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
+ * Created at:    Fri Aug  3 17:35:42 2001
+ * Modified at:   Fri Aug 17 10:22:40 2001
+ * Modified by:   SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
+ *
+ *     Copyright (c) 2001 SHIMIZU Takuya, 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.
+ *
+ ********************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/irtty.h>
+
+static int  act200l_reset(struct irda_task *task);
+static void act200l_open(dongle_t *self, struct qos_info *qos);
+static void act200l_close(dongle_t *self);
+static int  act200l_change_speed(struct irda_task *task);
+
+/* Regsiter 0: Control register #1 */
+#define ACT200L_REG0    0x00
+#define ACT200L_TXEN    0x01 /* Enable transmitter */
+#define ACT200L_RXEN    0x02 /* Enable receiver */
+
+/* Register 1: Control register #2 */
+#define ACT200L_REG1    0x10
+#define ACT200L_LODB    0x01 /* Load new baud rate count value */
+#define ACT200L_WIDE    0x04 /* Expand the maximum allowable pulse */
+
+/* Register 4: Output Power register */
+#define ACT200L_REG4    0x40
+#define ACT200L_OP0     0x01 /* Enable LED1C output */
+#define ACT200L_OP1     0x02 /* Enable LED2C output */
+#define ACT200L_BLKR    0x04
+
+/* Register 5: Receive Mode register */
+#define ACT200L_REG5    0x50
+#define ACT200L_RWIDL   0x01 /* fixed 1.6us pulse mode */
+
+/* Register 6: Receive Sensitivity register #1 */
+#define ACT200L_REG6    0x60
+#define ACT200L_RS0     0x01 /* receive threshold bit 0 */
+#define ACT200L_RS1     0x02 /* receive threshold bit 1 */
+
+/* Register 7: Receive Sensitivity register #2 */
+#define ACT200L_REG7    0x70
+#define ACT200L_ENPOS   0x04 /* Ignore the falling edge */
+
+/* Register 8,9: Baud Rate Dvider register #1,#2 */
+#define ACT200L_REG8    0x80
+#define ACT200L_REG9    0x90
+
+#define ACT200L_2400    0x5f
+#define ACT200L_9600    0x17
+#define ACT200L_19200   0x0b
+#define ACT200L_38400   0x05
+#define ACT200L_57600   0x03
+#define ACT200L_115200  0x01
+
+/* Register 13: Control register #3 */
+#define ACT200L_REG13   0xd0
+#define ACT200L_SHDW    0x01 /* Enable access to shadow registers */
+
+/* Register 15: Status register */
+#define ACT200L_REG15   0xf0
+
+/* Register 21: Control register #4 */
+#define ACT200L_REG21   0x50
+#define ACT200L_EXCK    0x02 /* Disable clock output driver */
+#define ACT200L_OSCL    0x04 /* oscillator in low power, medium accuracy mode */
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_ACT200L_DONGLE,
+	act200l_open,
+	act200l_close,
+	act200l_reset,
+	act200l_change_speed,
+};
+
+int __init act200l_init(void)
+{
+	return irda_device_register_dongle(&dongle);
+}
+
+void __exit act200l_cleanup(void)
+{
+	irda_device_unregister_dongle(&dongle);
+}
+
+static void act200l_open(dongle_t *self, struct qos_info *qos)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/* Power on the dongle */
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+	/* Set the speeds we can accept */
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x03;
+
+	MOD_INC_USE_COUNT;
+}
+
+static void act200l_close(dongle_t *self)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/* Power off the dongle */
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Function act200l_change_speed (dev, speed)
+ *
+ *    Set the speed for the ACTiSYS ACT-IR200L type dongle.
+ *
+ */
+static int act200l_change_speed(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
+	__u8 control[3];
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	self->speed_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		if (irda_task_execute(self, act200l_reset, NULL, task,
+				(void *) speed))
+		{
+			/* Dongle need more time to reset */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+			/* Give reset 1 sec to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		}
+		break;
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		ret = -1;
+		break;
+	case IRDA_TASK_CHILD_DONE:
+		/* Clear DTR and set RTS to enter command mode */
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
+
+		switch (speed) {
+		case 9600:
+		default:
+			control[0] = ACT200L_REG8 |  (ACT200L_9600       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_9600 >> 4) & 0x0f);
+			break;
+		case 19200:
+			control[0] = ACT200L_REG8 |  (ACT200L_19200       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_19200 >> 4) & 0x0f);
+			break;
+		case 38400:
+			control[0] = ACT200L_REG8 |  (ACT200L_38400       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_38400 >> 4) & 0x0f);
+			break;
+		case 57600:
+			control[0] = ACT200L_REG8 |  (ACT200L_57600       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_57600 >> 4) & 0x0f);
+			break;
+		case 115200:
+			control[0] = ACT200L_REG8 |  (ACT200L_115200       & 0x0f);
+			control[1] = ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f);
+			break;
+		}
+		control[2] = ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE;
+
+		/* Write control bytes */
+		self->write(self->dev, control, 3);
+		irda_task_next_state(task, IRDA_TASK_WAIT);
+		ret = MSECS_TO_JIFFIES(5);
+		break;
+	case IRDA_TASK_WAIT:
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * Function act200l_reset (driver)
+ *
+ *    Reset the ACTiSYS ACT-IR200L type dongle.
+ */
+static int act200l_reset(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	__u8 control[9] = {
+		ACT200L_REG15,
+		ACT200L_REG13 | ACT200L_SHDW,
+		ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
+		ACT200L_REG13,
+		ACT200L_REG7  | ACT200L_ENPOS,
+		ACT200L_REG6  | ACT200L_RS0  | ACT200L_RS1,
+		ACT200L_REG5  | ACT200L_RWIDL,
+		ACT200L_REG4  | ACT200L_OP0  | ACT200L_OP1 | ACT200L_BLKR,
+		ACT200L_REG0  | ACT200L_TXEN | ACT200L_RXEN
+	};
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	self->reset_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Power on the dongle */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT1:
+		/* Reset the dongle : set RTS low for 25 ms */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
+
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT2:
+		/* Clear DTR and set RTS to enter command mode */
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
+
+		/* Write control bytes */
+		self->write(self->dev, control, 9);
+		irda_task_next_state(task, IRDA_TASK_WAIT3);
+		ret = MSECS_TO_JIFFIES(15);
+		break;
+	case IRDA_TASK_WAIT3:
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+MODULE_AUTHOR("SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>");
+MODULE_DESCRIPTION("ACTiSYS ACT-IR200L dongle driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Function init_module (void)
+ *
+ *    Initialize ACTiSYS ACT-IR200L module
+ *
+ */
+module_init(act200l_init);
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup ACTiSYS ACT-IR200L module
+ *
+ */
+module_exit(act200l_cleanup);
diff -urN linux-2.4.20-pre1/drivers/net/irda/ali-ircc.c linux-2.4.20-pre2/drivers/net/irda/ali-ircc.c
--- linux-2.4.20-pre1/drivers/net/irda/ali-ircc.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/irda/ali-ircc.c	Mon Aug 12 16:34:16 2002
@@ -59,7 +59,6 @@
 static unsigned int irq[] = { 0, 0, 0, 0 };
 static unsigned int dma[] = { 0, 0, 0, 0 };
 
-static int  ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info);
 static int  ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info);
 static int  ali_ircc_init_43(ali_chip_t *chip, chipio_t *info);
 static int  ali_ircc_init_53(ali_chip_t *chip, chipio_t *info);
@@ -255,7 +254,6 @@
 	struct ali_ircc_cb *self;
 	struct pm_dev *pmdev;
 	int dongle_id;
-	int ret;
 	int err;
 			
 	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);	
@@ -454,16 +452,6 @@
 }
 
 /*
- * Function ali_ircc_probe_43 (chip, info)
- *    	
- *	Probes for the ALi M1543
- */
-static int ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info)
-{
-	return 0;	
-}
-
-/*
  * Function ali_ircc_probe_53 (chip, info)
  *    	
  *	Probes for the ALi M1535D or M1535
diff -urN linux-2.4.20-pre1/drivers/net/irda/irda-usb.c linux-2.4.20-pre2/drivers/net/irda/irda-usb.c
--- linux-2.4.20-pre1/drivers/net/irda/irda-usb.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/irda/irda-usb.c	Mon Aug 12 16:34:16 2002
@@ -112,9 +112,9 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
 static int irda_usb_open(struct irda_usb_cb *self);
 static int irda_usb_close(struct irda_usb_cb *self);
-static void speed_bulk_callback(purb_t purb);
-static void write_bulk_callback(purb_t purb);
-static void irda_usb_receive(purb_t purb);
+static void speed_bulk_callback(struct urb *urb);
+static void write_bulk_callback(struct urb *urb);
+static void irda_usb_receive(struct urb *urb);
 static int irda_usb_net_init(struct net_device *dev);
 static int irda_usb_net_open(struct net_device *dev);
 static int irda_usb_net_close(struct net_device *dev);
@@ -248,7 +248,7 @@
 {
 	unsigned long flags;
 	__u8 *frame;
-	purb_t purb;
+	struct urb *urb;
 	int ret;
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
@@ -288,7 +288,7 @@
 /*
  * Note : this function will be called with both speed_urb and empty_urb...
  */
-static void speed_bulk_callback(purb_t purb)
+static void speed_bulk_callback(struct urb *purb)
 {
 	struct irda_usb_cb *self = purb->context;
 	
@@ -329,7 +329,7 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct irda_usb_cb *self = netdev->priv;
-	purb_t purb = &self->tx_urb;
+	struct urb *purb = &self->tx_urb;
 	unsigned long flags;
 	s32 speed;
 	s16 xbofs;
@@ -479,7 +479,7 @@
 /*
  * Note : this function will be called only for tx_urb...
  */
-static void write_bulk_callback(purb_t purb)
+static void write_bulk_callback(struct urb *purb)
 {
 	struct sk_buff *skb = purb->context;
 	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
@@ -541,7 +541,7 @@
 static void irda_usb_net_timeout(struct net_device *netdev)
 {
 	struct irda_usb_cb *self = netdev->priv;
-	purb_t purb;
+	struct urb *purb;
 	int	done = 0;	/* If we have made any progress */
 
 	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
@@ -692,7 +692,7 @@
  *
  * Jean II
  */
-static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
+static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *purb)
 {
 	struct irda_skb_cb *cb;
 	int ret;
@@ -752,7 +752,7 @@
  *     Called by the USB subsystem when a frame has been received
  *
  */
-static void irda_usb_receive(purb_t purb) 
+static void irda_usb_receive(struct urb *purb) 
 {
 	struct sk_buff *skb = (struct sk_buff *) purb->context;
 	struct irda_usb_cb *self; 
@@ -1003,7 +1003,7 @@
 
 	/* Deallocate all the Rx path buffers (URBs and skb) */
 	for (i = 0; i < IU_MAX_RX_URBS; i++) {
-		purb_t purb = &(self->rx_urb[i]);
+		struct urb *purb = &(self->rx_urb[i]);
 		struct sk_buff *skb = (struct sk_buff *) purb->context;
 		/* Cancel the receive command */
 		usb_unlink_urb(purb);
diff -urN linux-2.4.20-pre1/drivers/net/irda/irtty.c linux-2.4.20-pre2/drivers/net/irda/irtty.c
--- linux-2.4.20-pre1/drivers/net/irda/irtty.c	Sun Sep 30 12:26:06 2001
+++ linux-2.4.20-pre2/drivers/net/irda/irtty.c	Mon Aug 12 16:34:16 2002
@@ -714,8 +714,6 @@
 
 		self->tx_buff.data += actual;
 		self->tx_buff.len  -= actual;
-
-		self->stats.tx_packets++;		      
 	} else {		
 		/* 
 		 *  Now serial buffer is almost free & we can start 
@@ -723,6 +721,8 @@
 		 */
 		IRDA_DEBUG(5, __FUNCTION__ "(), finished with frame!\n");
 		
+		self->stats.tx_packets++;		      
+
 		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 
 		if (self->new_speed) {
diff -urN linux-2.4.20-pre1/drivers/net/irda/ma600.c linux-2.4.20-pre2/drivers/net/irda/ma600.c
--- linux-2.4.20-pre1/drivers/net/irda/ma600.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/net/irda/ma600.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,356 @@
+/*********************************************************************
+ *                
+ * Filename:      ma600.c
+ * Version:       0.1
+ * Description:   Implementation of the MA600 dongle
+ * Status:        Experimental.
+ * Author:        Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95
+ * Created at:    Sat Jun 10 20:02:35 2000
+ * Modified at:   
+ * Modified by:   
+ *
+ * Note: very thanks to Mr. Maru Wang <maru@mobileaction.com.tw> for providing 
+ *       information on the MA600 dongle
+ * 
+ *     Copyright (c) 2000 Leung, 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
+ *     
+ ********************************************************************/
+
+/* define this macro for release version */
+//#define NDEBUG
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/irtty.h>
+
+#ifndef NDEBUG
+	#undef IRDA_DEBUG
+	#define IRDA_DEBUG(n, args...) (printk(KERN_DEBUG args))
+
+	#undef ASSERT(expr, func)
+	#define ASSERT(expr, func) \
+	if(!(expr)) { \
+	        printk( "Assertion failed! %s,%s,%s,line=%d\n",\
+        	#expr,__FILE__,__FUNCTION__,__LINE__); \
+	        ##func}
+#endif
+
+/* convert hex value to ascii hex */
+static const char hexTbl[] = "0123456789ABCDEF";
+
+
+static void ma600_open(dongle_t *self, struct qos_info *qos);
+static void ma600_close(dongle_t *self);
+static int  ma600_change_speed(struct irda_task *task);
+static int  ma600_reset(struct irda_task *task);
+
+/* control byte for MA600 */
+#define MA600_9600	0x00
+#define MA600_19200	0x01
+#define MA600_38400	0x02
+#define MA600_57600	0x03
+#define MA600_115200	0x04
+#define MA600_DEV_ID1	0x05
+#define MA600_DEV_ID2	0x06
+#define MA600_2400	0x08
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_MA600_DONGLE,
+	ma600_open,
+	ma600_close,
+	ma600_reset,
+	ma600_change_speed,
+};
+
+int __init ma600_init(void)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	return irda_device_register_dongle(&dongle);
+}
+
+void __exit ma600_cleanup(void)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	irda_device_unregister_dongle(&dongle);
+}
+
+/*
+	Power on:
+		(0) Clear RTS and DTR for 1 second
+		(1) Set RTS and DTR for 1 second
+		(2) 9600 bps now
+	Note: assume RTS, DTR are clear before
+*/
+static void ma600_open(dongle_t *self, struct qos_info *qos)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400
+				|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x01;		/* Needs at least 1 ms */	
+	irda_qos_bits_to_value(qos);
+
+	//self->set_dtr_rts(self->dev, FALSE, FALSE);
+	// should wait 1 second
+
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+	// should wait 1 second
+
+	MOD_INC_USE_COUNT;
+}
+
+static void ma600_close(dongle_t *self)
+{
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/* Power off dongle */
+	self->set_dtr_rts(self->dev, FALSE, FALSE);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static __u8 get_control_byte(__u32 speed)
+{
+	__u8 byte;
+
+	switch (speed) {
+	default:
+	case 115200:
+		byte = MA600_115200;
+		break;
+	case 57600:
+		byte = MA600_57600;
+		break;
+	case 38400:
+		byte = MA600_38400;
+		break;
+	case 19200:
+		byte = MA600_19200;
+		break;
+	case 9600:
+		byte = MA600_9600;
+		break;
+	case 2400:
+		byte = MA600_2400;
+		break;
+	}
+
+	return byte;
+}
+
+/*
+ * Function ma600_change_speed (dev, state, speed)
+ *
+ *    Set the speed for the MA600 type dongle. Warning, this 
+ *    function must be called with a process context!
+ *
+ *    Algorithm
+ *    1. Reset
+ *    2. clear RTS, set DTR and wait for 1ms
+ *    3. send Control Byte to the MA600 through TXD to set new baud rate
+ *       wait until the stop bit of Control Byte is sent (for 9600 baud rate, 
+ *       it takes about 10 msec)
+ *    4. set RTS, set DTR (return to NORMAL Operation)
+ *    5. wait at least 10 ms, new setting (baud rate, etc) takes effect here 
+ *       after
+ */
+static int ma600_change_speed(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
+	static __u8 byte;
+	__u8 byte_echo;
+	int ret = 0;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(task != NULL, return -1;);
+
+	if (self->speed_task && self->speed_task != task) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		return MSECS_TO_JIFFIES(10);
+	} else {
+		self->speed_task = task;
+	}
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+	case IRDA_TASK_CHILD_INIT:
+		/* 
+		 * Need to reset the dongle and go to 9600 bps before
+                 * programming 
+		 */
+		if (irda_task_execute(self, ma600_reset, NULL, task, 
+				      (void *) speed)) {
+			/* Dongle need more time to reset */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+	
+			/* give 1 second to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		} else {
+			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
+		}
+		break;
+
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		ret = -1;
+		break;
+
+	case IRDA_TASK_CHILD_DONE:
+		/* Set DTR, Clear RTS */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
+	
+		ret = MSECS_TO_JIFFIES(1);		/* Sleep 1 ms */
+		irda_task_next_state(task, IRDA_TASK_WAIT);
+		break;
+
+	case IRDA_TASK_WAIT:
+		speed = (__u32) task->param;
+		byte = get_control_byte(speed);
+
+		/* Write control byte */
+		self->write(self->dev, &byte, sizeof(byte));
+		
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+
+		/* Wait at least 10 ms */
+		ret = MSECS_TO_JIFFIES(15);
+		break;
+
+	case IRDA_TASK_WAIT1:
+		/* Read control byte echo */
+		self->read(self->dev, &byte_echo, sizeof(byte_echo));
+
+		if(byte != byte_echo) {
+			/* if control byte != echo, I don't know what to do */
+			printk(KERN_WARNING __FUNCTION__ "() control byte written != read!\n");
+			printk(KERN_WARNING "control byte = 0x%c%c\n", 
+			       hexTbl[(byte>>4)&0x0f], hexTbl[byte&0x0f]);
+			printk(KERN_WARNING "byte echo = 0x%c%c\n", 
+			       hexTbl[(byte_echo>>4) & 0x0f], 
+			       hexTbl[byte_echo & 0x0f]);
+		#ifndef NDEBUG
+		} else {
+			IRDA_DEBUG(2, __FUNCTION__ "() control byte write read OK\n");
+		#endif
+		}
+
+		/* Set DTR, Set RTS */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+
+		/* Wait at least 10 ms */
+		ret = MSECS_TO_JIFFIES(10);
+		break;
+
+	case IRDA_TASK_WAIT2:
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		break;
+
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * Function ma600_reset (driver)
+ *
+ *      This function resets the ma600 dongle. Warning, this function 
+ *      must be called with a process context!! 
+ *
+ *      Algorithm:
+ *    	  0. DTR=0, RTS=1 and wait 10 ms
+ *    	  1. DTR=1, RTS=1 and wait 10 ms
+ *        2. 9600 bps now
+ */
+int ma600_reset(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	int ret = 0;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(task != NULL, return -1;);
+
+	if (self->reset_task && self->reset_task != task) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		return MSECS_TO_JIFFIES(10);
+	} else
+		self->reset_task = task;
+	
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Clear DTR and Set RTS */
+		self->set_dtr_rts(self->dev, FALSE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+		ret = MSECS_TO_JIFFIES(10);		/* Sleep 10 ms */
+		break;
+	case IRDA_TASK_WAIT1:
+		/* Set DTR and RTS */
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+		ret = MSECS_TO_JIFFIES(10);		/* Sleep 10 ms */
+		break;
+	case IRDA_TASK_WAIT2:
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);		
+		self->reset_task = NULL;
+		ret = -1;
+	}
+	return ret;
+}
+
+MODULE_AUTHOR("Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95");
+MODULE_DESCRIPTION("MA600 dongle driver version 0.1");
+MODULE_LICENSE("GPL");
+		
+/*
+ * Function init_module (void)
+ *
+ *    Initialize MA600 module
+ *
+ */
+module_init(ma600_init);
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup MA600 module
+ *
+ */
+module_exit(ma600_cleanup);
+
diff -urN linux-2.4.20-pre1/drivers/net/irda/mcp2120.c linux-2.4.20-pre2/drivers/net/irda/mcp2120.c
--- linux-2.4.20-pre1/drivers/net/irda/mcp2120.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/net/irda/mcp2120.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,252 @@
+/*********************************************************************
+ *            
+ *    
+ * Filename:      mcp2120.c
+ * Version:       1.0
+ * Description:   Implementation for the MCP2120 (Microchip)
+ * Status:        Experimental.
+ * Author:        Felix Tang (tangf@eyetap.org)
+ * Created at:    Sun Mar 31 19:32:12 EST 2002
+ * Based on code by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 2002 Felix Tang, 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.
+ *  
+ ********************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/irtty.h>
+
+static int  mcp2120_reset(struct irda_task *task);
+static void mcp2120_open(dongle_t *self, struct qos_info *qos);
+static void mcp2120_close(dongle_t *self);
+static int  mcp2120_change_speed(struct irda_task *task);
+
+#define MCP2120_9600    0x87
+#define MCP2120_19200   0x8B
+#define MCP2120_38400   0x85
+#define MCP2120_57600   0x83
+#define MCP2120_115200  0x81
+
+#define MCP2120_COMMIT  0x11
+
+static struct dongle_reg dongle = {
+	Q_NULL,
+	IRDA_MCP2120_DONGLE,
+	mcp2120_open,
+	mcp2120_close,
+	mcp2120_reset,
+	mcp2120_change_speed,
+};
+
+int __init mcp2120_init(void)
+{
+	return irda_device_register_dongle(&dongle);
+}
+
+void mcp2120_cleanup(void)
+{
+	irda_device_unregister_dongle(&dongle);
+}
+
+static void mcp2120_open(dongle_t *self, struct qos_info *qos)
+{
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	qos->min_turn_time.bits = 0x01;
+
+	MOD_INC_USE_COUNT;
+}
+
+static void mcp2120_close(dongle_t *self)
+{
+	/* Power off dongle */
+        /* reset and inhibit mcp2120 */
+	self->set_dtr_rts(self->dev, TRUE, TRUE);
+	//self->set_dtr_rts(self->dev, FALSE, FALSE);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Function mcp2120_change_speed (dev, speed)
+ *
+ *    Set the speed for the MCP2120.
+ *
+ */
+static int mcp2120_change_speed(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	__u32 speed = (__u32) task->param;
+	__u8 control[2];
+	int ret = 0;
+
+	self->speed_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+		/* Need to reset the dongle and go to 9600 bps before
+                   programming */
+                //printk("Dmcp2120_change_speed irda_task_init\n");
+		if (irda_task_execute(self, mcp2120_reset, NULL, task, 
+				      (void *) speed))
+		{
+			/* Dongle need more time to reset */
+			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
+
+			/* Give reset 1 sec to finish */
+			ret = MSECS_TO_JIFFIES(1000);
+		}
+		break;
+	case IRDA_TASK_CHILD_WAIT:
+		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		ret = -1;
+		break;
+	case IRDA_TASK_CHILD_DONE:
+		/* Set DTR to enter command mode */
+		self->set_dtr_rts(self->dev, TRUE, FALSE);
+                udelay(500);
+
+		switch (speed) {
+		case 9600:
+		default:
+			control[0] = MCP2120_9600;
+                        //printk("mcp2120 9600\n");
+			break;
+		case 19200:
+			control[0] = MCP2120_19200;
+                        //printk("mcp2120 19200\n");
+			break;
+		case 34800:
+			control[0] = MCP2120_38400;
+                        //printk("mcp2120 38400\n");
+			break;
+		case 57600:
+			control[0] = MCP2120_57600;
+                        //printk("mcp2120 57600\n");
+			break;
+		case 115200:
+                        control[0] = MCP2120_115200;
+                        //printk("mcp2120 115200\n");
+			break;
+		}
+	        control[1] = MCP2120_COMMIT;
+	
+		/* Write control bytes */
+                self->write(self->dev, control, 2);
+ 
+                irda_task_next_state(task, IRDA_TASK_WAIT);
+		ret = MSECS_TO_JIFFIES(100);
+                //printk("mcp2120_change_speed irda_child_done\n");
+		break;
+	case IRDA_TASK_WAIT:
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, FALSE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+                //printk("mcp2120_change_speed irda_task_wait\n");
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->speed_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+/*
+ * Function mcp2120_reset (driver)
+ *
+ *      This function resets the mcp2120 dongle.
+ *      
+ *      Info: -set RTS to reset mcp2120
+ *            -set DTR to set mcp2120 software command mode
+ *            -mcp2120 defaults to 9600 baud after reset
+ *
+ *      Algorithm:
+ *      0. Set RTS to reset mcp2120.
+ *      1. Clear RTS and wait for device reset timer of 30 ms (max).
+ *      
+ */
+
+
+static int mcp2120_reset(struct irda_task *task)
+{
+	dongle_t *self = (dongle_t *) task->instance;
+	int ret = 0;
+
+	self->reset_task = task;
+
+	switch (task->state) {
+	case IRDA_TASK_INIT:
+                //printk("mcp2120_reset irda_task_init\n");
+		/* Reset dongle by setting RTS*/
+		self->set_dtr_rts(self->dev, TRUE, TRUE);
+		irda_task_next_state(task, IRDA_TASK_WAIT1);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT1:
+                //printk("mcp2120_reset irda_task_wait1\n");
+                /* clear RTS and wait for at least 30 ms. */
+		self->set_dtr_rts(self->dev, FALSE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_WAIT2);
+		ret = MSECS_TO_JIFFIES(50);
+		break;
+	case IRDA_TASK_WAIT2:
+                //printk("mcp2120_reset irda_task_wait2\n");
+		/* Go back to normal mode */
+		self->set_dtr_rts(self->dev, FALSE, FALSE);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		break;
+	default:
+		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		irda_task_next_state(task, IRDA_TASK_DONE);
+		self->reset_task = NULL;
+		ret = -1;
+		break;
+	}
+	return ret;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
+MODULE_DESCRIPTION("Microchip MCP2120");
+MODULE_LICENSE("GPL");
+
+	
+/*
+ * Function init_module (void)
+ *
+ *    Initialize MCP2120 module
+ *
+ */
+int init_module(void)
+{
+	return mcp2120_init();
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup MCP2120 module
+ *
+ */
+void cleanup_module(void)
+{
+        mcp2120_cleanup();
+}
+#endif /* MODULE */
diff -urN linux-2.4.20-pre1/drivers/net/irda/nsc-ircc.c linux-2.4.20-pre2/drivers/net/irda/nsc-ircc.c
--- linux-2.4.20-pre1/drivers/net/irda/nsc-ircc.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.20-pre2/drivers/net/irda/nsc-ircc.c	Mon Aug 12 16:34:16 2002
@@ -88,10 +88,14 @@
 
 /* These are the known NSC chips */
 static nsc_chip_t chips[] = {
+/*  Name, {cfg registers}, chip id index reg, chip id expected value, revision mask */
 	{ "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, 
 	  nsc_ircc_probe_108, nsc_ircc_init_108 },
 	{ "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8, 
 	  nsc_ircc_probe_338, nsc_ircc_init_338 },
+	/* Contributed by Kevin Thayer - OmniBook 6100 */
+	{ "PC87338?", { 0x2e, 0x15c, 0x398 }, 0x08, 0x00, 0xf8, 
+	  nsc_ircc_probe_338, nsc_ircc_init_338 },
 	{ NULL }
 };
 
@@ -698,6 +702,9 @@
 	switch_bank(iobase, BANK3);
 	version = inb(iobase+MID);
 
+	IRDA_DEBUG(2, __FUNCTION__  "() Driver %s Found chip version %02x\n",
+		   driver_name, version);
+
 	/* Should be 0x2? */
 	if (0x20 != (version & 0xf0)) {
 		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
diff -urN linux-2.4.20-pre1/drivers/net/lasi_82596.c linux-2.4.20-pre2/drivers/net/lasi_82596.c
--- linux-2.4.20-pre1/drivers/net/lasi_82596.c	Tue Oct 16 21:56:29 2001
+++ linux-2.4.20-pre2/drivers/net/lasi_82596.c	Mon Aug 12 16:34:16 2002
@@ -84,6 +84,7 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/types.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -95,8 +96,8 @@
 #include <asm/gsc.h>
 #include <asm/cache.h>
 
-static char version[] __initdata =
-	"82596.c $Revision: 1.20 $\n";
+static char version[] __devinitdata =
+	"82596.c $Revision: 1.29 $\n";
 
 /* DEBUG flags
  */
@@ -120,7 +121,7 @@
 #define DEB_ANY		0xffff
 
 
-#define DEB(x,y)	if (i596_debug & (x)) y
+#define DEB(x,y)	if (i596_debug & (x)) { y; }
 
 
 #define  CHECK_WBACK(addr,len) \
@@ -144,13 +145,13 @@
  */
 
 #ifdef __BIG_ENDIAN
-#define WSWAPrfd(x)  ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPrbd(x)  ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPscb(x)  ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPcmd(x)  ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPtbd(x)  ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPchar(x) ((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPrfd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPrbd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPiscp(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPscb(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPcmd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPtbd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPchar(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
 #define ISCP_BUSY	0x00010000
 #define MACH_IS_APRICOT	0
 #else
@@ -183,18 +184,19 @@
 MODULE_LICENSE("GPL");
 MODULE_PARM(i596_debug, "i");
 MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
+EXPORT_NO_SYMBOLS;
 
 /* Copy frames shorter than rx_copybreak, otherwise pass on up in
  * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
  */
 static int rx_copybreak = 100;
 
+#define MAX_DRIVERS	4	/* max count of drivers */
+
 #define PKT_BUF_SZ	1536
 #define MAX_MC_CNT	64
 
-#define I596_TOTAL_SIZE 17
-
-#define I596_NULL ((void *)0xffffffff)
+#define I596_NULL ((u32)0xffffffff)
 
 #define CMD_EOL		0x8000	/* The last command of the list, stop. */
 #define CMD_SUSP	0x4000	/* Suspend after doing cmd. */
@@ -229,7 +231,7 @@
 struct i596_reg {
 	unsigned short porthi;
 	unsigned short portlo;
-	unsigned long ca;
+	u32            ca;
 };
 
 #define EOF		0x8000
@@ -238,9 +240,9 @@
 struct i596_tbd {
 	unsigned short size;
 	unsigned short pad;
-	struct i596_tbd *next;
-	char *data;
-	long cache_pad[5];		/* Total 32 bytes... */
+	dma_addr_t     next;
+	dma_addr_t     data;
+	u32 cache_pad[5];		/* Total 32 bytes... */
 };
 
 /* The command structure has two 'next' pointers; v_next is the address of
@@ -257,17 +259,21 @@
 	struct i596_cmd *v_next;	/* Address from CPUs viewpoint */
 	unsigned short status;
 	unsigned short command;
-	struct i596_cmd *b_next;	/* Address from i596 viewpoint */
+	dma_addr_t     b_next;	/* Address from i596 viewpoint */
 };
 
 struct tx_cmd {
 	struct i596_cmd cmd;
-	struct i596_tbd *tbd;
+	dma_addr_t     tbd;
 	unsigned short size;
 	unsigned short pad;
 	struct sk_buff *skb;		/* So we can free it after tx */
 	dma_addr_t dma_addr;
-	long cache_pad[1];		/* Total 32 bytes... */
+#ifdef __LP64__
+	u32 cache_pad[6];		/* Total 64 bytes... */
+#else    
+	u32 cache_pad[1];		/* Total 32 bytes... */
+#endif    
 };
 
 struct tdr_cmd {
@@ -295,27 +301,34 @@
 struct i596_rfd {
 	unsigned short stat;
 	unsigned short cmd;
-	struct i596_rfd *b_next;	/* Address from i596 viewpoint */
-	struct i596_rbd *rbd;
+	dma_addr_t     b_next;	/* Address from i596 viewpoint */
+	dma_addr_t     rbd;
 	unsigned short count;
 	unsigned short size;
 	struct i596_rfd *v_next;	/* Address from CPUs viewpoint */
 	struct i596_rfd *v_prev;
-	long cache_pad[2];		/* Total 32 bytes... */
+#ifndef __LP64__    
+	u32 cache_pad[2];		/* Total 32 bytes... */
+#endif    
 };
 
 struct i596_rbd {
+    /* hardware data */
     unsigned short count;
     unsigned short zero1;
-    struct i596_rbd *b_next;
-    unsigned char *b_data;		/* Address from i596 viewpoint */
+    dma_addr_t     b_next;
+    dma_addr_t     b_data;		/* Address from i596 viewpoint */
     unsigned short size;
     unsigned short zero2;
+    /* driver data */
     struct sk_buff *skb;
     struct i596_rbd *v_next;
-    struct i596_rbd *b_addr;		/* This rbd addr from i596 view */
+    dma_addr_t     b_addr;		/* This rbd addr from i596 view */
     unsigned char *v_data;		/* Address from CPUs viewpoint */
 					/* Total 32 bytes... */
+#ifdef __LP64__
+    u32 cache_pad[4];
+#endif    
 };
 
 /* These values as chosen so struct i596_private fits in one page... */
@@ -326,27 +339,27 @@
 struct i596_scb {
 	unsigned short status;
 	unsigned short command;
-	struct i596_cmd *cmd;
-	struct i596_rfd *rfd;
-	unsigned long crc_err;
-	unsigned long align_err;
-	unsigned long resource_err;
-	unsigned long over_err;
-	unsigned long rcvdt_err;
-	unsigned long short_err;
+	dma_addr_t    cmd;
+	dma_addr_t    rfd;
+	u32           crc_err;
+	u32           align_err;
+	u32           resource_err;
+	u32           over_err;
+	u32           rcvdt_err;
+	u32           short_err;
 	unsigned short t_on;
 	unsigned short t_off;
 };
 
 struct i596_iscp {
-	unsigned long stat;
-	struct i596_scb *scb;
+	u32           stat;
+	dma_addr_t    scb;
 };
 
 struct i596_scp {
-	unsigned long sysbus;
-	unsigned long pad;
-	struct i596_iscp *iscp;
+	u32           sysbus;
+	u32            pad;
+	dma_addr_t    iscp;
 };
 
 struct i596_private {
@@ -361,14 +374,14 @@
 	struct i596_rbd rbds[RX_RING_SIZE]	__attribute__((aligned(32)));
 	struct tx_cmd tx_cmds[TX_RING_SIZE]	__attribute__((aligned(32)));
 	struct i596_tbd tbds[TX_RING_SIZE]	__attribute__((aligned(32)));
-	unsigned long stat;
+	u32    stat;
 	int last_restart;
 	struct i596_rfd *rfd_head;
 	struct i596_rbd *rbd_head;
 	struct i596_cmd *cmd_tail;
 	struct i596_cmd *cmd_head;
 	int cmd_backlog;
-	unsigned long last_cmd;
+	u32    last_cmd;
 	struct net_device_stats stats;
 	int next_tx_cmd;
 	int options;
@@ -393,6 +406,8 @@
 	0x00,
 	0x7f /*  *multi IA */ };
 
+static struct pci_dev *fake_pci_dev; /* The fake pci_dev needed for 
+					pci_* functions under ccio. */
 static int dma_consistent = 1;	/* Zero if pci_alloc_consistent() fails */
 
 static int i596_open(struct net_device *dev);
@@ -412,22 +427,28 @@
 
 static inline void CA(struct net_device *dev)
 {
-	gsc_writel(0, (void*)(dev->base_addr + PA_CHANNEL_ATTENTION));
+	gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
 }
 
 
-static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
+static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 
 	u32 v = (u32) (c) | (u32) (x);
+	u16 a, b;
 
-	if (lp->options & OPT_SWAP_PORT)
-		v = ((u32) (v) << 16) | ((u32) (v) >> 16);
+	if (lp->options & OPT_SWAP_PORT) {
+		a = v >> 16;
+		b = v & 0xffff;
+	} else {
+		a = v & 0xffff;
+		b = v >> 16;
+	}
 
-	gsc_writel(v & 0xffff, (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS));
+	gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS);
 	udelay(1);
-	gsc_writel(v >> 16,    (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS));
+	gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
 }
 
 
@@ -439,7 +460,7 @@
 		CHECK_INV(&(lp->iscp), sizeof(struct i596_iscp));
 	}
 	if (!delcnt) {
-		printk("%s: %s, iscp.stat %04lx, didn't clear\n",
+		printk("%s: %s, iscp.stat %04x, didn't clear\n",
 		     dev->name, str, lp->iscp.stat);
 		return -1;
 	}
@@ -472,28 +493,28 @@
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
 
-	printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
+	printk("lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
 	       &lp->scp, lp->scp.sysbus, lp->scp.iscp);
-	printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n",
+	printk("iscp at %p, iscp.stat = %08x, .scb = %08x\n",
 	       &lp->iscp, lp->iscp.stat, lp->iscp.scb);
 	printk("scb at %p, scb.status = %04x, .command = %04x,"
-		" .cmd = %p, .rfd = %p\n",
+		" .cmd = %08x, .rfd = %08x\n",
 	       &lp->scb, lp->scb.status, lp->scb.command,
 		lp->scb.cmd, lp->scb.rfd);
-	printk("   errors: crc %lx, align %lx, resource %lx,"
-               " over %lx, rcvdt %lx, short %lx\n",
+	printk("   errors: crc %x, align %x, resource %x,"
+               " over %x, rcvdt %x, short %x\n",
 		lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
 		lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
 	cmd = lp->cmd_head;
-	while (cmd != I596_NULL) {
-		printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
+	while (cmd != NULL) {
+		printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %08x\n",
 		  cmd, cmd->status, cmd->command, cmd->b_next);
 		cmd = cmd->v_next;
 	}
 	rfd = lp->rfd_head;
 	printk("rfd_head = %p\n", rfd);
 	do {
-		printk ("   %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
+		printk ("   %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
                         " count %04x\n",
 			rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
 			rfd->count);
@@ -502,7 +523,7 @@
 	rbd = lp->rbd_head;
 	printk("rbd_head = %p\n", rbd);
 	do {
-		printk("   %p .count %04x, b_next %p, b_data %p, size %04x\n",
+		printk("   %p .count %04x, b_next %08x, b_data %08x, size %04x\n",
 			rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
 		rbd = rbd->v_next;
 	} while (rbd != lp->rbd_head);
@@ -523,7 +544,7 @@
 }
 #endif
 
-#define virt_to_dma(lp,v) ((char *)(v)-(char *)(lp)+(char *)((lp)->dma_addr))
+#define virt_to_dma(lp,v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)(lp)))
 
 static inline void init_rx_bufs(struct net_device *dev)
 {
@@ -541,7 +562,7 @@
 		if (skb == NULL)
 			panic("82596: alloc_skb() failed");
 		skb_reserve(skb, 2);
-		dma_addr = pci_map_single(NULL, skb->tail,PKT_BUF_SZ,
+		dma_addr = pci_map_single(fake_pci_dev, skb->tail,PKT_BUF_SZ,
 					PCI_DMA_FROMDEVICE);
 		skb->dev = dev;
 		rbd->v_next = rbd+1;
@@ -569,7 +590,7 @@
 	lp->rfd_head = lp->rfds;
 	lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
 	rfd = lp->rfds;
-	rfd->rbd = lp->rbd_head;
+	rfd->rbd = WSWAPrbd(virt_to_dma(lp,lp->rbd_head));
 	rfd->v_prev = lp->rfds + rx_ring_size - 1;
 	rfd = lp->rfds + rx_ring_size - 1;
 	rfd->v_next = lp->rfds;
@@ -588,7 +609,9 @@
 	for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
 		if (rbd->skb == NULL)
 			break;
-		pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+		pci_unmap_single(fake_pci_dev,
+				 (dma_addr_t)WSWAPchar(rbd->b_data), 
+				 PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(rbd->skb);
 	}
 }
@@ -640,14 +663,15 @@
 	lp->iscp.stat = ISCP_BUSY;
 	lp->cmd_backlog = 0;
 
-	lp->cmd_head = lp->scb.cmd = I596_NULL;
+	lp->cmd_head = NULL;
+        lp->scb.cmd = I596_NULL;
 
 	DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name));
 
 	CHECK_WBACK(&(lp->scp), sizeof(struct i596_scp));
 	CHECK_WBACK(&(lp->iscp), sizeof(struct i596_iscp));
 
-	MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_dma(lp,&lp->scp));	
+	MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp));	
 
 	CA(dev);
 
@@ -724,7 +748,7 @@
 	CHECK_INV(rfd, sizeof(struct i596_rfd));
 	while ((rfd->stat) & STAT_C) {	/* Loop while complete frames */
 		if (rfd->rbd == I596_NULL)
-			rbd = I596_NULL;
+			rbd = NULL;
 		else if (rfd->rbd == lp->rbd_head->b_addr) {
 			rbd = lp->rbd_head;
 			CHECK_INV(rbd, sizeof(struct i596_rbd));
@@ -732,12 +756,12 @@
 		else {
 			printk("%s: rbd chain broken!\n", dev->name);
 			/* XXX Now what? */
-			rbd = I596_NULL;
+			rbd = NULL;
 		}
-		DEB(DEB_RXFRAME, printk("  rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+		DEB(DEB_RXFRAME, printk("  rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
 			rfd, rfd->rbd, rfd->stat));
 		
-		if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
+		if (rbd != NULL && ((rfd->stat) & STAT_OK)) {
 			/* a good frame */
 			int pkt_len = rbd->count & 0x3fff;
 			struct sk_buff *skb = rbd->skb;
@@ -754,7 +778,7 @@
 				struct sk_buff *newskb;
 				dma_addr_t dma_addr;
 
-				pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+				pci_unmap_single(fake_pci_dev,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				/* Get fresh skbuff to replace filled one. */
 				newskb = dev_alloc_skb(PKT_BUF_SZ + 4);
 				if (newskb == NULL) {
@@ -768,7 +792,7 @@
 				rx_in_place = 1;
 				rbd->skb = newskb;
 				newskb->dev = dev;
-				dma_addr = pci_map_single(NULL, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+				dma_addr = pci_map_single(fake_pci_dev, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				rbd->v_data = newskb->tail;
 				rbd->b_data = WSWAPchar(dma_addr);
 				CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
@@ -785,7 +809,7 @@
 				skb->dev = dev;
 				if (!rx_in_place) {
 					/* 16 byte align the data fields */
-					pci_dma_sync_single(NULL, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+					pci_dma_sync_single(fake_pci_dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 					skb_reserve(skb, 2);
 					memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
 				}
@@ -819,7 +843,7 @@
 
 		/* Clear the buffer descriptor count and EOF + F flags */
 
-		if (rbd != I596_NULL && (rbd->count & 0x4000)) {
+		if (rbd != NULL && (rbd->count & 0x4000)) {
 			rbd->count = 0;
 			lp->rbd_head = rbd->v_next;
 			CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
@@ -856,7 +880,7 @@
 {
 	struct i596_cmd *ptr;
 
-	while (lp->cmd_head != I596_NULL) {
+	while (lp->cmd_head != NULL) {
 		ptr = lp->cmd_head;
 		lp->cmd_head = ptr->v_next;
 		lp->cmd_backlog--;
@@ -866,19 +890,21 @@
 			{
 				struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
 				struct sk_buff *skb = tx_cmd->skb;
-				pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
+				pci_unmap_single(fake_pci_dev, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
 
 				dev_kfree_skb(skb);
 
 				lp->stats.tx_errors++;
 				lp->stats.tx_aborted_errors++;
 
-				ptr->v_next = ptr->b_next = I596_NULL;
+				ptr->v_next = NULL;
+				ptr->b_next = I596_NULL;
 				tx_cmd->cmd.command = 0;  /* Mark as free */
 				break;
 			}
 		default:
-			ptr->v_next = ptr->b_next = I596_NULL;
+			ptr->v_next = NULL;
+			ptr->b_next = I596_NULL;
 		}
 		CHECK_WBACK_INV(ptr, sizeof(struct i596_cmd));
 	}
@@ -889,7 +915,7 @@
 }
 
 
-static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr)
+static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
 {
 	unsigned long flags;
 
@@ -921,19 +947,19 @@
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
-	int ioaddr = dev->base_addr;
 	unsigned long flags;
 
 	DEB(DEB_ADDCMD,printk("i596_add_cmd cmd_head %p\n", lp->cmd_head));
 
 	cmd->status = 0;
 	cmd->command |= (CMD_EOL | CMD_INTR);
-	cmd->v_next = cmd->b_next = I596_NULL;
+	cmd->v_next = NULL;
+	cmd->b_next = I596_NULL;
 	CHECK_WBACK(cmd, sizeof(struct i596_cmd));
 
 	spin_lock_irqsave (&lp->lock, flags);
 
-	if (lp->cmd_head != I596_NULL) {
+	if (lp->cmd_head != NULL) {
 		lp->cmd_tail->v_next = cmd;
 		lp->cmd_tail->b_next = WSWAPcmd(virt_to_dma(lp,&cmd->status));
 		CHECK_WBACK(lp->cmd_tail, sizeof(struct i596_cmd));
@@ -958,7 +984,7 @@
 
 		printk("%s: command unit timed out, status resetting.\n", dev->name);
 #if 1
-		i596_reset(dev, lp, ioaddr);
+		i596_reset(dev, lp);
 #endif
 	}
 }
@@ -1011,8 +1037,6 @@
 		goto out_remove_rx_bufs;
 	}
 
-	request_mem_region(dev->base_addr, I596_TOTAL_SIZE, "i82596");
-
 	netif_start_queue(dev);
 
 	return 0;
@@ -1029,7 +1053,6 @@
 static void i596_tx_timeout (struct net_device *dev)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
-	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
 	DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n",
@@ -1041,7 +1064,7 @@
 	if (lp->last_restart == lp->stats.tx_packets) {
 		DEB(DEB_ERRORS,printk ("Resetting board.\n"));
 		/* Shutdown and restart */
-		i596_reset (dev, lp, ioaddr);
+		i596_reset (dev, lp);
 	} else {
 		/* Issue a channel attention signal */
 		DEB(DEB_ERRORS,printk ("Kicking board.\n"));
@@ -1064,8 +1087,8 @@
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	dev->trans_start = jiffies;
 
-	DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
-				skb->len, (unsigned int)skb->data));
+	DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%p) called\n", dev->name,
+				skb->len, skb->data));
 
 	netif_stop_queue(dev);
 
@@ -1092,7 +1115,7 @@
 		tbd->pad = 0;
 		tbd->size = EOF | length;
 
-		tx_cmd->dma_addr = pci_map_single(NULL, skb->data, skb->len, 
+		tx_cmd->dma_addr = pci_map_single(fake_pci_dev, skb->data, skb->len, 
 				PCI_DMA_TODEVICE);
 		tbd->data = WSWAPchar(tx_cmd->dma_addr);
 
@@ -1126,7 +1149,7 @@
 
 #define LAN_PROM_ADDR	0xF0810000
 
-static int __init i82596_probe(struct net_device *dev, int options)
+static int __devinit i82596_probe(struct net_device *dev)
 {
 	int i;
 	struct i596_private *lp;
@@ -1139,12 +1162,12 @@
 			    sizeof(struct i596_rfd));
 	    return -ENODEV;
 	}
-	if (sizeof(struct i596_rbd) != 32) {
+	if ((sizeof(struct i596_rbd) % 32) != 0) {
 	    printk("82596: sizeof(struct i596_rbd) = %d\n",
 			    sizeof(struct i596_rbd));
 	    return -ENODEV;
 	}
-	if (sizeof(struct tx_cmd) != 32) {
+	if ((sizeof(struct tx_cmd) % 32) != 0) {
 	    printk("82596: sizeof(struct tx_cmd) = %d\n",
 			    sizeof(struct tx_cmd));
 	    return -ENODEV;
@@ -1154,27 +1177,25 @@
 			    sizeof(struct i596_tbd));
 	    return -ENODEV;
 	}
+#ifndef __LP64__
 	if (sizeof(struct i596_private) > 4096) {
 	    printk("82596: sizeof(struct i596_private) = %d\n",
 			    sizeof(struct i596_private));
 	    return -ENODEV;
 	}
-
-	/* FIXME:
-	    Currently this works only, if set-up from lasi.c.
-	    This should be changed to use probing too !
-	*/
+#endif
 
 	if (!dev->base_addr || !dev->irq)
-	    return -ENODEV;
+		return -ENODEV;
 
-	if (pdc_lan_station_id( (char*)&eth_addr, (void*)dev->base_addr)) {
-	    for(i=0;i<6;i++)
-		eth_addr[i] = gsc_readb(LAN_PROM_ADDR+i);
-	    printk("82596.c: MAC of HP700 LAN blindely read from the prom!\n");
+	if (pdc_lan_station_id(eth_addr, dev->base_addr)) {
+		for (i=0; i < 6; i++) {
+			eth_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
+		}
+		printk("82596.c: MAC of HP700 LAN read from EEPROM\n");
 	}
 
-	dev->mem_start = (int)pci_alloc_consistent( NULL, 
+	dev->mem_start = (unsigned long) pci_alloc_consistent(fake_pci_dev, 
 		sizeof(struct i596_private), &dma_addr);
 	if (!dev->mem_start) {
 		printk("%s: Couldn't get consistent shared memory\n", dev->name);
@@ -1210,11 +1231,10 @@
 
 	lp = (struct i596_private *) dev->priv;
 	DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
-			dev->name, (unsigned long)lp,
-			sizeof(struct i596_private), (unsigned long)&lp->scb));
-	memset((void *) lp, 0, sizeof(struct i596_private));
+		dev->name, (unsigned long)lp,
+		sizeof(struct i596_private), (unsigned long)&lp->scb));
+	memset(lp, 0, sizeof(struct i596_private));
 
-	lp->options = options;
 	lp->scb.command = 0;
 	lp->scb.cmd = I596_NULL;
 	lp->scb.rfd = I596_NULL;
@@ -1227,18 +1247,6 @@
 }
 
 
-int __init lasi_i82596_probe(struct net_device *dev)
-{
-	return i82596_probe(dev, 0);
-}
-
-
-int __init asp_i82596_probe(struct net_device *dev)
-{
-	return i82596_probe(dev, OPT_SWAP_PORT);
-}
-
-
 static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
@@ -1276,7 +1284,7 @@
 		if ((status & 0x2000))
 			DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
 
-		while (lp->cmd_head != I596_NULL) {
+		while (lp->cmd_head != NULL) {
 			CHECK_INV(lp->cmd_head, sizeof(struct i596_cmd));
 			if (!(lp->cmd_head->status & STAT_C))
 				break;
@@ -1309,7 +1317,7 @@
 					if ((ptr->status) & 0x1000)
 						lp->stats.tx_aborted_errors++;
 				}
-				pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
+				pci_unmap_single(fake_pci_dev, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
 				dev_kfree_skb_irq(skb);
 
 				tx_cmd->cmd.command = 0; /* Mark free */
@@ -1338,7 +1346,8 @@
 				ptr->command = 0;
 				break;
 			}
-			ptr->v_next = ptr->b_next = I596_NULL;
+			ptr->v_next = NULL;
+		        ptr->b_next = I596_NULL;
 			CHECK_WBACK(ptr, sizeof(struct i596_cmd));
 			lp->last_cmd = jiffies;
 		}
@@ -1348,7 +1357,7 @@
 		 * only add to the cmd queue when the CU is stopped.
 		 */
 		ptr = lp->cmd_head;
-		while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
+		while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
 			struct i596_cmd *prev = ptr;
 
 			ptr->command &= 0x1fff;
@@ -1356,7 +1365,7 @@
 			CHECK_WBACK_INV(prev, sizeof(struct i596_cmd));
 		}
 
-		if ((lp->cmd_head != I596_NULL))
+		if ((lp->cmd_head != NULL))
 			ack_cmd |= CUC_START;
 		lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&lp->cmd_head->status));
 		CHECK_WBACK_INV(&lp->scb, sizeof(struct i596_scb));
@@ -1422,8 +1431,6 @@
 	free_irq(dev->irq, dev);
 	remove_rx_bufs(dev);
 
-	release_mem_region(dev->base_addr, I596_TOTAL_SIZE);
-
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -1503,48 +1510,106 @@
 	}
 }
 
-#ifdef HAVE_DEVLIST
-static unsigned int i596_portlist[] __initdata =
-{0x300, 0};
-struct netdev_entry i596_drv =
-{"lasi_i82596", lasi_i82596_probe, I596_TOTAL_SIZE, i596_portlist};
-#endif
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
+static int debug = -1;
+
+static int num_drivers;
+static struct net_device *netdevs[MAX_DRIVERS];
 
-#ifdef MODULE
-static char devicename[9] =
-{0,};
-static struct net_device dev_82596 =
+static int __devinit
+lan_init_chip(struct parisc_device *dev)
 {
-	name: devicename,	/* device name inserted by drivers/net/net_init.c */
-	init: lasi_i82596_probe,
+	struct	net_device *netdevice;
+	int	retval;
+
+	if (num_drivers >= MAX_DRIVERS) {
+		/* max count of possible i82596 drivers reached */
+		return -ENODEV;
+	}
+	
+	fake_pci_dev = ccio_get_fake(dev);
+
+	if (!dev->irq) {
+		printk(KERN_ERR __FILE__ ": IRQ not found for i82596 at 0x%lx\n", dev->hpa);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa, dev->irq);
+
+	netdevice = alloc_etherdev(0);
+	if (!netdevice)
+		return -ENOMEM;
+
+	netdevice->base_addr = dev->hpa;
+	netdevice->irq = dev->irq;
+	netdevice->init = i82596_probe;
+
+	retval = register_netdev(netdevice);
+	if (retval) {
+		printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval);
+		kfree(netdevice);
+		return -ENODEV;
+	};
+	if (dev->id.sversion == 0x72) {
+		((struct i596_private *)netdevice->priv)->options = OPT_SWAP_PORT;
+	}
+
+	netdevs[num_drivers++] = netdevice;
+
+	return retval;
+}
+
+
+static struct parisc_device_id lan_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 },
+	{ 0, }
 };
 
+MODULE_DEVICE_TABLE(parisc, lan_tbl);
 
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
-static int debug = -1;
+static struct parisc_driver lan_driver = {
+	name:		"Apricot",
+	id_table:	lan_tbl,
+	probe:		lan_init_chip,
+};
 
-int init_module(void)
+static int __devinit lasi_82596_init(void)
 {
 	if (debug >= 0)
 		i596_debug = debug;
-	if (register_netdev(&dev_82596) != 0)
-		return -EIO;
-	return 0;
+	return register_parisc_driver(&lan_driver);
 }
 
-void cleanup_module(void)
+module_init(lasi_82596_init);
+
+static void __exit lasi_82596_exit(void)
 {
-	unregister_netdev(&dev_82596);
-	lp = (struct i596_private *) dev_82596.priv;
+	int i;
 
-	if (dma_consistent)
-		pci_free_consistent( NULL, sizeof( struct i596_private), 
-			dev_82596.mem_start, lp->dma_addr);
-	else
-		free_page ((u32)(dev_82596.mem_start));
+	for (i=0; i<MAX_DRIVERS; i++) {
+		struct i596_private *lp;
+		struct net_device *netdevice;
+		
+		netdevice = netdevs[i];
+		if (!netdevice) 
+			continue;
+		
+		unregister_netdev(netdevice);
+
+		lp = (struct i596_private *) netdevice->priv;
+		if (dma_consistent)
+			pci_free_consistent(fake_pci_dev, 
+					    sizeof(struct i596_private), 
+				(void *)netdevice->mem_start, lp->dma_addr);
+		else
+			free_page(netdevice->mem_start);
+
+		netdevice->priv = NULL;
+	}
 
-	dev_82596.priv = NULL;
+	unregister_parisc_driver(&lan_driver);
 }
 
-#endif				/* MODULE */
+module_exit(lasi_82596_exit);
diff -urN linux-2.4.20-pre1/drivers/net/natsemi.c linux-2.4.20-pre2/drivers/net/natsemi.c
--- linux-2.4.20-pre1/drivers/net/natsemi.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/natsemi.c	Mon Aug 12 16:34:16 2002
@@ -108,6 +108,10 @@
 	version 1.0.13:
 		* crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
 
+	version 1.0.15:
+		* Get rid of cable_magic flag
+		* use new (National provided) solution for cable magic issue
+
 	TODO:
 	* big endian support with CFG:BEM instead of cpu_to_le32
 	* support for an external PHY
@@ -146,8 +150,8 @@
 #include <asm/uaccess.h>
 
 #define DRV_NAME	"natsemi"
-#define DRV_VERSION	"1.07+LK1.0.14"
-#define DRV_RELDATE	"Nov 27, 2001"
+#define DRV_VERSION	"1.07+LK1.0.15"
+#define DRV_RELDATE	"Jul 23, 2002"
 
 /* Updated to recommendations in pci-skeleton v2.03. */
 
@@ -191,8 +195,8 @@
    The media type is usually passed in 'options[]'.
 */
 #define MAX_UNITS 8		/* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[MAX_UNITS];
+static int full_duplex[MAX_UNITS];
 
 /* Operational parameters that are set at compile time. */
 
@@ -203,7 +207,7 @@
    There are no ill effects from too-large receive rings. */
 #define TX_RING_SIZE	16
 #define TX_QUEUE_LEN	10 /* Limit ring entries actually used, min 4. */
-#define RX_RING_SIZE	64
+#define RX_RING_SIZE	32
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
@@ -402,14 +406,12 @@
 	SDCFG			= 0xF8
 };
 /* the values for the 'magic' registers above (PGSEL=1) */
-#ifdef CONFIG_NATSEMI_CABLE_MAGIC
-#define PMDCSR_VAL	0x1898
-#else
-#define PMDCSR_VAL	0x189C
-#endif
+#define PMDCSR_VAL	0x189c	/* enable preferred adaptation circuitry */
 #define TSTDAT_VAL	0x0
 #define DSPCFG_VAL	0x5040
-#define SDCFG_VAL	0x008c
+#define SDCFG_VAL	0x008c	/* set voltage thresholds for Signal Detect */
+#define DSPCFG_LOCK	0x20	/* coefficient lock bit in DSPCFG */
+#define TSTDAT_FIXED	0xe8	/* magic number for bad coefficients */
 
 /* misc PCI space registers */
 enum pci_register_offsets {
@@ -639,6 +641,8 @@
 	u32 SavedClkRun;
 	/* silicon revision */
 	u32 srr;
+	/* expected DSPCFG value */
+	u16 dspcfg;
 	/* MII transceiver section. */
 	u16 advertising; /* NWay media advertisement */
 	unsigned int iosize;
@@ -653,6 +657,8 @@
 static void natsemi_reload_eeprom(struct net_device *dev);
 static void natsemi_stop_rxtx(struct net_device *dev);
 static int netdev_open(struct net_device *dev);
+static void do_cable_magic(struct net_device *dev);
+static void undo_cable_magic(struct net_device *dev);
 static void check_link(struct net_device *dev);
 static void netdev_timer(unsigned long data);
 static void tx_timeout(struct net_device *dev);
@@ -774,7 +780,7 @@
 		option = dev->mem_start;
 
 	/* The lower four bits are the media type. */
-	if (option > 0) {
+	if (option) {
 		if (option & 0x200)
 			np->full_duplex = 1;
 		if (option & 15)
@@ -782,7 +788,7 @@
 				"%s: ignoring user supplied media type %d",
 				dev->name, option & 15);
 	}
-	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
+	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt])
 		np->full_duplex = 1;
 
 	/* The chip-specific entries in the device structure. */
@@ -1081,6 +1087,54 @@
 	return 0;
 }
 
+static void do_cable_magic(struct net_device *dev)
+{
+	/*
+	 * 100 MBit links with short cables can trip an issue with the chip.
+	 * The problem manifests as lots of CRC errors and/or flickering
+	 * activity LED while idle.  This process is based on instructions
+	 * from engineers at National.
+	 */
+	if (readl(dev->base_addr + ChipConfig) & CfgSpeed100) {
+		u16 data;
+
+		writew(1, dev->base_addr + PGSEL);
+		/*
+		 * coefficient visibility should already be enabled via
+		 * DSPCFG | 0x1000
+		 */
+		data = readw(dev->base_addr + TSTDAT) & 0xff;
+		/*
+		 * the value must be negative, and within certain values
+		 * (these values all come from National)
+		 */
+		if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) {
+			struct netdev_private *np = dev->priv;
+
+			/* the bug has been triggered - fix the coefficient */
+			writew(TSTDAT_FIXED, dev->base_addr + TSTDAT);
+			/* lock the value */
+			data = readw(dev->base_addr + DSPCFG);
+			np->dspcfg = data | DSPCFG_LOCK;
+			writew(np->dspcfg, dev->base_addr + DSPCFG);
+		}
+		writew(0, dev->base_addr + PGSEL);
+	}
+}
+
+static void undo_cable_magic(struct net_device *dev)
+{
+	u16 data;
+	struct netdev_private *np = dev->priv;
+
+	writew(1, dev->base_addr + PGSEL);
+	/* make sure the lock bit is clear */
+	data = readw(dev->base_addr + DSPCFG);
+	np->dspcfg = data & ~DSPCFG_LOCK;
+	writew(np->dspcfg, dev->base_addr + DSPCFG);
+	writew(0, dev->base_addr + PGSEL);
+}
+
 static void check_link(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
@@ -1094,6 +1148,7 @@
 				printk(KERN_NOTICE "%s: link down.\n", 
 					dev->name);
 			netif_carrier_off(dev);
+			undo_cable_magic(dev);
 		}
 		return;
 	}
@@ -1101,6 +1156,7 @@
 		if (netif_msg_link(np))
 			printk(KERN_NOTICE "%s: link up.\n", dev->name);
 		netif_carrier_on(dev);
+		do_cable_magic(dev);
 	}
 
 	duplex = np->full_duplex || (chipcfg & CfgFullDuplex ? 1 : 0);
@@ -1154,6 +1210,7 @@
 	writew(DSPCFG_VAL, ioaddr + DSPCFG);
 	writew(SDCFG_VAL, ioaddr + SDCFG);
 	writew(0, ioaddr + PGSEL);
+	np->dspcfg = DSPCFG_VAL;
 
 	/* Enable PHY Specific event based interrupts.  Link state change
 	   and Auto-Negotiation Completion are among the affected.
@@ -1216,8 +1273,10 @@
 	writel(StatsClear, ioaddr + StatsCtrl); /* Clear Stats */
 }
 
-/* 
- * The frequency on this has been increased because of a nasty little problem.
+/*
+ * Purpose:
+ * check for sudden death of the NIC:
+ *
  * It seems that a reference set for this chip went out with incorrect info,
  * and there exist boards that aren't quite right.  An unexpected voltage drop
  * can cause the PHY to get itself in a weird state (basically reset..).
@@ -1239,12 +1298,15 @@
 			   dev->name);
 	}
 
+	spin_lock_irq(&np->lock);
+
 	/* check for a nasty random phy-reset - use dspcfg as a flag */
 	writew(1, ioaddr+PGSEL);
 	dspcfg = readw(ioaddr+DSPCFG);
 	writew(0, ioaddr+PGSEL);
-	if (dspcfg != DSPCFG_VAL) {
+	if (dspcfg != np->dspcfg) {
 		if (!netif_queue_stopped(dev)) {
+			spin_unlock_irq(&np->lock);
 			if (netif_msg_hw(np))
 				printk(KERN_NOTICE "%s: possible phy reset: "
 					"re-initializing\n", dev->name);
@@ -1256,10 +1318,10 @@
 		} else {
 			/* hurry back */
 			next_tick = HZ;
+			spin_unlock_irq(&np->lock);
 		}
 	} else {
 		/* init_registers() calls check_link() for the above case */
-		spin_lock_irq(&np->lock);
 		check_link(dev);
 		spin_unlock_irq(&np->lock);
 	}
@@ -1325,8 +1387,8 @@
 {
 	struct netdev_private *np = dev->priv;
 	np->rx_ring = pci_alloc_consistent(np->pci_dev,
-				sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
-				&np->ring_dma);
+	    sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
+	    &np->ring_dma);
 	if (!np->rx_ring)
 		return -ENOMEM;
 	np->tx_ring = &np->rx_ring[RX_RING_SIZE];
@@ -1530,8 +1592,11 @@
 		if (intr_status == 0)
 			break;
 
-		if (intr_status & (IntrRxDone | IntrRxIntr))
+		if (intr_status &
+		   (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
+		    IntrRxErr | IntrRxOverrun)) {
 			netdev_rx(dev);
+		}
 
 		if (intr_status & (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr) ) {
 			spin_lock(&np->lock);
@@ -1544,9 +1609,10 @@
 			netdev_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
-			printk(KERN_WARNING "%s: Too much work at interrupt, "
-				   "status=%#08x.\n",
-				   dev->name, intr_status);
+			if (netif_msg_intr(np))
+				printk(KERN_WARNING 
+				    "%s: Too much work at interrupt, "
+				    "status=%#08x.\n", dev->name, intr_status);
 			break;
 		}
 	} while (1);
@@ -1685,7 +1751,7 @@
 			np->tx_config += 2;
 		if (netif_msg_tx_err(np))
 			printk(KERN_NOTICE 
-				"%s: increased Tx theshold, txcfg %#08x.\n",
+				"%s: increased Tx threshold, txcfg %#08x.\n",
 				dev->name, np->tx_config);
 		writel(np->tx_config, ioaddr + TxConfig);
 	}
@@ -2332,7 +2398,8 @@
 		/* enable the WOL interrupt.
 		 * Could be used to send a netlink message.
 		 */
-		writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask);
+		writel(WOLPkt | LinkChange, ioaddr + IntrMask);
+		writel(1, ioaddr + IntrEnable);
 	}
 }
 
@@ -2391,7 +2458,7 @@
 	drain_ring(dev);
 	free_ring(dev);
 
-	 {
+	{
 		u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary;
 		if (wol) {
 			/* restart the NIC in WOL mode.
diff -urN linux-2.4.20-pre1/drivers/net/ni65.c linux-2.4.20-pre2/drivers/net/ni65.c
--- linux-2.4.20-pre1/drivers/net/ni65.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/ni65.c	Mon Aug 12 16:34:16 2002
@@ -1105,7 +1105,7 @@
 	{
 		short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		struct tmd *tmdp;
-		long flags;
+		unsigned long flags;
 
 #ifdef XMT_VIA_SKB
 		if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
diff -urN linux-2.4.20-pre1/drivers/net/pcmcia/3c574_cs.c linux-2.4.20-pre2/drivers/net/pcmcia/3c574_cs.c
--- linux-2.4.20-pre1/drivers/net/pcmcia/3c574_cs.c	Tue Nov 13 09:02:30 2001
+++ linux-2.4.20-pre2/drivers/net/pcmcia/3c574_cs.c	Mon Aug 12 16:34:16 2002
@@ -1207,7 +1207,7 @@
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 		{
 			int saved_window;
-			long flags;
+			unsigned long flags;
 
 			save_flags(flags);
 			cli();
@@ -1221,7 +1221,7 @@
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		{
 			int saved_window;
-			long flags;
+			unsigned long flags;
 
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
diff -urN linux-2.4.20-pre1/drivers/net/pcmcia/aironet4500_cs.c linux-2.4.20-pre2/drivers/net/pcmcia/aironet4500_cs.c
--- linux-2.4.20-pre1/drivers/net/pcmcia/aironet4500_cs.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.20-pre2/drivers/net/pcmcia/aironet4500_cs.c	Mon Aug 12 16:34:16 2002
@@ -347,7 +347,7 @@
 static void awc_detach(dev_link_t *link)
 {
 	dev_link_t **linkp;
-	long flags;
+	unsigned long flags;
 	int i=0;
 
 	DEBUG(0, "awc_detach(0x%p)\n", link);
diff -urN linux-2.4.20-pre1/drivers/net/pcmcia/fmvj18x_cs.c linux-2.4.20-pre2/drivers/net/pcmcia/fmvj18x_cs.c
--- linux-2.4.20-pre1/drivers/net/pcmcia/fmvj18x_cs.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/pcmcia/fmvj18x_cs.c	Mon Aug 12 16:34:16 2002
@@ -1254,7 +1254,7 @@
     ioaddr_t ioaddr = dev->base_addr;
     struct local_info_t *lp = (struct local_info_t *)dev->priv;
     unsigned char mc_filter[8];		 /* Multicast hash filter */
-    long flags;
+    unsigned long flags;
     int i;
     
     if (dev->flags & IFF_PROMISC) {
diff -urN linux-2.4.20-pre1/drivers/net/pcmcia/smc91c92_cs.c linux-2.4.20-pre2/drivers/net/pcmcia/smc91c92_cs.c
--- linux-2.4.20-pre1/drivers/net/pcmcia/smc91c92_cs.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/pcmcia/smc91c92_cs.c	Mon Aug 12 16:34:16 2002
@@ -1778,7 +1778,7 @@
 {
     ioaddr_t ioaddr = dev->base_addr;
     u_int multicast_table[ 2 ] = { 0, };
-    long flags;
+    unsigned long flags;
     u_short rx_cfg_setting;
     
     if (dev->flags & IFF_PROMISC) {
diff -urN linux-2.4.20-pre1/drivers/net/pcmcia/wavelan.h linux-2.4.20-pre2/drivers/net/pcmcia/wavelan.h
--- linux-2.4.20-pre1/drivers/net/pcmcia/wavelan.h	Fri Mar  2 11:02:15 2001
+++ linux-2.4.20-pre2/drivers/net/pcmcia/wavelan.h	Mon Aug 12 16:34:16 2002
@@ -88,6 +88,7 @@
  */
 const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
 
+
 /*************************** PC INTERFACE ****************************/
 
 /* WaveLAN host interface definitions */
@@ -316,6 +317,7 @@
 /* Calculate offset of a field in the above structure */
 #define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
 
+
 /*
  * Modem Management Controller (MMC) read structure.
  */
@@ -373,6 +375,7 @@
 /* Calculate offset of a field in the above structure */
 #define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
 
+
 /* Make the two above structures one */
 typedef union mm_t
 {
diff -urN linux-2.4.20-pre1/drivers/net/pcmcia/wavelan_cs.c linux-2.4.20-pre2/drivers/net/pcmcia/wavelan_cs.c
--- linux-2.4.20-pre1/drivers/net/pcmcia/wavelan_cs.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/pcmcia/wavelan_cs.c	Mon Aug 12 16:34:16 2002
@@ -41,7 +41,8 @@
  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
  * - reorganize kmallocs in wavelan_attach, checking all for failure
  *   and releasing the previous allocations if one fails
- *
+ * <No longer true, we reverted to the version in the Pcmcia package
+ *  which was correct in the first place - Jean II>
  *
  ****************************************************************************
  *   Copyright 1995
@@ -72,6 +73,34 @@
 
 /*------------------------------------------------------------------*/
 /*
+ * Wrapper for disabling interrupts.
+ * (note : inline, so optimised away)
+ */
+static inline void
+wv_splhi(net_local *		lp,
+	 unsigned long *	pflags)
+{
+  spin_lock_irqsave(&lp->spinlock, *pflags);
+  /* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(net_local *		lp,
+	unsigned long *		pflags)
+{
+  spin_unlock_irqrestore(&lp->spinlock, *pflags);
+
+  /* Note : enabling interrupts on the hardware is done in wv_ru_start()
+   * via : outb(OP1_INT_ENABLE, LCCR(base));
+   */
+}
+
+/*------------------------------------------------------------------*/
+/*
  * Wrapper for reporting error to cardservices
  */
 static void cs_error(client_handle_t handle, int func, int ret)
@@ -103,7 +132,7 @@
 
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the wavelan
  */
 
 /*------------------------------------------------------------------*/
@@ -138,7 +167,7 @@
 {
   hacr_write(base, hacr);
   /* delay might only be needed sometimes */
-  mdelay(1L);
+  mdelay(1);
 } /* hacr_write_slow */
 
 /*------------------------------------------------------------------*/
@@ -569,18 +598,18 @@
 #endif
   
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
   
   m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
   mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
   
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
   if(mode==NWID_PROMISC)
     lp->cell_search=1;
   else
-	lp->cell_search=0;
+    lp->cell_search=0;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
 }
 
 /* Find a record in the WavePoint table matching a given NWID */
@@ -737,7 +766,7 @@
   ioaddr_t              base = lp->dev->base_addr;  
   mm_t                  m;
   unsigned long         flags;
-  
+
   if(wavepoint==lp->curr_point)          /* Sanity check... */
     {
       wv_nwid_filter(!NWID_PROMISC,lp);
@@ -749,16 +778,16 @@
 #endif
  	
   /* Disable interrupts & save flags */
-  spin_lock_irqsave(&lp->lock, flags);
-  
+  wv_splhi(lp, &flags);
+
   m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
   m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
   
   mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
   
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
+  wv_splx(lp, &flags);
+
   wv_nwid_filter(!NWID_PROMISC,lp);
   lp->curr_point=wavepoint;
 }
@@ -775,6 +804,11 @@
   wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
   net_local *lp=(net_local *)dev->priv;              /* Device info */
 
+#ifdef I_NEED_THIS_FEATURE
+  /* Some people don't need this, some other may need it */
+  nwid=nwid^ntohs(beacon->domain_id);
+#endif
+
 #if WAVELAN_ROAMING_DEBUG > 1
   printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
   printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
@@ -832,7 +866,9 @@
 /*------------------------------------------------------------------*/
 /*
  * Routine to synchronously send a command to the i82593 chip. 
- * Should be called with interrupts enabled.
+ * Should be called with interrupts disabled.
+ * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(),
+ *  wv_82593_config() & wv_diag())
  */
 static int
 wv_82593_cmd(device *	dev,
@@ -841,74 +877,98 @@
 	     int	result)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
   int		status;
+  int		wait_completed;
   long		spin;
-  u_long	flags;
 
   /* Spin until the chip finishes executing its current command (if any) */
+  spin = 1000;
   do
     {
-      spin_lock_irqsave (&lp->lock, flags);
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  /* If the interrupt hasn't be posted */
+  if(spin <= 0)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
 
   /* Issue the command to the controller */
   outb(cmd, LCCR(base));
 
-  /* If we don't have to check the result of the command */
+  /* If we don't have to check the result of the command
+   * Note : this mean that the irq handler will deal with that */
   if(result == SR0_NO_RESULT)
-    {
-      wv_wait_completed = FALSE;
-      return(TRUE);
-    }
+    return(TRUE);
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 1000))
-    udelay(10);
+  /* We are waiting for command completion */
+  wait_completed = TRUE;
 
-  /* If the interrupt handler hasn't be called */
-  if(wv_wait_completed)
+  /* Busy wait while the LAN controller executes the command. */
+  spin = 1000;
+  do
     {
-      outb(OP0_NOP, LCCR(base));
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
       status = inb(LCSR(base));
-      if(status & SR0_INTERRUPT)
+
+      /* Check if there was an interrupt posted */
+      if((status & SR0_INTERRUPT))
 	{
-	  /* There was an interrupt : call the interrupt handler */
-#ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n");
-#endif
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
 
-	  wavelan_interrupt(dev->irq, (void *) dev,
-			    (struct pt_regs *) NULL);
+	  /* Check if interrupt is a command completion */
+	  if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) &&
+	     ((status & SR0_BOTH_RX_TX) != 0x0) &&
+	     !(status & SR0_RECEPTION))
+	    {
+	      /* Signal command completion */
+	      wait_completed = FALSE;
+	    }
+	  else
+	    {
+	      /* Note : Rx interrupts will be handled later, because we can
+	       * handle multiple Rx packets at once */
+#ifdef DEBUG_INTERRUPT_INFO
+	      printk(KERN_INFO "wv_82593_cmd: not our interrupt\n");
+#endif
+	    }
 	}
-      else
-	{
-	  wv_wait_completed = 0; /* XXX */
+    }
+  while(wait_completed && (spin-- > 0));
+
+  /* If the interrupt hasn't be posted */
+  if(wait_completed)
+    {
 #ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n",
-		 str, status);
+      printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n",
+	     str, status);
 #endif
-	  /* We probably should reset the controller here */
-	  return(FALSE);
-	}
+      return(FALSE);
     }
 
-  /* Check the return code provided by the interrupt handler against
+  /* Check the return code returned by the card (see above) against
    * the expected return code provided by the caller */
-  if((lp->status & SR0_EVENT_MASK) != result)
+  if((status & SR0_EVENT_MASK) != result)
     {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n",
-	     str, lp->status);
+      printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n",
+	     str, status);
 #endif
       return(FALSE);
     }
@@ -924,14 +984,16 @@
 static inline int
 wv_diag(device *	dev)
 {
+  int		ret = FALSE;
+
   if(wv_82593_cmd(dev, "wv_diag(): diagnose",
 		  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
-    return(TRUE);
+    ret = TRUE;
 
 #ifdef DEBUG_CONFIG_ERROR
   printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
 #endif
-  return(FALSE);
+  return(ret);
 } /* wv_diag */
 
 /*------------------------------------------------------------------*/
@@ -951,15 +1013,6 @@
   int		chunk_len;
   char *	buf_ptr = buf;
 
-#ifdef OLDIES
-  /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem
-   * quite safe to remove this... */
-
-  /* If buf is NULL, just increment the ring buffer pointer */
-  if(buf == NULL)
-    return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
-#endif
-
   /* Get all the buffer */
   while(len > 0)
     {
@@ -990,70 +1043,32 @@
  * wavelan_interrupt is not an option...), so you may experience
  * some delay sometime...
  */
-static inline void wv_82593_reconfig (device * dev)
+static inline void
+wv_82593_reconfig(device *	dev)
 {
-	net_local *lp = (net_local *) dev->priv;
-	dev_link_t *link = ((net_local *) dev->priv)->link;
+  net_local *		lp = (net_local *)dev->priv;
+  dev_link_t *		link = ((net_local *) dev->priv)->link;
+  unsigned long		flags;
+
+  /* Arm the flag, will be cleard in wv_82593_config() */
+  lp->reconfig_82593 = TRUE;
 
-	/* Check if we can do it now ! */
-	if (!(link->open)) {
-		lp->reconfig_82593 = TRUE;
+  /* Check if we can do it now ! */
+  if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+    }
+  else
+    {
 #ifdef DEBUG_IOCTL_INFO
-		printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
-			dev->name, link->open);
+      printk(KERN_DEBUG
+	     "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n",
+	     dev->name, dev->state, link->open);
 #endif
-	} else {
-		netif_stop_queue (dev);
-
-		lp->reconfig_82593 = FALSE;
-		wv_82593_config (dev);
-		netif_wake_queue (dev);
-	}
-}
-
-#ifdef OLDIES
-/*------------------------------------------------------------------*/
-/*
- * Dumps the current i82593 receive buffer to the console.
- */
-static void wavelan_dump(device *dev)
-{
-  ioaddr_t base = dev->base_addr;
-  int i, c;
-
-  /* disable receiver so we can use channel 1 */
-  outb(OP0_RCV_DISABLE, LCCR(base));
-
-  /* reset receive DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-
-  /* dump into receive buffer */
-  wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
-
-  /* set read pointer to start of receive buffer */
-  outb(0, PIORL(base));
-  outb(0, PIORH(base));
-
-  printk(KERN_DEBUG "wavelan_cs: dump:\n");
-  printk(KERN_DEBUG "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
-  for(i = 0; i < 73; i++){
-    if((i % 16) == 0) {
-      printk("\n0x%02x:", i);
-      if (!i) {
-	printk("   ");
-	continue;
-      }
     }
-    c = inb(PIOP(base));
-    printk("%02x ", c);
-  }
-  printk("\n");
-
-  /* enable the receiver again */
-  wv_ru_start(dev);
 }
-#endif
 
 /********************* DEBUG & INFO SUBROUTINES *********************/
 /*
@@ -1171,6 +1186,8 @@
       return;
     }
 
+  wv_splhi(lp, &flags);
+
   /* Read the mmc */
   mmc_out(base, mmwoff(0, mmw_freeze), 1);
   mmc_read(base, 0, (u_char *)&m, sizeof(m));
@@ -1181,6 +1198,8 @@
   lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
 #endif	/* WIRELESS_EXT */
 
+  wv_splx(lp, &flags);
+
   printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -1265,6 +1284,7 @@
 wv_dev_show(device *	dev)
 {
   printk(KERN_DEBUG "dev:");
+  printk(" state=%lX,", dev->state);
   printk(" trans_start=%ld,", dev->trans_start);
   printk(" flags=0x%x,", dev->flags);
   printk("\n");
@@ -1892,7 +1912,7 @@
 #endif
 
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Look what is the request */
   switch(cmd)
@@ -1968,7 +1988,7 @@
 
     case SIOCGIWFREQ:
       /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody XXX - especially old cards...) */
+       * (does it work for everybody ? - especially old cards...) */
       if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
 	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
 	{
@@ -2239,15 +2259,17 @@
 	{
 	  struct iw_range	range;
 
-	  /* Set the length (very important for backward compatibility) */
-	  wrq->u.data.length = sizeof(struct iw_range);
+	   /* Set the length (very important for backward compatibility) */
+	   wrq->u.data.length = sizeof(struct iw_range);
 
-	  /* Set all the info we don't care or don't know about to zero */
-	  memset(&range, 0, sizeof(range));
+	   /* Set all the info we don't care or don't know about to zero */
+	   memset(&range, 0, sizeof(range));
 
-	  /* Set the Wireless Extension versions */
-	  range.we_version_compiled = WIRELESS_EXT;
-	  range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#if WIRELESS_EXT > 10
+	   /* Set the Wireless Extension versions */
+	   range.we_version_compiled = WIRELESS_EXT;
+	   range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
 
 	  /* Set information in the range struct */
 	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
@@ -2517,7 +2539,7 @@
     }
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2543,11 +2565,8 @@
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
-  if (lp == NULL) /* XXX will this ever occur? */
-    return NULL;
-
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   wstats = &lp->wstats;
 
@@ -2573,7 +2592,7 @@
   wstats->discard.misc = 0L;
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
@@ -2692,12 +2711,6 @@
   skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef DEBUG_RX_INFO
-  /* Another glitch : Due to the way the GET_PACKET macro is written,
-   * we are not sure to have the same thing in skb->data. On the other
-   * hand, skb->mac.raw is not defined everywhere...
-   * For versions between 1.2.13 and those where skb->mac.raw appear,
-   * I don't have a clue...
-   */
   wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
 #endif	/* DEBUG_RX_INFO */
      
@@ -2731,9 +2744,7 @@
 	  wl_roam_gather(dev, skb->data, stats);
 #endif	/* WAVELAN_ROAMING */
 	  
-      /* Spying stuff */
 #ifdef WIRELESS_SPY
-      /* Same as above */
       wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
 #endif	/* WIRELESS_SPY */
 #ifdef HISTOGRAM
@@ -2766,6 +2777,7 @@
  * called to do the actual transfer of the card's data including the
  * ethernet header into a packet consisting of an sk_buff chain.
  * (called by wavelan_interrupt())
+ * Note : the spinlock is already grabbed for us and irq are disabled.
  */
 static inline void
 wv_packet_rcv(device *	dev)
@@ -2916,7 +2928,7 @@
   printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
 #endif
 
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Check if we need some padding */
   if(clen < ETH_ZLEN)
@@ -2943,18 +2955,13 @@
   wv_82593_cmd(dev, "wv_packet_write(): transmit",
 	       OP0_TRANSMIT, SR0_NO_RESULT);
 
+  /* Make sure the watchdog will keep quiet for a while */
+  dev->trans_start = jiffies;
+
   /* Keep stats up to date */
   lp->stats.tx_bytes += length;
 
-  /* If watchdog not already active, activate it... */
-  if (!timer_pending(&lp->watchdog))
-    {
-      /* set timer to expire in WATCHDOG_JIFFIES */
-      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-      add_timer(&lp->watchdog);
-    }
-
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_TX_INFO
   wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
@@ -2963,56 +2970,57 @@
 #ifdef DEBUG_TX_TRACE
   printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
 #endif
-
-  netif_start_queue (dev);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
+ * In this routine, we check if the harware is ready to accept
  * the packet. We also prevent reentrance. Then, we call the function
  * to send the packet...
  */
-static int wavelan_packet_xmit (struct sk_buff *skb,
-				device * dev)
+static int
+wavelan_packet_xmit(struct sk_buff *	skb,
+		    device *		dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *)dev->priv;
+  unsigned long		flags;
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-		(unsigned) skb);
+  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	 (unsigned) skb);
 #endif
 
-	/*
-	 * For ethernet, fill in the header.
-	 */
+  /*
+   * Block a timer-based transmit from overlapping a previous transmit.
+   * In other words, prevent reentering this routine.
+   */
+  netif_stop_queue(dev);
 
-	netif_stop_queue (dev);
+  /* If somebody has asked to reconfigure the controller,
+   * we can do it now */
+  if(lp->reconfig_82593)
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+      /* Note : the configure procedure was totally synchronous,
+       * so the Tx buffer is now free */
+    }
 
-	/*
-	 * Block a timer-based transmit from overlapping a previous transmit.
-	 * In other words, prevent reentering this routine.
-	 */
-	if (1) {
-		/* If somebody has asked to reconfigure the controller, we can do it now */
-		if (lp->reconfig_82593) {
-			lp->reconfig_82593 = FALSE;
-			wv_82593_config (dev);
-		}
 #ifdef DEBUG_TX_ERROR
-		if (skb->next)
-			printk (KERN_INFO "skb has next\n");
+	if (skb->next)
+		printk(KERN_INFO "skb has next\n");
 #endif
 
-		wv_packet_write (dev, skb->data, skb->len);
-	}
-	dev_kfree_skb (skb);
+  wv_packet_write(dev, skb->data, skb->len);
+
+  dev_kfree_skb(skb);
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-	return (0);
+  return(0);
 }
 
 /********************** HARDWARE CONFIGURATION **********************/
@@ -3165,7 +3173,7 @@
    */
 
   /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody XXX - especially old cards...) */
+   * (does it work for everybody ? - especially old cards...) */
   /* Note : WFREQSEL verify that it is able to read from EEprom
    * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
    * is 0xA (Xilinx version) or 0xB (Ariadne version).
@@ -3223,7 +3231,7 @@
 wv_ru_stop(device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *lp = (net_local *) dev->priv;
+  net_local *	lp = (net_local *) dev->priv;
   unsigned long	flags;
   int		status;
   int		spin;
@@ -3232,35 +3240,35 @@
   printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
 #endif
 
+  wv_splhi(lp, &flags);
+
   /* First, send the LAN controller a stop receive command */
   wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
 	       OP0_STOP_RCV, SR0_NO_RESULT);
 
   /* Then, spin until the receive unit goes idle */
-  spin = 0;
+  spin = 300;
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
+  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0));
 
   /* Now, spin until the chip finishes executing its current command */
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+  wv_splx(lp, &flags);
 
   /* If there was a problem */
-  if(spin > 300)
+  if(spin <= 0)
     {
 #ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
@@ -3287,6 +3295,7 @@
 {
   ioaddr_t	base = dev->base_addr;
   net_local *	lp = (net_local *) dev->priv;
+  unsigned long	flags;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
@@ -3300,6 +3309,8 @@
   if(!wv_ru_stop(dev))
     return FALSE;
 
+  wv_splhi(lp, &flags);
+
   /* Now we know that no command is being executed. */
 
   /* Set the receive frame pointer and stop pointer */
@@ -3309,8 +3320,17 @@
   /* Reset ring management.  This sets the receive frame pointer to 1 */
   outb(OP1_RESET_RING_MNGMT, LCCR(base));
 
+#if 0
+  /* XXX the i82593 manual page 6-4 seems to indicate that the stop register
+     should be set as below */
+  /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/
+#elif 0
+  /* but I set it 0 instead */
+  lp->stop = 0;
+#else
   /* but I set it to 3 bytes per packet less than 8K */
   lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+#endif
   outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
   outb(OP1_INT_ENABLE, LCCR(base));
   outb(OP1_SWIT_TO_PORT_0, LCCR(base));
@@ -3326,17 +3346,15 @@
 #ifdef DEBUG_I82593_SHOW
   {
     int	status;
-    unsigned long flags;
-    int	i = 0;
+    int	opri;
+    int	spin = 10000;
 
     /* spin until the chip starts receiving */
     do
       {
-	spin_lock_irqsave (&lp->lock, flags);
 	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
 	status = inb(LCSR(base));
-	spin_unlock_irqrestore (&lp->lock, flags);
-	if(i++ > 10000)
+	if(spin-- <= 0)
 	  break;
       }
     while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
@@ -3345,6 +3363,9 @@
 	   (status & SR3_RCV_STATE_MASK), i);
   }
 #endif
+
+  wv_splx(lp, &flags);
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
 #endif
@@ -3363,6 +3384,7 @@
   ioaddr_t			base = dev->base_addr;
   net_local *			lp = (net_local *) dev->priv;
   struct i82593_conf_block	cfblk;
+  int				ret = TRUE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
@@ -3457,7 +3479,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
 		   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
-    return(FALSE);
+    ret = FALSE;
 
   /* Initialize adapter's ethernet MAC address */
   outb(TX_BASE & 0xff, PIORL(base));
@@ -3471,7 +3493,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
 		   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
-    return(FALSE);
+    ret = FALSE;
 
 #ifdef WAVELAN_ROAMING
     /* If roaming is enabled, join the "Beacon Request" multicast group... */
@@ -3508,14 +3530,17 @@
       hacr_write(base, HACR_DEFAULT);
       if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
 		       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
-	return(FALSE);
+	ret = FALSE;
       lp->mc_count = dev->mc_count;	/* remember to avoid repeated reset */
     }
 
+  /* Job done, clear the flag */
+  lp->reconfig_82593 = FALSE;
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
 #endif
-  return(TRUE);
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3594,6 +3619,8 @@
 {
   net_local *		lp = (net_local *) dev->priv;
   ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			ret = FALSE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
@@ -3612,50 +3639,78 @@
   if(wv_pcmcia_reset(dev) == FALSE)
     return FALSE;
 
-  /* Power UP the module + reset the modem + reset host adapter
-   * (in fact, reset DMA channels) */
-  hacr_write_slow(base, HACR_RESET);
-  hacr_write(base, HACR_DEFAULT);
+  /* Disable interrupts */
+  wv_splhi(lp, &flags);
 
-  /* Check if the module has been powered up... */
-  if(hasr_read(base) & HASR_NO_CLK)
+  /* Disguised goto ;-) */
+  do
     {
+      /* Power UP the module + reset the modem + reset host adapter
+       * (in fact, reset DMA channels) */
+      hacr_write_slow(base, HACR_RESET);
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
-	     dev->name);
+	  printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* initialize the modem */
-  if(wv_mmc_init(dev) == FALSE)
-    return FALSE;
+      /* initialize the modem */
+      if(wv_mmc_init(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* reset the LAN controller (i82593) */
-  outb(OP0_RESET, LCCR(base));
-  mdelay(1);	/* A bit crude ! */
-
-  /* Initialize the LAN controller */
-  if((wv_82593_config(dev) == FALSE) ||
-     (wv_diag(dev) == FALSE))
-    {
+      /* reset the LAN controller (i82593) */
+      outb(OP0_RESET, LCCR(base));
+      mdelay(1);	/* A bit crude ! */
+
+      /* Initialize the LAN controller */
+      if(wv_82593_config(dev) == FALSE)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* 
-   * insert code for loopback test here
-   */
+      /* Diagnostic */
+      if(wv_diag(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* The device is now configured */
-  lp->configured = 1;
+      /* 
+       * insert code for loopback test here
+       */
+
+      /* The device is now configured */
+      lp->configured = 1;
+      ret = TRUE;
+    }
+  while(0);
+
+  /* Re-enable interrupts */
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
 #endif
-  return TRUE;
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3675,10 +3730,6 @@
   printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
 #endif
 
-  /* If watchdog was activated, kill it ! */
-  if (timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   lp->nresets++;
   lp->configured = 0;
   
@@ -3786,13 +3837,13 @@
 	}
 
       /*
-       * Allocate a 4K memory window.  Note that the dev_link_t
+       * Allocate a small memory window.  Note that the dev_link_t
        * structure provides space for one window handle -- if your
        * device needs several windows, you'll need to keep track of
        * the handles in your private data structure, link->priv.
        */
       req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-      req.Base = 0; req.Size = 0x1000;
+      req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
       link->win = (window_handle_t)link->handle;
       i = CardServices(RequestWindow, &link->win, &req);
@@ -3803,7 +3854,7 @@
 	}
 
       dev->rmem_start = dev->mem_start =
-	  (u_long)ioremap(req.Base, 0x1000);
+	  (u_long)ioremap(req.Base, req.Size);
       dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
 
       mem.CardOffset = 0; mem.Page = 0;
@@ -3817,7 +3868,7 @@
       /* Feed device with this info... */
       dev->irq = link->irq.AssignedIRQ;
       dev->base_addr = link->io.BasePort1;
-      netif_start_queue (dev);
+      netif_start_queue(dev);
 
 #ifdef DEBUG_CONFIG_INFO
       printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
@@ -3843,7 +3894,7 @@
       return FALSE;
     }
 
-  /* XXX Could you explain me this, Dave ? */
+  strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
   link->dev = &((net_local *) dev->priv)->node;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3887,7 +3938,7 @@
   CardServices(ReleaseIO, link->handle, &link->io);
   CardServices(ReleaseIRQ, link->handle, &link->irq);
 
-  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
+  link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
@@ -3896,7 +3947,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Sometimes, netwave_detach can't be performed following a call from
+ * Sometimes, wavelan_detach can't be performed following a call from
  * cardmgr (device still open, pcmcia_release not done) and the device
  * is put in a STALE_LINK state and remains in memory.
  *
@@ -3970,7 +4021,19 @@
   lp = (net_local *) dev->priv;
   base = dev->base_addr;
 
-  spin_lock (&lp->lock);
+#ifdef DEBUG_INTERRUPT_INFO
+  /* Check state of our spinlock (it should be cleared) */
+  if(spin_is_locked(&lp->spinlock))
+    printk(KERN_DEBUG
+	   "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+	   dev->name);
+#endif
+
+  /* Prevent reentrancy. We need to do that because we may have
+   * multiple interrupt handler running concurently.
+   * It is safe because wv_splhi() disable interrupts before aquiring
+   * the spinlock. */
+  spin_lock(&lp->spinlock);
 
   /* Treat all pending interrupts */
   while(1)
@@ -4015,8 +4078,6 @@
 	  break;
 	}
 
-      lp->status = status0;	/* Save current status (for commands) */
-
       /* ----------------- RECEIVING PACKET ----------------- */
       /*
        * When the wavelan signal the reception of a new packet,
@@ -4054,22 +4115,6 @@
        * Most likely : transmission done
        */
 
-      /* If we are already waiting elsewhere for the command to complete */
-      if(wv_wait_completed)
-	{
-#ifdef DEBUG_INTERRUPT_INFO
-	  printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n",
-		 dev->name);
-#endif
-
-	  /* Signal command completion */
-	  wv_wait_completed = 0;
-
-	  /* Acknowledge the interrupt */
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
-	  continue;
-    	}
-
       /* If a transmission has been done */
       if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
 	 (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
@@ -4081,10 +4126,6 @@
 		   dev->name);
 #endif
 
-	  /* If watchdog was activated, kill it ! */
-	  if(timer_pending(&lp->watchdog))
-	    del_timer(&lp->watchdog);
-
 	  /* Get transmission status */
 	  tx_status = inb(LCSR(base));
 	  tx_status |= (inb(LCSR(base)) << 8);
@@ -4174,7 +4215,7 @@
 	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
 	  lp->stats.tx_packets++;
 
-	  netif_wake_queue (dev);
+	  netif_wake_queue(dev);
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	} 
       else	/* if interrupt = transmit done or retransmit done */
@@ -4185,9 +4226,9 @@
 #endif
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	}
-    }
+    }	/* while(1) */
 
-  spin_unlock_irq (&lp->lock);
+  spin_unlock(&lp->spinlock);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
@@ -4196,30 +4237,23 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel.  If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
  *
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the ISA driver. I make it this way because the overhead
- * of add_timer() and del_timer() is nothing and that it avoid calling
- * the watchdog, saving some CPU... If you want to apply the same
- * watchdog to the ISA driver, you should be a bit carefull, because
- * of the many transmit buffers...
- * This watchdog is also move clever, it try to abort the current
- * command before reseting everything...
+ * Note : This watchdog is move clever than the one in the ISA driver,
+ * because it try to abort the current command before reseting
+ * everything...
+ * On the other hand, it's a bit simpler, because we don't have to
+ * deal with the multiple Tx buffers...
  */
 static void
-wavelan_watchdog(u_long		a)
+wavelan_watchdog(device *	dev)
 {
-  device *		dev;
-  net_local *		lp;
-  ioaddr_t		base;
-  int			spin;
-
-  dev = (device *) a;
-  base = dev->base_addr;
-  lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			aborted = FALSE;
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
@@ -4230,21 +4264,21 @@
 	 dev->name);
 #endif
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  wv_splhi(lp, &flags);
 
   /* Ask to abort the current command */
   outb(OP0_ABORT, LCCR(base));
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 250))
-    udelay(10);
-
-  /* If the interrupt handler hasn't be called or invalid status */
-  if((wv_wait_completed) ||
-     ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED))
+  /* Wait for the end of the command (a bit hackish) */
+  if(wv_82593_cmd(dev, "wavelan_watchdog(): abort",
+		  OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED))
+    aborted = TRUE;
+
+  /* Release spinlock here so that wv_hw_reset() can grab it */
+  wv_splx(lp, &flags);
+
+  /* Check if we were successful in aborting it */
+  if(!aborted)
     {
       /* It seem that it wasn't enough */
 #ifdef DEBUG_INTERRUPT_ERROR
@@ -4269,7 +4303,7 @@
 #endif
 
   /* We are no more waiting for something... */
-  netif_start_queue (dev);
+  netif_wake_queue(dev);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -4322,7 +4356,7 @@
     return FALSE;
   if(!wv_ru_start(dev))
     wv_hw_reset(dev);		/* If problem : reset */
-  netif_start_queue (dev);
+  netif_start_queue(dev);
 
   /* Mark the device as used */
   link->open++;
@@ -4348,7 +4382,6 @@
 wavelan_close(device *	dev)
 {
   dev_link_t *	link = ((net_local *) dev->priv)->link;
-  net_local *	lp = (net_local *)dev->priv;
   ioaddr_t	base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4356,8 +4389,6 @@
 	 (unsigned int) dev);
 #endif
 
-  netif_stop_queue (dev);
-
   /* If the device isn't open, then nothing to do */
   if(!link->open)
     {
@@ -4373,17 +4404,13 @@
     wv_roam_cleanup(dev);
 #endif	/* WAVELAN_ROAMING */
 
-  /* If watchdog was activated, kill it ! */
-  if(timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   link->open--;
   MOD_DEC_USE_COUNT;
 
   /* If the card is still present */
-  if (netif_device_present(dev))
+  if(netif_running(dev))
     {
-      netif_stop_queue (dev);
+      netif_stop_queue(dev);
 
       /* Stop receiving new messages and wait end of transmission */
       wv_ru_stop(dev);
@@ -4404,21 +4431,6 @@
 
 /*------------------------------------------------------------------*/
 /*
- * We never need to do anything when a wavelan device is "initialized"
- * by the net software, because we only register already-found cards.
- */
-static int
-wavelan_init(device *	dev)
-{
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<>wavelan_init()\n");
-#endif
-
-  return(0);
-}
-
-/*------------------------------------------------------------------*/
-/*
  * wavelan_attach() creates an "instance" of the driver, allocating
  * local data structures for one device (one interface).  The device
  * is registered with Card Services.
@@ -4445,24 +4457,8 @@
 
   /* Initialize the dev_link_t structure */
   link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-  if (!link)
-	  return NULL;
-  
-  /* Allocate the generic data structure */
-  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-  if (!dev)
-	  goto fail_alloc_dev;
-  
-  /* Allocate the wavelan-specific data structure. */
-  lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
-  if (!lp)
-	  goto fail_alloc_dev_priv;
-  
-  memset(lp, 0, sizeof(net_local));
+  if (!link) return NULL;
   memset(link, 0, sizeof(struct dev_link_t));
-  memset(dev, 0, sizeof(struct net_device));
-
-  dev->priv = lp;
 
   /* Unused for the Wavelan */
   link->release.function = &wv_pcmcia_release;
@@ -4492,18 +4488,35 @@
   link->next = dev_list;
   dev_list = link;
 
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  if (!dev) {
+      kfree(link);
+      return NULL;
+  }
+  memset(dev, 0x00, sizeof(struct net_device));
   link->priv = link->irq.Instance = dev;
 
+  /* Allocate the wavelan-specific data structure. */
+  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  if (!lp) {
+      kfree(link);
+      kfree(dev);
+      return NULL;
+  }
+  memset(lp, 0x00, sizeof(net_local));
+
   /* Init specific data */
-  wv_wait_completed = 0;
-  lp->status = FALSE;
   lp->configured = 0;
   lp->reconfig_82593 = FALSE;
   lp->nresets = 0;
+  /* Multicast stuff */
+  lp->promiscuous = 0;
+  lp->allmulticast = 0;
+  lp->mc_count = 0;
 
-  /* Set the watchdog timer */
-  lp->watchdog.function = wavelan_watchdog;
-  lp->watchdog.data = (unsigned long) dev;
+  /* Init spinlock */
+  spin_lock_init(&lp->spinlock);
 
   /* back links */
   lp->link = link;
@@ -4513,7 +4526,6 @@
   ether_setup(dev);
 
   /* wavelan NET3 callbacks */
-  dev->init = &wavelan_init;
   dev->open = &wavelan_open;
   dev->stop = &wavelan_close;
   dev->hard_start_xmit = &wavelan_packet_xmit;
@@ -4523,14 +4535,16 @@
   dev->set_mac_address = &wavelan_set_mac_address;
 #endif	/* SET_MAC_ADDRESS */
 
+  /* Set the watchdog timer */
+  dev->tx_timeout	= &wavelan_watchdog;
+  dev->watchdog_timeo	= WATCHDOG_JIFFIES;
+
 #ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
   dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
 
   /* Other specific data */
-  strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name);
-  netif_start_queue (dev);
   dev->mtu = WAVELAN_MTU;
 
   /* Register with Card Services */
@@ -4562,12 +4576,6 @@
 #endif
 
   return link;
-
-fail_alloc_dev_priv:
-  kfree(dev);
-fail_alloc_dev:
-  kfree(link);
-  return NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -4698,7 +4706,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
 	    /* Accept no more transmissions */
-      	    netif_device_detach(dev);
+	    netif_device_detach(dev);
 
 	    /* Release the card */
 	    wv_pcmcia_release((u_long) link);
@@ -4720,7 +4728,7 @@
 	 * obliged to close nicely the wavelan here. David, could you
 	 * close the device before suspending them ? And, by the way,
 	 * could you, on resume, add a "route add -net ..." after the
-	 * ifconfig up XXX Thanks... */
+	 * ifconfig up ? Thanks... */
 
 	/* Stop receiving new messages and wait end of transmission */
 	wv_ru_stop(dev);
@@ -4735,8 +4743,7 @@
     	if(link->state & DEV_CONFIG)
 	  {
       	    if(link->open)
-	      	netif_device_detach(dev);
-
+	      netif_device_detach(dev);
       	    CardServices(ReleaseConfiguration, link->handle);
 	  }
 	break;
@@ -4748,7 +4755,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
       	    CardServices(RequestConfiguration, link->handle, &link->conf);
-      	    if(link->open)	/* If RESET -> True, If RESUME -> False XXX */
+      	    if(link->open)	/* If RESET -> True, If RESUME -> False ? */
 	      {
 		wv_hw_reset(dev);
 		netif_device_attach(dev);
@@ -4838,4 +4845,5 @@
 
 module_init(init_wavelan_cs);
 module_exit(exit_wavelan_cs);
-MODULE_LICENSE("Dual BSD/GPL");
+
+/* Note : Modules parameters are in wavelan_cs.h - Jean II */
diff -urN linux-2.4.20-pre1/drivers/net/pcmcia/wavelan_cs.h linux-2.4.20-pre2/drivers/net/pcmcia/wavelan_cs.h
--- linux-2.4.20-pre1/drivers/net/pcmcia/wavelan_cs.h	Fri Oct 12 14:21:18 2001
+++ linux-2.4.20-pre2/drivers/net/pcmcia/wavelan_cs.h	Mon Aug 12 16:34:16 2002
@@ -34,6 +34,25 @@
  *	I try to maintain a web page with the Wireless LAN Howto at :
  *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
  *
+ * SMP
+ * ---
+ *	We now are SMP compliant (I eventually fixed the remaining bugs).
+ *	The driver has been tested on a dual P6-150 and survived my usual
+ *	set of torture tests.
+ *	Anyway, I spent enough time chasing interrupt re-entrancy during
+ *	errors or reconfigure, and I designed the locked/unlocked sections
+ *	of the driver with great care, and with the recent addition of
+ *	the spinlock (thanks to the new API), we should be quite close to
+ *	the truth.
+ *	The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ *	but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ *	I have also looked into disabling only our interrupt on the card
+ *	(via HACR) instead of all interrupts in the processor (via cli),
+ *	so that other driver are not impacted, and it look like it's
+ *	possible, but it's very tricky to do right (full of races). As
+ *	the gain would be mostly for SMP systems, it can wait...
+ *
  * Debugging and options
  * ---------------------
  *	You will find below a set of '#define" allowing a very fine control
@@ -122,7 +141,7 @@
  * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
  * correctly 2.00 cards (2.4 GHz with frequency selection).
- * David Hinds <dhinds@pcmcia.sourceforge.org> integrated the whole in his
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
  * Pcmcia package (+ bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
@@ -158,8 +177,8 @@
  *
  *    This software was originally developed under Linux 1.2.3
  *	(Slackware 2.0 distribution).
- *    And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with
- *	HP OmniBook 4000 & 5500.
+ *    And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+)
+ *	with an HP OmniBook 4000 and then a 5500.
  *
  *    It is based on other device drivers and information either written
  *    or supplied by:
@@ -174,7 +193,7 @@
  *	Matthew Geier (matthew@cs.su.oz.au),
  *	Remo di Giovanni (remo@cs.su.oz.au),
  *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- *	David Hinds <dhinds@pcmcia.sourceforge.org>,
+ *	David Hinds <dahinds@users.sourceforge.net>,
  *	Jan Hoogendoorn (c/o marteijn@lucent.com),
  *      Bruce Janson <bruce@cs.usyd.edu.au>,
  *	Anthony D. Joseph <adj@lcs.mit.edu>,
@@ -349,6 +368,37 @@
  *	- Fix check for root permission (break instead of exit)
  *	- New nwid & encoding setting (Wireless Extension 9)
  *
+ * Changes made for release in 3.1.12 :
+ * ----------------------------------
+ *	- reworked wv_82593_cmd to avoid using the IRQ handler and doing
+ *	  ugly things with interrupts.
+ *	- Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog
+ *	- Update to new network API (softnet - 2.3.43) :
+ *		o replace dev->tbusy (David + me)
+ *		o replace dev->tstart (David + me)
+ *		o remove dev->interrupt (David)
+ *		o add SMP locking via spinlock in splxx (me)
+ *		o add spinlock in interrupt handler (me)
+ *		o use kernel watchdog instead of ours (me)
+ *		o verify that all the changes make sense and work (me)
+ *	- Re-sync kernel/pcmcia versions (not much actually)
+ *	- A few other cleanups (David & me)...
+ *
+ * Changes made for release in 3.1.22 :
+ * ----------------------------------
+ *	- Check that SMP works, remove annoying log message
+ *
+ * Changes made for release in 3.1.24 :
+ * ----------------------------------
+ *	- Fix unfrequent card lockup when watchdog was reseting the hardware :
+ *		o control first busy loop in wv_82593_cmd()
+ *		o Extend spinlock protection in wv_hw_config()
+ *
+ * Changes made for release in 3.2.1 :
+ * ---------------------------------
+ *	- Set dev->trans_start to avoid filling the logs
+ *		(and generating useless abort commands)
+ *
  * Wishes & dreams:
  * ----------------
  *	- Cleanup and integrate the roaming code
@@ -368,6 +418,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
 #include <linux/in.h>
 #include <linux/delay.h>
 #include <asm/uaccess.h>
@@ -384,7 +435,7 @@
 
 #ifdef CONFIG_NET_PCMCIA_RADIO
 #include <linux/wireless.h>		/* Wireless extensions */
-#endif	/* CONFIG_NET_PCMCIA_RADIO */
+#endif
 
 /* Pcmcia headers that we need */
 #include <pcmcia/cs_types.h>
@@ -437,7 +488,7 @@
 #undef DEBUG_RX_INFO		/* Header of the transmitted packet */
 #undef DEBUG_RX_FAIL		/* Normal failure conditions */
 #define DEBUG_RX_ERROR		/* Unexpected conditions */
-#undef DEBUG_PACKET_DUMP	/* Dump packet on the screen */
+#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen */
 #undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
 #undef DEBUG_IOCTL_INFO		/* Various debug info */
 #define DEBUG_IOCTL_ERROR	/* What's going wrong */
@@ -452,7 +503,7 @@
 /************************ CONSTANTS & MACROS ************************/
 
 #ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n";
+static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n";
 #endif
 
 /* Watchdog temporisation */
@@ -557,9 +608,9 @@
  */
 struct net_local
 {
-  spinlock_t	lock;
   dev_node_t 	node;		/* ???? What is this stuff ???? */
   device *	dev;		/* Reverse link... */
+  spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
   dev_link_t *	link;		/* pcmcia structure */
   en_stats	stats;		/* Ethernet interface statistics */
   int		nresets;	/* Number of hw resets */
@@ -568,9 +619,7 @@
   u_char	promiscuous;	/* Promiscuous mode */
   u_char	allmulticast;	/* All Multicast mode */
   int		mc_count;	/* Number of multicast addresses */
-  timer_list	watchdog;	/* To avoid blocking state */
 
-  u_char        status;		/* Current i82593 status */
   int   	stop;		/* Current i82593 Stop Hit Register */
   int   	rfp;		/* Last DMA machine receive pointer */
   int		overrunning;	/* Receiver overrun flag */
@@ -617,8 +666,14 @@
 #endif	/* WAVELAN_ROAMING */
 
 /* ----------------------- MISC SUBROUTINES ------------------------ */
+static inline void
+	wv_splhi(net_local *,		/* Disable interrupts */
+		 unsigned long *);	/* flags */
+static inline void
+	wv_splx(net_local *,		/* ReEnable interrupts */
+		unsigned long *);	/* flags */
 static void
-	cs_error(client_handle_t, /* Report error to cardmgr */
+	cs_error(client_handle_t,	/* Report error to cardmgr */
 		 int,
 		 int);
 /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
@@ -722,16 +777,15 @@
 	wv_flush_stale_links(void);	/* "detach" all possible devices */
 /* ---------------------- INTERRUPT HANDLING ---------------------- */
 static void
-wavelan_interrupt(int,	/* Interrupt handler */
-		  void *,
-		  struct pt_regs *);
+	wavelan_interrupt(int,	/* Interrupt handler */
+			  void *,
+			  struct pt_regs *);
 static void
-	wavelan_watchdog(u_long);	/* Transmission watchdog */
+	wavelan_watchdog(device *);	/* Transmission watchdog */
 /* ------------------- CONFIGURATION CALLBACKS ------------------- */
 static int
 	wavelan_open(device *),		/* Open the device */
-	wavelan_close(device *),	/* Close the device */
-	wavelan_init(device *);		/* Do nothing */
+	wavelan_close(device *);	/* Close the device */
 static dev_link_t *
 	wavelan_attach(void);		/* Create a new device */
 static void
@@ -744,11 +798,7 @@
 /**************************** VARIABLES ****************************/
 
 static dev_info_t dev_info = "wavelan_cs";
-static dev_link_t *dev_list;		/* Linked list of devices */
-
-/* WARNING : the following variable MUST be volatile
- * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ 
-static volatile int	wv_wait_completed;
+static dev_link_t *dev_list = NULL;	/* Linked list of devices */
 
 /*
  * Parameters that can be set with 'insmod'
@@ -761,7 +811,7 @@
 static int 	irq_list[4] = { -1 };
 
 /* Shared memory speed, in ns */
-static int	mem_speed;
+static int	mem_speed = 0;
 
 /* New module interface */
 MODULE_PARM(irq_mask, "i");
@@ -770,9 +820,12 @@
 
 #ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
 /* Enable roaming mode ? No ! Please keep this to 0 */
-static int	do_roaming;
+static int	do_roaming = 0;
 MODULE_PARM(do_roaming, "i");
 #endif	/* WAVELAN_ROAMING */
 
+/* My modifications and rewrite were GPL only - Jean II */
+MODULE_LICENSE("GPL");
+
 #endif	/* WAVELAN_CS_H */
 
diff -urN linux-2.4.20-pre1/drivers/net/pcmcia/xirc2ps_cs.c linux-2.4.20-pre2/drivers/net/pcmcia/xirc2ps_cs.c
--- linux-2.4.20-pre1/drivers/net/pcmcia/xirc2ps_cs.c	Tue Nov 13 09:02:30 2001
+++ linux-2.4.20-pre2/drivers/net/pcmcia/xirc2ps_cs.c	Mon Aug 12 16:34:16 2002
@@ -2096,7 +2096,7 @@
 	MAYBE_SET(irq_list[1], 7);
 	MAYBE_SET(irq_list[2], 8);
 	MAYBE_SET(irq_list[3], 9);
-#undef  MAYBE_SET(X,Y)
+#undef  MAYBE_SET
 
 	return 0;
 }
diff -urN linux-2.4.20-pre1/drivers/net/pcmcia/xircom_tulip_cb.c linux-2.4.20-pre2/drivers/net/pcmcia/xircom_tulip_cb.c
--- linux-2.4.20-pre1/drivers/net/pcmcia/xircom_tulip_cb.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/pcmcia/xircom_tulip_cb.c	Mon Aug 12 16:34:16 2002
@@ -355,7 +355,7 @@
 	const int strict_bits =
 		TxThresh10 | TxStoreForw | TxThreshMask | EnableTxRx | FullDuplexBit;
     int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
-    long flags;
+    unsigned long flags;
     save_flags(flags);
     cli();
 	/* mask out the reserved bits that always read 0 on the Xircom cards */
@@ -1464,7 +1464,7 @@
 	struct xircom_private *tp = dev->priv;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = tp->phys[0] & 0x1f;
-	long flags;
+	unsigned long flags;
 
 	switch(cmd) {
 	case SIOCETHTOOL:
diff -urN linux-2.4.20-pre1/drivers/net/ppp_deflate.c linux-2.4.20-pre2/drivers/net/ppp_deflate.c
--- linux-2.4.20-pre1/drivers/net/ppp_deflate.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/ppp_deflate.c	Mon Aug 12 16:34:16 2002
@@ -39,7 +39,7 @@
 #include <linux/ppp_defs.h>
 #include <linux/ppp-comp.h>
 
-#include "zlib.c"
+#include <linux/zlib.h>
 
 /*
  * State for a Deflate (de)compressor.
@@ -56,10 +56,6 @@
 
 #define DEFLATE_OVHD	2		/* Deflate overhead/packet */
 
-static void	*zalloc __P((void *, unsigned int items, unsigned int size));
-static void	*zalloc_init __P((void *, unsigned int items,
-				  unsigned int size));
-static void	zfree __P((void *, void *ptr));
 static void	*z_comp_alloc __P((unsigned char *options, int opt_len));
 static void	*z_decomp_alloc __P((unsigned char *options, int opt_len));
 static void	z_comp_free __P((void *state));
@@ -80,72 +76,6 @@
 static void	z_decomp_reset __P((void *state));
 static void	z_comp_stats __P((void *state, struct compstat *stats));
 
-struct chunk_header {
-	int valloced;		/* allocated with valloc, not kmalloc */
-	int guard;		/* check for overwritten header */
-};
-
-#define GUARD_MAGIC	0x77a8011a
-#define MIN_VMALLOC	2048	/* use kmalloc for blocks < this */
-
-/*
- * Space allocation and freeing routines for use by zlib routines.
- */
-void
-zfree(arg, ptr)
-    void *arg;
-    void *ptr;
-{
-	struct chunk_header *hdr = ((struct chunk_header *)ptr) - 1;
-
-	if (hdr->guard != GUARD_MAGIC) {
-		printk(KERN_WARNING "zfree: header corrupted (%x %x) at %p\n",
-		       hdr->valloced, hdr->guard, hdr);
-		return;
-	}
-	if (hdr->valloced)
-		vfree(hdr);
-	else
-		kfree(hdr);
-}
-
-void *
-zalloc(arg, items, size)
-    void *arg;
-    unsigned int items, size;
-{
-	struct chunk_header *hdr;
-	unsigned nbytes;
-
-	nbytes = items * size + sizeof(*hdr);
-	hdr = kmalloc(nbytes, GFP_ATOMIC);
-	if (hdr == 0)
-		return 0;
-	hdr->valloced = 0;
-	hdr->guard = GUARD_MAGIC;
-	return (void *) (hdr + 1);
-}
-
-void *
-zalloc_init(arg, items, size)
-    void *arg;
-    unsigned int items, size;
-{
-	struct chunk_header *hdr;
-	unsigned nbytes;
-
-	nbytes = items * size + sizeof(*hdr);
-	if (nbytes >= MIN_VMALLOC)
-		hdr = vmalloc(nbytes);
-	else
-		hdr = kmalloc(nbytes, GFP_KERNEL);
-	if (hdr == 0)
-		return 0;
-	hdr->valloced = nbytes >= MIN_VMALLOC;
-	hdr->guard = GUARD_MAGIC;
-	return (void *) (hdr + 1);
-}
-
 static void
 z_comp_free(arg)
     void *arg;
@@ -153,7 +83,9 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	if (state) {
-		deflateEnd(&state->strm);
+		zlib_deflateEnd(&state->strm);
+		if (state->strm.workspace)
+			vfree(state->strm.workspace);
 		kfree(state);
 		MOD_DEC_USE_COUNT;
 	}
@@ -180,27 +112,27 @@
 	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
 		return NULL;
 
-	state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL);
+	state = (struct ppp_deflate_state *) kmalloc(sizeof(*state),
+						     GFP_KERNEL);
 	if (state == NULL)
 		return NULL;
 
 	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
-	state->strm.next_in = NULL;
-	state->strm.zalloc  = zalloc_init;
-	state->strm.zfree   = zfree;
-	state->w_size       = w_size;
+	state->strm.next_in   = NULL;
+	state->w_size         = w_size;
+	state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
+	if (state->strm.workspace == NULL)
+		goto out_free;
 
-	if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
+	if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
 			 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)
 	    != Z_OK)
 		goto out_free;
-	state->strm.zalloc = zalloc;
 	return (void *) state;
 
 out_free:
 	z_comp_free(state);
-	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -224,7 +156,7 @@
 	state->unit  = unit;
 	state->debug = debug;
 
-	deflateReset(&state->strm);
+	zlib_deflateReset(&state->strm);
 
 	return 1;
 }
@@ -236,7 +168,7 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	state->seqno = 0;
-	deflateReset(&state->strm);
+	zlib_deflateReset(&state->strm);
 }
 
 int
@@ -286,7 +218,7 @@
 	state->strm.avail_in = (isize - off);
 
 	for (;;) {
-		r = deflate(&state->strm, Z_PACKET_FLUSH);
+		r = zlib_deflate(&state->strm, Z_PACKET_FLUSH);
 		if (r != Z_OK) {
 			if (state->debug)
 				printk(KERN_ERR
@@ -337,7 +269,9 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	if (state) {
-		inflateEnd(&state->strm);
+		zlib_inflateEnd(&state->strm);
+		if (state->strm.workspace)
+			kfree(state->strm.workspace);
 		kfree(state);
 		MOD_DEC_USE_COUNT;
 	}
@@ -370,19 +304,19 @@
 
 	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
-	state->w_size        = w_size;
-	state->strm.next_out = NULL;
-	state->strm.zalloc   = zalloc_init;
-	state->strm.zfree    = zfree;
+	state->w_size         = w_size;
+	state->strm.next_out  = NULL;
+	state->strm.workspace = kmalloc(zlib_inflate_workspacesize(),
+					GFP_KERNEL);
+	if (state->strm.workspace == NULL)
+		goto out_free;
 
-	if (inflateInit2(&state->strm, -w_size) != Z_OK)
+	if (zlib_inflateInit2(&state->strm, -w_size) != Z_OK)
 		goto out_free;
-	state->strm.zalloc = zalloc;
 	return (void *) state;
 
 out_free:
 	z_decomp_free(state);
-	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -407,7 +341,7 @@
 	state->debug = debug;
 	state->mru   = mru;
 
-	inflateReset(&state->strm);
+	zlib_inflateReset(&state->strm);
 
 	return 1;
 }
@@ -419,7 +353,7 @@
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
 
 	state->seqno = 0;
-	inflateReset(&state->strm);
+	zlib_inflateReset(&state->strm);
 }
 
 /*
@@ -492,7 +426,7 @@
 	 * Call inflate, supplying more input or output as needed.
 	 */
 	for (;;) {
-		r = inflate(&state->strm, Z_PACKET_FLUSH);
+		r = zlib_inflate(&state->strm, Z_PACKET_FLUSH);
 		if (r != Z_OK) {
 			if (state->debug)
 				printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n",
@@ -575,7 +509,7 @@
 		++state->strm.avail_in;
 	}
 
-	r = inflateIncomp(&state->strm);
+	r = zlib_inflateIncomp(&state->strm);
 	if (r != Z_OK) {
 		/* gak! */
 		if (state->debug) {
diff -urN linux-2.4.20-pre1/drivers/net/ppp_generic.c linux-2.4.20-pre2/drivers/net/ppp_generic.c
--- linux-2.4.20-pre1/drivers/net/ppp_generic.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/ppp_generic.c	Mon Aug 12 16:34:16 2002
@@ -378,7 +378,7 @@
 {
 	struct ppp_file *pf = file->private_data;
 	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
+	ssize_t ret = 0;
 	struct sk_buff *skb = 0;
 
 	if (pf == 0)
diff -urN linux-2.4.20-pre1/drivers/net/rcpci45.c linux-2.4.20-pre2/drivers/net/rcpci45.c
--- linux-2.4.20-pre1/drivers/net/rcpci45.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.20-pre2/drivers/net/rcpci45.c	Mon Aug 12 16:34:16 2002
@@ -102,8 +102,6 @@
 
 static void rc_timer (unsigned long);
 
-static int RCinit (struct net_device *);
-
 static int RCopen (struct net_device *);
 static int RC_xmit_packet (struct sk_buff *, struct net_device *);
 static void RCinterrupt (int, void *, struct pt_regs *);
@@ -188,7 +186,7 @@
 	error = -ENOMEM;
 	pci_start = pci_resource_start (pdev, 0);
 	pci_len = pci_resource_len (pdev, 0);
-	printk("pci_start %x pci_len %x\n", pci_start, pci_len);
+	printk("pci_start %lx pci_len %lx\n", pci_start, pci_len);
 
 	pci_set_drvdata (pdev, dev);
 
diff -urN linux-2.4.20-pre1/drivers/net/tokenring/3c359.c linux-2.4.20-pre2/drivers/net/tokenring/3c359.c
--- linux-2.4.20-pre1/drivers/net/tokenring/3c359.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/tokenring/3c359.c	Mon Aug 12 16:34:16 2002
@@ -51,7 +51,6 @@
 #include <linux/timer.h>
 #include <linux/in.h>
 #include <linux/ioport.h>
-#include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/proc_fs.h>
 #include <linux/ptrace.h>
diff -urN linux-2.4.20-pre1/drivers/net/tokenring/Config.in linux-2.4.20-pre2/drivers/net/tokenring/Config.in
--- linux-2.4.20-pre1/drivers/net/tokenring/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/tokenring/Config.in	Fri Aug  2 17:39:44 2002
@@ -5,11 +5,6 @@
 mainmenu_option next_comment
 comment 'Token Ring devices'
 
-#x86-64 disabled by now because the drivers look largely not 64bit clean
-if [ "$CONFIG_X86_64" = "y" ]; then
-   define_bool CONFIG_TR n
-else
-
 # So far, we only have PCI, ISA, and MCA token ring devices
 if [ "$CONFIG_PCI" = "y" -o "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
    bool 'Token Ring driver support' CONFIG_TR
@@ -17,8 +12,6 @@
    define_bool CONFIG_TR n
 fi
 
-fi
-
 if [ "$CONFIG_TR" != "n" ]; then
    if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
       tristate '  IBM Tropic chipset based adapter support' CONFIG_IBMTR
diff -urN linux-2.4.20-pre1/drivers/net/tokenring/olympic.c linux-2.4.20-pre2/drivers/net/tokenring/olympic.c
--- linux-2.4.20-pre1/drivers/net/tokenring/olympic.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/tokenring/olympic.c	Mon Aug 12 16:34:16 2002
@@ -128,7 +128,7 @@
 /* Module paramters */
 
 MODULE_AUTHOR("Mike Phillips <mikep@linuxtr.net>") ; 
-MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver \n") ; 
+MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver") ; 
 
 /* Ring Speed 0,4,16,100 
  * 0 = Autosense         
diff -urN linux-2.4.20-pre1/drivers/net/tulip/tulip.h linux-2.4.20-pre2/drivers/net/tulip/tulip.h
--- linux-2.4.20-pre1/drivers/net/tulip/tulip.h	Fri Nov  9 13:45:35 2001
+++ linux-2.4.20-pre2/drivers/net/tulip/tulip.h	Mon Aug 12 16:34:16 2002
@@ -84,6 +84,7 @@
 	COMPEX9881,
 	I21145,
 	DM910X,
+	CONEXANT,
 };
 
 
diff -urN linux-2.4.20-pre1/drivers/net/tulip/tulip_core.c linux-2.4.20-pre2/drivers/net/tulip/tulip_core.c
--- linux-2.4.20-pre1/drivers/net/tulip/tulip_core.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/tulip/tulip_core.c	Mon Aug 12 16:34:16 2002
@@ -15,8 +15,8 @@
 */
 
 #define DRV_NAME	"tulip"
-#define DRV_VERSION	"0.9.15-pre11"
-#define DRV_RELDATE	"May 11, 2002"
+#define DRV_VERSION	"0.9.15-pre12"
+#define DRV_RELDATE	"Aug 9, 2002"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -191,6 +191,10 @@
   { "Davicom DM9102/DM9102A", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,
 	tulip_timer },
+
+  /* CONEXANT */
+  {	"Conexant LANfinity", 256, 0x0001ebef,
+	HAS_MII, tulip_timer },
 };
 
 
@@ -221,6 +225,10 @@
 	{ 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
 	{ 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x1186, 0x1561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x1626, 0x8410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },
 	{ } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -453,7 +461,7 @@
 		tp->csr6 = 0x01a80200;
 		outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
 		outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
-	} else if (tp->chip_id == COMET) {
+	} else if (tp->chip_id == COMET || tp->chip_id == CONEXANT) {
 		/* Enable automatic Tx underrun recovery. */
 		outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88);
 		dev->if_port = tp->mii_cnt ? 11 : 0;
@@ -1548,7 +1556,13 @@
 		for (i = 0; i < 8; i ++)
 			if (ee_data[i] != ee_data[16+i])
 				sa_offset = 20;
-		if (ee_data[0] == 0xff  &&  ee_data[1] == 0xff &&  ee_data[2] == 0) {
+		if (chip_idx == CONEXANT) {
+		    /* Check that the tuple type and length is correct. */
+			if (ee_data[0x198] == 0x04  &&  ee_data[0x199] == 6)
+			    sa_offset = 0x19A;
+		}
+		if (ee_data[0] == 0xff && ee_data[1] == 0xff &&
+		    ee_data[2] == 0) {
 			sa_offset = 2;		/* Grrr, damn Matrox boards. */
 			multiport_cnt = 4;
 		}
diff -urN linux-2.4.20-pre1/drivers/net/wan/8253x/crc32.c linux-2.4.20-pre2/drivers/net/wan/8253x/crc32.c
--- linux-2.4.20-pre1/drivers/net/wan/8253x/crc32.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/wan/8253x/crc32.c	Mon Aug 12 16:34:16 2002
@@ -46,13 +46,13 @@
 
 #if defined(AMD29K)
 pragma Data (Export,"fastbss");
-#endif defined(AMD29K)
+#endif // defined(AMD29K)
 
 unsigned int gg_a_crc_table[k_crc_table_size];
 
 #if defined(AMD29K)
 pragma Data;
-#endif defined(AMD29K)
+#endif // defined(AMD29K)
 
 
 /****************************************************/
diff -urN linux-2.4.20-pre1/drivers/net/wan/Config.in linux-2.4.20-pre2/drivers/net/wan/Config.in
--- linux-2.4.20-pre1/drivers/net/wan/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/wan/Config.in	Mon Aug 12 16:34:16 2002
@@ -42,14 +42,12 @@
 # The Etinc driver has not been tested as non-modular yet.
 #
 
-   if [ "$CONFIG_X86_64" != "y" ]; then	
    dep_tristate '  Etinc PCISYNC serial board support (EXPERIMENTAL)' CONFIG_DSCC4 m
 
 # FarSite Communications' cards
 
    tristate '  FarSync T-Series X.21 (and V.35/V.24) cards' CONFIG_FARSYNC
 
-   fi
 #
 # Lan Media's board. Currently 1000, 1200, 5200, 5245
 #
@@ -60,9 +58,7 @@
 # ATI's sync/async boards. Currently 2520, 4020, 4520, 8520 -- 0 in second digit means async only
 #
 
-   if [ "$CONFIG_X86_64" != "y" ]; then	
    tristate '  Aurora Technology, Inc. synchronous asynchronous PCI cards V2' CONFIG_ATI_XX20
-   fi
 
 # There is no way to detect a Sealevel board. Force it modular
 
@@ -105,7 +101,7 @@
 	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	    dep_tristate '    Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS $CONFIG_ISA
 	    if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then
-	       bool '      Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25
+	       bool '      Cyclom 2X X.25 support (EXPERIMENTAL)' CONFIG_CYCLOMX_X25
 	    fi
 	 fi
       fi
diff -urN linux-2.4.20-pre1/drivers/net/wan/cycx_drv.c linux-2.4.20-pre2/drivers/net/wan/cycx_drv.c
--- linux-2.4.20-pre1/drivers/net/wan/cycx_drv.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.20-pre2/drivers/net/wan/cycx_drv.c	Mon Aug 12 16:34:16 2002
@@ -423,9 +423,9 @@
 
 	/* Verify firmware module format version */
 	if (cfm->version != CFM_VERSION) {
-		printk(KERN_ERR "%s:" __FUNCTION__ ": firmware format %u rejected! "
+		printk(KERN_ERR "%s:%s: firmware format %u rejected! "
 				"Expecting %u.\n",
-				modname, cfm->version, CFM_VERSION);
+				modname, __FUNCTION__, cfm->version, CFM_VERSION);
 		return -EINVAL;
 	}
 
@@ -437,8 +437,8 @@
 	if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) ||
 */
 	if (cksum != cfm->checksum) {
-		printk(KERN_ERR "%s:" __FUNCTION__ ": firmware corrupted!\n",
-				modname);
+		printk(KERN_ERR "%s:%s: firmware corrupted!\n",
+				modname, __FUNCTION__);
 		printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n",
 				len - sizeof(cfm_t) - 1, cfm->info.codesize);
                 printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n",
@@ -450,7 +450,7 @@
 
 	img_hdr = (cycx_header_t*)(((u8*)cfm) + sizeof(cfm_t) - 1);
 #ifdef FIRMWARE_DEBUG
-	printk(KERN_INFO "%s:" __FUNCTION__ ": image sizes\n", modname);
+	printk(KERN_INFO "%s:%s: image sizes\n", __FUNCTION__, modname);
 	printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size);
 	printk(KERN_INFO "  data=%lu\n", img_hdr->data_size);
 	printk(KERN_INFO "  code=%lu\n", img_hdr->code_size);
diff -urN linux-2.4.20-pre1/drivers/net/wan/sbni.c linux-2.4.20-pre2/drivers/net/wan/sbni.c
--- linux-2.4.20-pre1/drivers/net/wan/sbni.c	Fri Sep 14 14:40:00 2001
+++ linux-2.4.20-pre2/drivers/net/wan/sbni.c	Mon Aug 12 16:34:16 2002
@@ -64,11 +64,6 @@
 #include <net/arp.h>
 #include <linux/pci.h>
 
-
-#ifndef MODULE
-#include <linux/string.h>
-#endif
-
 #include <linux/config.h>
 #include "sbni.h"
 
diff -urN linux-2.4.20-pre1/drivers/net/wan/sdla_ft1.c linux-2.4.20-pre2/drivers/net/wan/sdla_ft1.c
--- linux-2.4.20-pre1/drivers/net/wan/sdla_ft1.c	Thu Sep 13 16:04:43 2001
+++ linux-2.4.20-pre2/drivers/net/wan/sdla_ft1.c	Mon Aug 12 16:34:16 2002
@@ -23,7 +23,6 @@
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/module.h>
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
diff -urN linux-2.4.20-pre1/drivers/net/wan/syncppp.c linux-2.4.20-pre2/drivers/net/wan/syncppp.c
--- linux-2.4.20-pre1/drivers/net/wan/syncppp.c	Thu Sep 13 16:04:43 2001
+++ linux-2.4.20-pre2/drivers/net/wan/syncppp.c	Mon Aug 12 16:34:16 2002
@@ -796,7 +796,7 @@
 		printk (">\n");
 	}
 	sp->obytes += skb->len;
-	/* Control is high priority so it doesnt get queued behind data */
+	/* Control is high priority so it doesn't get queued behind data */
 	skb->priority=TC_PRIO_CONTROL;
 	skb->dev = dev;
 	dev_queue_xmit(skb);
diff -urN linux-2.4.20-pre1/drivers/net/wavelan.c linux-2.4.20-pre2/drivers/net/wavelan.c
--- linux-2.4.20-pre1/drivers/net/wavelan.c	Mon Feb 25 11:38:03 2002
+++ linux-2.4.20-pre2/drivers/net/wavelan.c	Mon Aug 12 16:34:16 2002
@@ -2782,6 +2782,9 @@
 		    (unsigned char *) &nop.nop_h.ac_link,
 		    sizeof(nop.nop_h.ac_link));
 
+	/* Make sure the watchdog will keep quiet for a while */
+	dev->trans_start = jiffies;
+
 	/* Keep stats up to date. */
 	lp->stats.tx_bytes += length;
 
diff -urN linux-2.4.20-pre1/drivers/net/wavelan.p.h linux-2.4.20-pre2/drivers/net/wavelan.p.h
--- linux-2.4.20-pre1/drivers/net/wavelan.p.h	Fri Oct 12 14:21:18 2001
+++ linux-2.4.20-pre2/drivers/net/wavelan.p.h	Mon Aug 12 16:34:16 2002
@@ -345,6 +345,10 @@
  *	- Fix spinlock stupid bugs that I left in. The driver is now SMP
  *		compliant and doesn't lockup at startup.
  *
+ * Changes made for release in 2.4.20 :
+ * ----------------------------------
+ *	- Set dev->trans_start to avoid filling the logs
+ *
  * Wishes & dreams:
  * ----------------
  *	- roaming (see Pcmcia driver)
diff -urN linux-2.4.20-pre1/drivers/net/wireless/Config.in linux-2.4.20-pre2/drivers/net/wireless/Config.in
--- linux-2.4.20-pre1/drivers/net/wireless/Config.in	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/wireless/Config.in	Mon Aug 12 16:34:16 2002
@@ -13,8 +13,8 @@
 fi
 
 if [ "$CONFIG_PCI" = "y" ]; then
-   dep_tristate '    Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)' CONFIG_PLX_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
-   dep_tristate '    Prism 2.5 PCI 802.11b adaptor support' CONFIG_PCI_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
+   dep_tristate '    Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)' CONFIG_PLX_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
+   dep_tristate '    Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)' CONFIG_PCI_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
 fi
 
 # If Pcmcia is compiled in, offer Pcmcia cards...
diff -urN linux-2.4.20-pre1/drivers/net/wireless/airo.c linux-2.4.20-pre2/drivers/net/wireless/airo.c
--- linux-2.4.20-pre1/drivers/net/wireless/airo.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/net/wireless/airo.c	Mon Aug 12 16:34:16 2002
@@ -269,7 +269,7 @@
 
 /* This is a kind of sloppy hack to get this information to OUT4500 and
    IN4500.  I would be extremely interested in the situation where this
-   doesnt work though!!! */
+   doesn't work though!!! */
 static int do8bitIO = 0;
 
 /* Return codes */
@@ -3658,7 +3658,7 @@
 	struct net_device_list *next;
 } *airo_devices = 0;
 
-/* Since the card doesnt automatically switch to the right WEP mode,
+/* Since the card doesn't automatically switch to the right WEP mode,
    we will make it do it.  If the card isn't associated, every secs we
    will switch WEP modes to see if that will help.  If the card is
    associated we will check every minute to see if anything has
diff -urN linux-2.4.20-pre1/drivers/net/wireless/orinoco_plx.c linux-2.4.20-pre2/drivers/net/wireless/orinoco_plx.c
--- linux-2.4.20-pre1/drivers/net/wireless/orinoco_plx.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/wireless/orinoco_plx.c	Mon Aug 12 16:34:16 2002
@@ -363,6 +363,7 @@
 
 
 static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = {
+	{0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,},	/* 3ComAirConnect */
 	{0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},	/* Siemens SpeedStream SS1023 */
 	{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},	/* Netgear MA301 */
 	{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},	/* Correga  - does this work? */
diff -urN linux-2.4.20-pre1/drivers/net/zlib.c linux-2.4.20-pre2/drivers/net/zlib.c
--- linux-2.4.20-pre1/drivers/net/zlib.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/net/zlib.c	Wed Dec 31 16:00:00 1969
@@ -1,5376 +0,0 @@
-/*
- * This file is derived from various .h and .c files from the zlib-1.0.4
- * 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:
- * - added Z_PACKET_FLUSH (see zlib.h for details)
- * - added inflateIncomp and deflateOutputPending
- * - allow strm->next_out to be NULL, meaning discard the output
- *
- * $Id: zlib.c,v 1.3 1997/12/23 10:47:42 paulus Exp $
- */
-
-/* 
- *  ==FILEVERSION 20020318==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-#define NO_DUMMY_DECL
-#define NO_ZCFUNCS
-#define MY_ZCALLOC
-
-#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
-#define inflate	inflate_ppp	/* FreeBSD already has an inflate :-( */
-#endif
-
-
-/* +++ zutil.h */
-/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-1996 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.16 1996/07/24 13:41:13 me Exp $ */
-
-#ifndef _Z_UTIL_H
-#define _Z_UTIL_H
-
-#include "zlib.h"
-
-#if defined(KERNEL) || defined(_KERNEL)
-/* Assume this is a *BSD or SVR4 kernel */
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/systm.h>
-#  define HAVE_MEMCPY
-#  define memcpy(d, s, n)	bcopy((s), (d), (n))
-#  define memset(d, v, n)	bzero((d), (n))
-#  define memcmp		bcmp
-
-#else
-#if defined(__KERNEL__)
-/* Assume this is a Linux kernel */
-#include <linux/string.h>
-#define HAVE_MEMCPY
-
-#else /* not kernel */
-
-#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
-#   include <stddef.h>
-#   include <errno.h>
-#else
-    extern int errno;
-#endif
-#ifdef STDC
-#  include <string.h>
-#  include <stdlib.h>
-#endif
-#endif /* __KERNEL__ */
-#endif /* _KERNEL || KERNEL */
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-typedef unsigned char  uch;
-typedef uch FAR uchf;
-typedef unsigned short ush;
-typedef ush FAR ushf;
-typedef unsigned long  ulg;
-
-extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
-/* (size given to avoid silly warnings with Visual C++) */
-
-#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
-
-#define ERR_RETURN(strm,err) \
-  return (strm->msg = (char*)ERR_MSG(err), (err))
-/* To be used only when the state is known to be valid */
-
-        /* common constants */
-
-#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 */
-
-#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
-
-        /* target dependencies */
-
-#ifdef MSDOS
-#  define OS_CODE  0x00
-#  ifdef __TURBOC__
-#    include <alloc.h>
-#  else /* MSC or DJGPP */
-#    include <malloc.h>
-#  endif
-#endif
-
-#ifdef OS2
-#  define OS_CODE  0x06
-#endif
-
-#ifdef WIN32 /* Window 95 & Windows NT */
-#  define OS_CODE  0x0b
-#endif
-
-#if defined(VAXC) || defined(VMS)
-#  define OS_CODE  0x02
-#  define FOPEN(name, mode) \
-     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
-#endif
-
-#ifdef AMIGA
-#  define OS_CODE  0x01
-#endif
-
-#if defined(ATARI) || defined(atarist)
-#  define OS_CODE  0x05
-#endif
-
-#ifdef MACOS
-#  define OS_CODE  0x07
-#endif
-
-#ifdef __50SERIES /* Prime/PRIMOS */
-#  define OS_CODE  0x0F
-#endif
-
-#ifdef TOPS20
-#  define OS_CODE  0x0a
-#endif
-
-#if defined(_BEOS_) || defined(RISCOS)
-#  define fdopen(fd,mode) NULL /* No fdopen() */
-#endif
-
-        /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03  /* assume Unix */
-#endif
-
-#ifndef FOPEN
-#  define FOPEN(name, mode) fopen((name), (mode))
-#endif
-
-         /* functions */
-
-#ifdef HAVE_STRERROR
-   extern char *strerror OF((int));
-#  define zstrerror(errnum) strerror(errnum)
-#else
-#  define zstrerror(errnum) ""
-#endif
-
-#if defined(pyr)
-#  define NO_MEMCPY
-#endif
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
- /* Use our own functions for small and medium model with MSC <= 5.0.
-  * You may have to use the same strategy for Borland C (untested).
-  */
-#  define NO_MEMCPY
-#endif
-#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
-#  define HAVE_MEMCPY
-#endif
-#ifdef HAVE_MEMCPY
-#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
-#    define zmemcpy _fmemcpy
-#    define zmemcmp _fmemcmp
-#    define zmemzero(dest, len) _fmemset(dest, 0, len)
-#  else
-#    define zmemcpy memcpy
-#    define zmemcmp memcmp
-#    define zmemzero(dest, len) memset(dest, 0, len)
-#  endif
-#else
-   extern void zmemcpy  OF((Bytef* dest, Bytef* source, uInt len));
-   extern int  zmemcmp  OF((Bytef* s1,   Bytef* s2, uInt len));
-   extern void zmemzero OF((Bytef* dest, uInt len));
-#endif
-
-/* Diagnostic functions */
-#ifdef DEBUG_ZLIB
-#  include <stdio.h>
-#  ifndef verbose
-#    define verbose 0
-#  endif
-   extern void z_error    OF((char *m));
-#  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, const 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)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
-#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
-
-#endif /* _Z_UTIL_H */
-/* --- zutil.h */
-
-/* +++ deflate.h */
-/* deflate.h -- internal compression state
- * Copyright (C) 1995-1996 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: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
-
-#ifndef _DEFLATE_H
-#define _DEFLATE_H
-
-/* #include "zutil.h" */
-
-/* ===========================================================================
- * Internal compression state.
- */
-
-#define LENGTH_CODES 29
-/* number of length codes, not counting the special END_BLOCK code */
-
-#define LITERALS  256
-/* number of literal bytes 0..255 */
-
-#define L_CODES (LITERALS+1+LENGTH_CODES)
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-#define D_CODES   30
-/* number of distance codes */
-
-#define BL_CODES  19
-/* number of codes used to transfer the bit lengths */
-
-#define HEAP_SIZE (2*L_CODES+1)
-/* maximum heap size */
-
-#define MAX_BITS 15
-/* All codes must not exceed MAX_BITS bits */
-
-#define INIT_STATE    42
-#define BUSY_STATE   113
-#define FINISH_STATE 666
-/* Stream status */
-
-
-/* Data structure describing a single value and its code string. */
-typedef struct ct_data_s {
-    union {
-        ush  freq;       /* frequency count */
-        ush  code;       /* bit string */
-    } fc;
-    union {
-        ush  dad;        /* father node in Huffman tree */
-        ush  len;        /* length of bit string */
-    } dl;
-} FAR ct_data;
-
-#define Freq fc.freq
-#define Code fc.code
-#define Dad  dl.dad
-#define Len  dl.len
-
-typedef struct static_tree_desc_s  static_tree_desc;
-
-typedef struct tree_desc_s {
-    ct_data *dyn_tree;           /* the dynamic tree */
-    int     max_code;            /* largest code with non zero frequency */
-    static_tree_desc *stat_desc; /* the corresponding static tree */
-} FAR tree_desc;
-
-typedef ush Pos;
-typedef Pos FAR Posf;
-typedef unsigned IPos;
-
-/* A Pos is an index in the character window. We use short instead of int to
- * save space in the various tables. IPos is used only for parameter passing.
- */
-
-typedef struct deflate_state {
-    z_streamp strm;      /* pointer back to this zlib stream */
-    int   status;        /* as the name implies */
-    Bytef *pending_buf;  /* output still pending */
-    ulg   pending_buf_size; /* size of pending_buf */
-    Bytef *pending_out;  /* next pending byte to output to the stream */
-    int   pending;       /* nb of bytes in the pending buffer */
-    int   noheader;      /* suppress zlib header and adler32 */
-    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
-    Byte  method;        /* STORED (for zip only) or DEFLATED */
-    int   last_flush;    /* value of flush param for previous deflate call */
-
-                /* used by deflate.c: */
-
-    uInt  w_size;        /* LZ77 window size (32K by default) */
-    uInt  w_bits;        /* log2(w_size)  (8..16) */
-    uInt  w_mask;        /* w_size - 1 */
-
-    Bytef *window;
-    /* Sliding window. Input bytes are read into the second half of the window,
-     * and move to the first half later to keep a dictionary of at least wSize
-     * bytes. With this organization, matches are limited to a distance of
-     * wSize-MAX_MATCH bytes, but this ensures that IO is always
-     * performed with a length multiple of the block size. Also, it limits
-     * the window size to 64K, which is quite useful on MSDOS.
-     * To do: use the user input buffer as sliding window.
-     */
-
-    ulg window_size;
-    /* Actual size of window: 2*wSize, except when the user input buffer
-     * is directly used as sliding window.
-     */
-
-    Posf *prev;
-    /* Link to older string with same hash index. To limit the size of this
-     * array to 64K, this link is maintained only for the last 32K strings.
-     * An index in this array is thus a window index modulo 32K.
-     */
-
-    Posf *head; /* Heads of the hash chains or NIL. */
-
-    uInt  ins_h;          /* hash index of string to be inserted */
-    uInt  hash_size;      /* number of elements in hash table */
-    uInt  hash_bits;      /* log2(hash_size) */
-    uInt  hash_mask;      /* hash_size-1 */
-
-    uInt  hash_shift;
-    /* Number of bits by which ins_h must be shifted at each input
-     * step. It must be such that after MIN_MATCH steps, the oldest
-     * byte no longer takes part in the hash key, that is:
-     *   hash_shift * MIN_MATCH >= hash_bits
-     */
-
-    long block_start;
-    /* Window position at the beginning of the current output block. Gets
-     * negative when the window is moved backwards.
-     */
-
-    uInt match_length;           /* length of best match */
-    IPos prev_match;             /* previous match */
-    int match_available;         /* set if previous match exists */
-    uInt strstart;               /* start of string to insert */
-    uInt match_start;            /* start of matching string */
-    uInt lookahead;              /* number of valid bytes ahead in window */
-
-    uInt prev_length;
-    /* Length of the best match at previous step. Matches not greater than this
-     * are discarded. This is used in the lazy match evaluation.
-     */
-
-    uInt max_chain_length;
-    /* To speed up deflation, hash chains are never searched beyond this
-     * length.  A higher limit improves compression ratio but degrades the
-     * speed.
-     */
-
-    uInt max_lazy_match;
-    /* Attempt to find a better match only when the current match is strictly
-     * smaller than this value. This mechanism is used only for compression
-     * levels >= 4.
-     */
-#   define max_insert_length  max_lazy_match
-    /* Insert new strings in the hash table only if the match length is not
-     * greater than this length. This saves time but degrades compression.
-     * max_insert_length is used only for compression levels <= 3.
-     */
-
-    int level;    /* compression level (1..9) */
-    int strategy; /* favor or force Huffman coding*/
-
-    uInt good_match;
-    /* Use a faster search when the previous match is longer than this */
-
-    int nice_match; /* Stop searching when current match exceeds this */
-
-                /* used by trees.c: */
-    /* Didn't use ct_data typedef below to suppress compiler warning */
-    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
-    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
-    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
-
-    struct tree_desc_s l_desc;               /* desc. for literal tree */
-    struct tree_desc_s d_desc;               /* desc. for distance tree */
-    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
-
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
-    int heap_len;               /* number of elements in the heap */
-    int heap_max;               /* element of largest frequency */
-    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
-     * The same heap array is used to build all trees.
-     */
-
-    uch depth[2*L_CODES+1];
-    /* Depth of each subtree used as tie breaker for trees of equal frequency
-     */
-
-    uchf *l_buf;          /* buffer for literals or lengths */
-
-    uInt  lit_bufsize;
-    /* Size of match buffer for literals/lengths.  There are 4 reasons for
-     * limiting lit_bufsize to 64K:
-     *   - frequencies can be kept in 16 bit counters
-     *   - if compression is not successful for the first block, all input
-     *     data is still in the window so we can still emit a stored block even
-     *     when input comes from standard input.  (This can also be done for
-     *     all blocks if lit_bufsize is not greater than 32K.)
-     *   - if compression is not successful for a file smaller than 64K, we can
-     *     even emit a stored file instead of a stored block (saving 5 bytes).
-     *     This is applicable only for zip (not gzip or zlib).
-     *   - creating new Huffman trees less frequently may not provide fast
-     *     adaptation to changes in the input data statistics. (Take for
-     *     example a binary file with poorly compressible code followed by
-     *     a highly compressible string table.) Smaller buffer sizes give
-     *     fast adaptation but have of course the overhead of transmitting
-     *     trees more frequently.
-     *   - I can't count above 4
-     */
-
-    uInt last_lit;      /* running index in l_buf */
-
-    ushf *d_buf;
-    /* Buffer for distances. To simplify the code, d_buf and l_buf have
-     * the same number of elements. To use different lengths, an extra flag
-     * array would be necessary.
-     */
-
-    ulg opt_len;        /* bit length of current block with optimal trees */
-    ulg static_len;     /* bit length of current block with static trees */
-    ulg compressed_len; /* total bit length of compressed file */
-    uInt matches;       /* number of string matches in current block */
-    int last_eob_len;   /* bit length of EOB code for last block */
-
-#ifdef DEBUG_ZLIB
-    ulg bits_sent;      /* bit length of the compressed data */
-#endif
-
-    ush bi_buf;
-    /* Output buffer. bits are inserted starting at the bottom (least
-     * significant bits).
-     */
-    int bi_valid;
-    /* Number of valid bits in bi_buf.  All bits above the last valid bit
-     * are always zero.
-     */
-
-} FAR deflate_state;
-
-/* Output a byte on the stream.
- * IN assertion: there is enough room in pending_buf.
- */
-#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
-
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-        /* in trees.c */
-void _tr_init         OF((deflate_state *s));
-int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
-ulg  _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
-			  int eof));
-void _tr_align        OF((deflate_state *s));
-void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
-                          int eof));
-void _tr_stored_type_only OF((deflate_state *));
-
-#endif
-/* --- deflate.h */
-
-/* +++ deflate.c */
-/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process depends on being able to identify portions
- *      of the input text which are identical to earlier input (within a
- *      sliding window trailing behind the input currently being processed).
- *
- *      The most straightforward technique turns out to be the fastest for
- *      most input files: try all possible matches and select the longest.
- *      The key feature of this algorithm is that insertions into the string
- *      dictionary are very simple and thus fast, and deletions are avoided
- *      completely. Insertions are performed at each input character, whereas
- *      string matches are performed only when the previous match ends. So it
- *      is preferable to spend more time in matches to allow very fast string
- *      insertions and avoid deletions. The matching algorithm for small
- *      strings is inspired from that of Rabin & Karp. A brute force approach
- *      is used to find longer strings when a small match has been found.
- *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
- *      (by Leonid Broukhis).
- *         A previous version of this file used a more sophisticated algorithm
- *      (by Fiala and Greene) which is guaranteed to run in linear amortized
- *      time, but has a larger average cost, uses more memory and is patented.
- *      However the F&G algorithm may be faster for some highly redundant
- *      files if the parameter max_chain_length (described below) is too large.
- *
- *  ACKNOWLEDGEMENTS
- *
- *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
- *      I found it in 'freeze' written by Leonid Broukhis.
- *      Thanks to many people for bug reports and testing.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
- *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
- *
- *      A description of the Rabin and Karp algorithm is given in the book
- *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
- *
- *      Fiala,E.R., and Greene,D.H.
- *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
- *
- */
-
-/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
-
-/* #include "deflate.h" */
-
-char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-/* ===========================================================================
- *  Function prototypes.
- */
-typedef enum {
-    need_more,      /* block not completed, need more input or more output */
-    block_done,     /* block flush performed */
-    finish_started, /* finish started, need only more output at next deflate */
-    finish_done     /* finish done, accept no more input or output */
-} block_state;
-
-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
-/* Compression function. Returns the block state after the call. */
-
-local void fill_window    OF((deflate_state *s));
-local block_state deflate_stored OF((deflate_state *s, int flush));
-local block_state deflate_fast   OF((deflate_state *s, int flush));
-local block_state deflate_slow   OF((deflate_state *s, int flush));
-local void lm_init        OF((deflate_state *s));
-local void putShortMSB    OF((deflate_state *s, uInt b));
-local void flush_pending  OF((z_streamp strm));
-local int read_buf        OF((z_streamp strm, charf *buf, unsigned size));
-#ifdef ASMV
-      void match_init OF((void)); /* asm code initialization */
-      uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#else
-local uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#endif
-
-#ifdef DEBUG_ZLIB
-local  void check_match OF((deflate_state *s, IPos start, IPos match,
-                            int length));
-#endif
-
-/* ===========================================================================
- * Local data
- */
-
-#define NIL 0
-/* Tail of hash chains */
-
-#ifndef TOO_FAR
-#  define TOO_FAR 4096
-#endif
-/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-typedef struct config_s {
-   ush good_length; /* reduce lazy search above this match length */
-   ush max_lazy;    /* do not perform lazy search above this match length */
-   ush nice_length; /* quit search above this match length */
-   ush max_chain;
-   compress_func func;
-} config;
-
-local config configuration_table[10] = {
-/*      good lazy nice chain */
-/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
-/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
-/* 2 */ {4,    5, 16,    8, deflate_fast},
-/* 3 */ {4,    6, 32,   32, deflate_fast},
-
-/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
-/* 5 */ {8,   16, 32,   32, deflate_slow},
-/* 6 */ {8,   16, 128, 128, deflate_slow},
-/* 7 */ {8,   32, 128, 256, deflate_slow},
-/* 8 */ {32, 128, 258, 1024, deflate_slow},
-/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
-
-/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
- * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
- * meaning.
- */
-
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
-#ifndef NO_DUMMY_DECL
-struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
-#endif
-
-/* ===========================================================================
- * Update a hash value with the given input byte
- * IN  assertion: all calls to UPDATE_HASH are made with consecutive
- *    input characters, so that a running hash key can be computed from the
- *    previous key instead of complete recalculation each time.
- */
-#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
-
-
-/* ===========================================================================
- * Insert string str in the dictionary and set match_head to the previous head
- * of the hash chain (the most recent string with same hash key). Return
- * the previous length of the hash chain.
- * IN  assertion: all calls to INSERT_STRING are made with consecutive
- *    input characters and the first MIN_MATCH bytes of str are valid
- *    (except for the last MIN_MATCH-1 bytes of the input file).
- */
-#define INSERT_STRING(s, str, match_head) \
-   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
-    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
-    s->head[s->ins_h] = (Pos)(str))
-
-/* ===========================================================================
- * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
- * prev[] will be initialized on the fly.
- */
-#define CLEAR_HASH(s) \
-    s->head[s->hash_size-1] = NIL; \
-    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
-
-/* ========================================================================= */
-int deflateInit_(strm, level, version, stream_size)
-    z_streamp strm;
-    int level;
-    const char *version;
-    int stream_size;
-{
-    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
-			 Z_DEFAULT_STRATEGY, version, stream_size);
-    /* To do: ignore strm->next_in if we use it as window */
-}
-
-/* ========================================================================= */
-int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
-		  version, stream_size)
-    z_streamp strm;
-    int  level;
-    int  method;
-    int  windowBits;
-    int  memLevel;
-    int  strategy;
-    const char *version;
-    int stream_size;
-{
-    deflate_state *s;
-    int noheader = 0;
-    static char* my_version = ZLIB_VERSION;
-
-    ushf *overlay;
-    /* We overlay pending_buf and d_buf+l_buf. This works since the average
-     * output size for (length,distance) codes is <= 24 bits.
-     */
-
-    if (version == Z_NULL || version[0] != my_version[0] ||
-        stream_size != sizeof(z_stream)) {
-	return Z_VERSION_ERROR;
-    }
-    if (strm == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-    if (strm->zalloc == Z_NULL) {
-	strm->zalloc = zcalloc;
-	strm->opaque = (voidpf)0;
-    }
-    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
-#endif
-
-    if (level == Z_DEFAULT_COMPRESSION) level = 6;
-
-    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
-        noheader = 1;
-        windowBits = -windowBits;
-    }
-    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
-        windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
-	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
-    if (s == Z_NULL) return Z_MEM_ERROR;
-    strm->state = (struct internal_state FAR *)s;
-    s->strm = strm;
-
-    s->noheader = noheader;
-    s->w_bits = windowBits;
-    s->w_size = 1 << s->w_bits;
-    s->w_mask = s->w_size - 1;
-
-    s->hash_bits = memLevel + 7;
-    s->hash_size = 1 << s->hash_bits;
-    s->hash_mask = s->hash_size - 1;
-    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
-
-    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
-    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
-    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
-
-    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
-
-    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
-    s->pending_buf = (uchf *) overlay;
-    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
-
-    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
-        s->pending_buf == Z_NULL) {
-        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
-        deflateEnd (strm);
-        return Z_MEM_ERROR;
-    }
-    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
-    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
-
-    s->level = level;
-    s->strategy = strategy;
-    s->method = (Byte)method;
-
-    return deflateReset(strm);
-}
-
-/* ========================================================================= */
-int deflateSetDictionary (strm, dictionary, dictLength)
-    z_streamp strm;
-    const Bytef *dictionary;
-    uInt  dictLength;
-{
-    deflate_state *s;
-    uInt length = dictLength;
-    uInt n;
-    IPos hash_head = 0;
-
-    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
-	return Z_STREAM_ERROR;
-
-    s = (deflate_state *) strm->state;
-    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
-
-    strm->adler = adler32(strm->adler, dictionary, dictLength);
-
-    if (length < MIN_MATCH) return Z_OK;
-    if (length > MAX_DIST(s)) {
-	length = MAX_DIST(s);
-#ifndef USE_DICT_HEAD
-	dictionary += dictLength - length; /* use the tail of the dictionary */
-#endif
-    }
-    zmemcpy((charf *)s->window, dictionary, length);
-    s->strstart = length;
-    s->block_start = (long)length;
-
-    /* Insert all strings in the hash table (except for the last two bytes).
-     * s->lookahead stays null, so s->ins_h will be recomputed at the next
-     * call of fill_window.
-     */
-    s->ins_h = s->window[0];
-    UPDATE_HASH(s, s->ins_h, s->window[1]);
-    for (n = 0; n <= length - MIN_MATCH; n++) {
-	INSERT_STRING(s, n, hash_head);
-    }
-    if (hash_head) hash_head = 0;  /* to make compiler happy */
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateReset (strm)
-    z_streamp strm;
-{
-    deflate_state *s;
-    
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->total_in = strm->total_out = 0;
-    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
-    strm->data_type = Z_UNKNOWN;
-
-    s = (deflate_state *)strm->state;
-    s->pending = 0;
-    s->pending_out = s->pending_buf;
-
-    if (s->noheader < 0) {
-        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
-    }
-    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
-    strm->adler = 1;
-    s->last_flush = Z_NO_FLUSH;
-
-    _tr_init(s);
-    lm_init(s);
-
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateParams(strm, level, strategy)
-    z_streamp strm;
-    int level;
-    int strategy;
-{
-    deflate_state *s;
-    compress_func func;
-    int err = Z_OK;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    if (level == Z_DEFAULT_COMPRESSION) {
-	level = 6;
-    }
-    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-	return Z_STREAM_ERROR;
-    }
-    func = configuration_table[s->level].func;
-
-    if (func != configuration_table[level].func && strm->total_in != 0) {
-	/* Flush the last buffer: */
-	err = deflate(strm, Z_PARTIAL_FLUSH);
-    }
-    if (s->level != level) {
-	s->level = level;
-	s->max_lazy_match   = configuration_table[level].max_lazy;
-	s->good_match       = configuration_table[level].good_length;
-	s->nice_match       = configuration_table[level].nice_length;
-	s->max_chain_length = configuration_table[level].max_chain;
-    }
-    s->strategy = strategy;
-    return err;
-}
-
-/* =========================================================================
- * Put a short in the pending buffer. The 16-bit value is put in MSB order.
- * IN assertion: the stream state is correct and there is enough room in
- * pending_buf.
- */
-local void putShortMSB (s, b)
-    deflate_state *s;
-    uInt b;
-{
-    put_byte(s, (Byte)(b >> 8));
-    put_byte(s, (Byte)(b & 0xff));
-}   
-
-/* =========================================================================
- * Flush as much pending output as possible. All deflate() output goes
- * through this function so some applications may wish to modify it
- * to avoid allocating a large strm->next_out buffer and copying into it.
- * (See also read_buf()).
- */
-local void flush_pending(strm)
-    z_streamp strm;
-{
-    deflate_state *s = (deflate_state *) strm->state;
-    unsigned len = s->pending;
-
-    if (len > strm->avail_out) len = strm->avail_out;
-    if (len == 0) return;
-
-    if (strm->next_out != Z_NULL) {
-	zmemcpy(strm->next_out, s->pending_out, len);
-	strm->next_out += len;
-    }
-    s->pending_out += len;
-    strm->total_out += len;
-    strm->avail_out  -= len;
-    s->pending -= len;
-    if (s->pending == 0) {
-        s->pending_out = s->pending_buf;
-    }
-}
-
-/* ========================================================================= */
-int deflate (strm, flush)
-    z_streamp strm;
-    int flush;
-{
-    int old_flush; /* value of flush param for previous deflate call */
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-	flush > Z_FINISH || flush < 0) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) strm->state;
-
-    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
-	(s->status == FINISH_STATE && flush != Z_FINISH)) {
-        ERR_RETURN(strm, Z_STREAM_ERROR);
-    }
-    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
-
-    s->strm = strm; /* just in case */
-    old_flush = s->last_flush;
-    s->last_flush = flush;
-
-    /* Write the zlib header */
-    if (s->status == INIT_STATE) {
-
-        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
-        uInt level_flags = (s->level-1) >> 1;
-
-        if (level_flags > 3) level_flags = 3;
-        header |= (level_flags << 6);
-	if (s->strstart != 0) header |= PRESET_DICT;
-        header += 31 - (header % 31);
-
-        s->status = BUSY_STATE;
-        putShortMSB(s, header);
-
-	/* Save the adler32 of the preset dictionary: */
-	if (s->strstart != 0) {
-	    putShortMSB(s, (uInt)(strm->adler >> 16));
-	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-	}
-	strm->adler = 1L;
-    }
-
-    /* Flush as much pending output as possible */
-    if (s->pending != 0) {
-        flush_pending(strm);
-        if (strm->avail_out == 0) {
-	    /* Since avail_out is 0, deflate will be called again with
-	     * more output space, but possibly with both pending and
-	     * avail_in equal to zero. There won't be anything to do,
-	     * but this is not an error situation so make sure we
-	     * return OK instead of BUF_ERROR at next call of deflate:
-             */
-	    s->last_flush = -1;
-	    return Z_OK;
-	}
-
-    /* Make sure there is something to do and avoid duplicate consecutive
-     * flushes. For repeated and useless calls with Z_FINISH, we keep
-     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
-     */
-    } else if (strm->avail_in == 0 && flush <= old_flush &&
-	       flush != Z_FINISH) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* User must not provide more input after the first FINISH: */
-    if (s->status == FINISH_STATE && strm->avail_in != 0) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* Start a new block or continue the current one.
-     */
-    if (strm->avail_in != 0 || s->lookahead != 0 ||
-        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
-        block_state bstate;
-
-	bstate = (*(configuration_table[s->level].func))(s, flush);
-
-        if (bstate == finish_started || bstate == finish_done) {
-            s->status = FINISH_STATE;
-        }
-        if (bstate == need_more || bstate == finish_started) {
-	    if (strm->avail_out == 0) {
-	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
-	    }
-	    return Z_OK;
-	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
-	     * of deflate should use the same flush parameter to make sure
-	     * that the flush is complete. So we don't have to output an
-	     * empty block here, this will be done at next call. This also
-	     * ensures that for a very small output buffer, we emit at most
-	     * one empty block.
-	     */
-	}
-        if (bstate == block_done) {
-            if (flush == Z_PARTIAL_FLUSH) {
-                _tr_align(s);
-	    } else if (flush == Z_PACKET_FLUSH) {
-		/* Output just the 3-bit `stored' block type value,
-		   but not a zero length. */
-		_tr_stored_type_only(s);
-            } else { /* FULL_FLUSH or SYNC_FLUSH */
-                _tr_stored_block(s, (char*)0, 0L, 0);
-                /* For a full flush, this empty block will be recognized
-                 * as a special marker by inflate_sync().
-                 */
-                if (flush == Z_FULL_FLUSH) {
-                    CLEAR_HASH(s);             /* forget history */
-                }
-            }
-            flush_pending(strm);
-	    if (strm->avail_out == 0) {
-	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
-	      return Z_OK;
-	    }
-        }
-    }
-    Assert(strm->avail_out > 0, "bug2");
-
-    if (flush != Z_FINISH) return Z_OK;
-    if (s->noheader) return Z_STREAM_END;
-
-    /* Write the zlib trailer (adler32) */
-    putShortMSB(s, (uInt)(strm->adler >> 16));
-    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-    flush_pending(strm);
-    /* If avail_out is zero, the application will call deflate again
-     * to flush the rest.
-     */
-    s->noheader = -1; /* write the trailer only once! */
-    return s->pending != 0 ? Z_OK : Z_STREAM_END;
-}
-
-/* ========================================================================= */
-int deflateEnd (strm)
-    z_streamp strm;
-{
-    int status;
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    status = s->status;
-    if (status != INIT_STATE && status != BUSY_STATE &&
-	status != FINISH_STATE) {
-      return Z_STREAM_ERROR;
-    }
-
-    /* Deallocate in reverse order of allocations: */
-    TRY_FREE(strm, s->pending_buf);
-    TRY_FREE(strm, s->head);
-    TRY_FREE(strm, s->prev);
-    TRY_FREE(strm, s->window);
-
-    ZFREE(strm, s);
-    strm->state = Z_NULL;
-
-    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
-}
-
-/* =========================================================================
- * Copy the source state to the destination state.
- */
-int deflateCopy (dest, source)
-    z_streamp dest;
-    z_streamp source;
-{
-    deflate_state *ds;
-    deflate_state *ss;
-    ushf *overlay;
-
-    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
-        return Z_STREAM_ERROR;
-    ss = (deflate_state *) source->state;
-
-    *dest = *source;
-
-    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
-    if (ds == Z_NULL) return Z_MEM_ERROR;
-    dest->state = (struct internal_state FAR *) ds;
-    *ds = *ss;
-    ds->strm = dest;
-
-    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
-    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
-    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
-    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
-    ds->pending_buf = (uchf *) overlay;
-
-    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
-        ds->pending_buf == Z_NULL) {
-        deflateEnd (dest);
-        return Z_MEM_ERROR;
-    }
-    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
-    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
-    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
-    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
-    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
-
-    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
-    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
-    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
-
-    ds->l_desc.dyn_tree = ds->dyn_ltree;
-    ds->d_desc.dyn_tree = ds->dyn_dtree;
-    ds->bl_desc.dyn_tree = ds->bl_tree;
-
-    return Z_OK;
-}
-
-/* ===========================================================================
- * Return the number of bytes of output which are immediately available
- * for output from the decompressor.
- */
-int deflateOutputPending (strm)
-    z_streamp strm;
-{
-    if (strm == Z_NULL || strm->state == Z_NULL) return 0;
-    
-    return ((deflate_state *)(strm->state))->pending;
-}
-
-/* ===========================================================================
- * Read a new buffer from the current input stream, update the adler32
- * and total number of bytes read.  All deflate() input goes through
- * this function so some applications may wish to modify it to avoid
- * allocating a large strm->next_in buffer and copying from it.
- * (See also flush_pending()).
- */
-local int read_buf(strm, buf, size)
-    z_streamp strm;
-    charf *buf;
-    unsigned size;
-{
-    unsigned len = strm->avail_in;
-
-    if (len > size) len = size;
-    if (len == 0) return 0;
-
-    strm->avail_in  -= len;
-
-    if (!((deflate_state *)(strm->state))->noheader) {
-        strm->adler = adler32(strm->adler, strm->next_in, len);
-    }
-    zmemcpy(buf, strm->next_in, len);
-    strm->next_in  += len;
-    strm->total_in += len;
-
-    return (int)len;
-}
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new zlib stream
- */
-local void lm_init (s)
-    deflate_state *s;
-{
-    s->window_size = (ulg)2L*s->w_size;
-
-    CLEAR_HASH(s);
-
-    /* Set the default configuration parameters:
-     */
-    s->max_lazy_match   = configuration_table[s->level].max_lazy;
-    s->good_match       = configuration_table[s->level].good_length;
-    s->nice_match       = configuration_table[s->level].nice_length;
-    s->max_chain_length = configuration_table[s->level].max_chain;
-
-    s->strstart = 0;
-    s->block_start = 0L;
-    s->lookahead = 0;
-    s->match_length = s->prev_length = MIN_MATCH-1;
-    s->match_available = 0;
-    s->ins_h = 0;
-#ifdef ASMV
-    match_init(); /* initialize the asm code */
-#endif
-}
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- * OUT assertion: the match length is not greater than s->lookahead.
- */
-#ifndef ASMV
-/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
- * match.S. The code will be functionally equivalent.
- */
-local uInt longest_match(s, cur_match)
-    deflate_state *s;
-    IPos cur_match;                             /* current match */
-{
-    unsigned chain_length = s->max_chain_length;/* max hash chain length */
-    register Bytef *scan = s->window + s->strstart; /* current string */
-    register Bytef *match;                       /* matched string */
-    register int len;                           /* length of current match */
-    int best_len = s->prev_length;              /* best match length so far */
-    int nice_match = s->nice_match;             /* stop if match long enough */
-    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
-        s->strstart - (IPos)MAX_DIST(s) : NIL;
-    /* Stop when cur_match becomes <= limit. To simplify the code,
-     * we prevent matches with the string of window index 0.
-     */
-    Posf *prev = s->prev;
-    uInt wmask = s->w_mask;
-
-#ifdef UNALIGNED_OK
-    /* Compare two bytes at a time. Note: this is not always beneficial.
-     * Try with and without -DUNALIGNED_OK to check.
-     */
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
-    register ush scan_start = *(ushf*)scan;
-    register ush scan_end   = *(ushf*)(scan+best_len-1);
-#else
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
-    register Byte scan_end1  = scan[best_len-1];
-    register Byte scan_end   = scan[best_len];
-#endif
-
-    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
-     * It is easy to get rid of this optimization if necessary.
-     */
-    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-
-    /* Do not waste too much time if we already have a good match: */
-    if (s->prev_length >= s->good_match) {
-        chain_length >>= 2;
-    }
-    /* Do not look for matches beyond the end of the input. This is necessary
-     * to make deflate deterministic.
-     */
-    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
-
-    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-
-    do {
-        Assert(cur_match < s->strstart, "no future");
-        match = s->window + cur_match;
-
-        /* Skip to next match if the match length cannot increase
-         * or if the match length is less than 2:
-         */
-#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
-        /* This code assumes sizeof(unsigned short) == 2. Do not use
-         * UNALIGNED_OK if your compiler uses a different size.
-         */
-        if (*(ushf*)(match+best_len-1) != scan_end ||
-            *(ushf*)match != scan_start) continue;
-
-        /* It is not necessary to compare scan[2] and match[2] since they are
-         * always equal when the other bytes match, given that the hash keys
-         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
-         * strstart+3, +5, ... up to strstart+257. We check for insufficient
-         * lookahead only every 4th comparison; the 128th check will be made
-         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
-         * necessary to put more guard bytes at the end of the window, or
-         * to check more often for insufficient lookahead.
-         */
-        Assert(scan[2] == match[2], "scan[2]?");
-        scan++, match++;
-        do {
-        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 scan < strend);
-        /* The funny "do {}" generates better code on most compilers */
-
-        /* Here, scan <= window+strstart+257 */
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-        if (*scan == *match) scan++;
-
-        len = (MAX_MATCH - 1) - (int)(strend-scan);
-        scan = strend - (MAX_MATCH-1);
-
-#else /* UNALIGNED_OK */
-
-        if (match[best_len]   != scan_end  ||
-            match[best_len-1] != scan_end1 ||
-            *match            != *scan     ||
-            *++match          != scan[1])      continue;
-
-        /* The check at best_len-1 can be removed because it will be made
-         * again later. (This heuristic is not always a win.)
-         * It is not necessary to compare scan[2] and match[2] since they
-         * are always equal when the other bytes match, given that
-         * the hash keys are equal and that HASH_BITS >= 8.
-         */
-        scan += 2, match++;
-        Assert(*scan == *match, "match[2]?");
-
-        /* We check for insufficient lookahead only every 8th comparison;
-         * the 256th check will be made at strstart+258.
-         */
-        do {
-        } while (*++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 scan < strend);
-
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-
-        len = MAX_MATCH - (int)(strend - scan);
-        scan = strend - MAX_MATCH;
-
-#endif /* UNALIGNED_OK */
-
-        if (len > best_len) {
-            s->match_start = cur_match;
-            best_len = len;
-            if (len >= nice_match) break;
-#ifdef UNALIGNED_OK
-            scan_end = *(ushf*)(scan+best_len-1);
-#else
-            scan_end1  = scan[best_len-1];
-            scan_end   = scan[best_len];
-#endif
-        }
-    } while ((cur_match = prev[cur_match & wmask]) > limit
-             && --chain_length != 0);
-
-    if ((uInt)best_len <= s->lookahead) return best_len;
-    return s->lookahead;
-}
-#endif /* ASMV */
-
-#ifdef DEBUG_ZLIB
-/* ===========================================================================
- * Check that the match at match_start is indeed a match.
- */
-local void check_match(s, start, match, length)
-    deflate_state *s;
-    IPos start, match;
-    int length;
-{
-    /* check that the match is indeed a match */
-    if (zmemcmp((charf *)s->window + match,
-                (charf *)s->window + start, length) != EQUAL) {
-        fprintf(stderr, " start %u, match %u, length %d\n",
-		start, match, length);
-        do {
-	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
-	} while (--length != 0);
-        z_error("invalid match");
-    }
-    if (z_verbose > 1) {
-        fprintf(stderr,"\\[%d,%d]", start-match, length);
-        do { putc(s->window[start++], stderr); } while (--length != 0);
-    }
-}
-#else
-#  define check_match(s, start, match, length)
-#endif
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead.
- *
- * IN assertion: lookahead < MIN_LOOKAHEAD
- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- *    At least one byte has been read, or avail_in == 0; reads are
- *    performed for at least two bytes (required for the zip translate_eol
- *    option -- not supported here).
- */
-local void fill_window(s)
-    deflate_state *s;
-{
-    register unsigned n, m;
-    register Posf *p;
-    unsigned more;    /* Amount of free space at the end of the window. */
-    uInt wsize = s->w_size;
-
-    do {
-        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
-
-        /* Deal with !@#$% 64K limit: */
-        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
-            more = wsize;
-
-        } else if (more == (unsigned)(-1)) {
-            /* Very unlikely, but possible on 16 bit machine if strstart == 0
-             * and lookahead == 1 (input done one byte at time)
-             */
-            more--;
-
-        /* If the window is almost full and there is insufficient lookahead,
-         * move the upper half to the lower one to make room in the upper half.
-         */
-        } else if (s->strstart >= wsize+MAX_DIST(s)) {
-
-            zmemcpy((charf *)s->window, (charf *)s->window+wsize,
-                   (unsigned)wsize);
-            s->match_start -= wsize;
-            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
-            s->block_start -= (long) wsize;
-
-            /* Slide the hash table (could be avoided with 32 bit values
-               at the expense of memory usage). We slide even when level == 0
-               to keep the hash table consistent if we switch back to level > 0
-               later. (Using level 0 permanently is not an optimal usage of
-               zlib, so we don't care about this pathological case.)
-             */
-            n = s->hash_size;
-            p = &s->head[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-            } while (--n);
-
-            n = wsize;
-            p = &s->prev[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-                /* If n is not on any hash chain, prev[n] is garbage but
-                 * its value will never be used.
-                 */
-            } while (--n);
-            more += wsize;
-        }
-        if (s->strm->avail_in == 0) return;
-
-        /* If there was no sliding:
-         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
-         *    more == window_size - lookahead - strstart
-         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
-         * => more >= window_size - 2*WSIZE + 2
-         * In the BIG_MEM or MMAP case (not yet supported),
-         *   window_size == input_size + MIN_LOOKAHEAD  &&
-         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
-         * Otherwise, window_size == 2*WSIZE so more >= 2.
-         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
-         */
-        Assert(more >= 2, "more < 2");
-
-        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
-                     more);
-        s->lookahead += n;
-
-        /* Initialize the hash value now that we have some input: */
-        if (s->lookahead >= MIN_MATCH) {
-            s->ins_h = s->window[s->strstart];
-            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-            Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-        }
-        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
-         * but this is not important since only literal bytes will be emitted.
-         */
-
-    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
-}
-
-/* ===========================================================================
- * Flush the current block, with given end-of-file flag.
- * IN assertion: strstart is set to the end of the current match.
- */
-#define FLUSH_BLOCK_ONLY(s, eof) { \
-   _tr_flush_block(s, (s->block_start >= 0L ? \
-                   (charf *)&s->window[(unsigned)s->block_start] : \
-                   (charf *)Z_NULL), \
-		(ulg)((long)s->strstart - s->block_start), \
-		(eof)); \
-   s->block_start = s->strstart; \
-   flush_pending(s->strm); \
-   Tracev((stderr,"[FLUSH]")); \
-}
-
-/* Same but force premature exit if necessary. */
-#define FLUSH_BLOCK(s, eof) { \
-   FLUSH_BLOCK_ONLY(s, eof); \
-   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
-}
-
-/* ===========================================================================
- * Copy without compression as much as possible from the input stream, return
- * the current block state.
- * This function does not insert new strings in the dictionary since
- * uncompressible data is probably not useful. This function is used
- * only for the level=0 compression option.
- * NOTE: this function should be optimized to avoid extra copying from
- * window to pending_buf.
- */
-local block_state deflate_stored(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
-     * to pending_buf_size, and each stored block has a 5 byte header:
-     */
-    ulg max_block_size = 0xffff;
-    ulg max_start;
-
-    if (max_block_size > s->pending_buf_size - 5) {
-        max_block_size = s->pending_buf_size - 5;
-    }
-
-    /* Copy as much as possible from input to output: */
-    for (;;) {
-        /* Fill the window as much as possible: */
-        if (s->lookahead <= 1) {
-
-            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
-		   s->block_start >= (long)s->w_size, "slide too late");
-
-            fill_window(s);
-            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
-
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-	Assert(s->block_start >= 0L, "block gone");
-
-	s->strstart += s->lookahead;
-	s->lookahead = 0;
-
-	/* Emit a stored block if pending_buf will be full: */
- 	max_start = s->block_start + max_block_size;
-        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
-	    /* strstart == 0 is possible when wraparound on 16-bit machine */
-	    s->lookahead = (uInt)(s->strstart - max_start);
-	    s->strstart = (uInt)max_start;
-            FLUSH_BLOCK(s, 0);
-	}
-	/* Flush if we may have to slide, otherwise block_start may become
-         * negative and the data will be gone:
-         */
-        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
-            FLUSH_BLOCK(s, 0);
-	}
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Compress as much as possible from the input stream, return the current
- * block state.
- * This function does not perform lazy evaluation of matches and inserts
- * new strings in the dictionary only for unmatched strings or for short
- * matches. It is used only for the fast compression options.
- */
-local block_state deflate_fast(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL; /* head of the hash chain */
-    int bflush;           /* set if current block must be flushed */
-
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         * At this point we have always match_length < MIN_MATCH
-         */
-        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-        }
-        if (s->match_length >= MIN_MATCH) {
-            check_match(s, s->strstart, s->match_start, s->match_length);
-
-            bflush = _tr_tally(s, s->strstart - s->match_start,
-                               s->match_length - MIN_MATCH);
-
-            s->lookahead -= s->match_length;
-
-            /* Insert new strings in the hash table only if the match length
-             * is not too large. This saves time but degrades compression.
-             */
-            if (s->match_length <= s->max_insert_length &&
-                s->lookahead >= MIN_MATCH) {
-                s->match_length--; /* string at strstart already in hash table */
-                do {
-                    s->strstart++;
-                    INSERT_STRING(s, s->strstart, hash_head);
-                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                     * always MIN_MATCH bytes ahead.
-                     */
-                } while (--s->match_length != 0);
-                s->strstart++; 
-            } else {
-                s->strstart += s->match_length;
-                s->match_length = 0;
-                s->ins_h = s->window[s->strstart];
-                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-                Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
-                 * matter since it will be recomputed at next deflate call.
-                 */
-            }
-        } else {
-            /* No match, output a literal byte */
-            Tracevv((stderr,"%c", s->window[s->strstart]));
-            bflush = _tr_tally (s, 0, s->window[s->strstart]);
-            s->lookahead--;
-            s->strstart++; 
-        }
-        if (bflush) FLUSH_BLOCK(s, 0);
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-local block_state deflate_slow(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL;    /* head of hash chain */
-    int bflush;              /* set if current block must be flushed */
-
-    /* Process the input block. */
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         */
-        s->prev_length = s->match_length, s->prev_match = s->match_start;
-        s->match_length = MIN_MATCH-1;
-
-        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
-            s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-
-            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
-                 (s->match_length == MIN_MATCH &&
-                  s->strstart - s->match_start > TOO_FAR))) {
-
-                /* If prev_match is also MIN_MATCH, match_start is garbage
-                 * but we will ignore the current match anyway.
-                 */
-                s->match_length = MIN_MATCH-1;
-            }
-        }
-        /* If there was a match at the previous step and the current
-         * match is not better, output the previous match:
-         */
-        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
-            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
-            /* Do not insert strings in hash table beyond this. */
-
-            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
-
-            bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
-                               s->prev_length - MIN_MATCH);
-
-            /* Insert in hash table all strings up to the end of the match.
-             * strstart-1 and strstart are already inserted. If there is not
-             * enough lookahead, the last two strings are not inserted in
-             * the hash table.
-             */
-            s->lookahead -= s->prev_length-1;
-            s->prev_length -= 2;
-            do {
-                if (++s->strstart <= max_insert) {
-                    INSERT_STRING(s, s->strstart, hash_head);
-                }
-            } while (--s->prev_length != 0);
-            s->match_available = 0;
-            s->match_length = MIN_MATCH-1;
-            s->strstart++;
-
-            if (bflush) FLUSH_BLOCK(s, 0);
-
-        } else if (s->match_available) {
-            /* If there was no match at the previous position, output a
-             * single literal. If there was a match but the current match
-             * is longer, truncate the previous match to a single literal.
-             */
-            Tracevv((stderr,"%c", s->window[s->strstart-1]));
-            if (_tr_tally (s, 0, s->window[s->strstart-1])) {
-                FLUSH_BLOCK_ONLY(s, 0);
-            }
-            s->strstart++;
-            s->lookahead--;
-            if (s->strm->avail_out == 0) return need_more;
-        } else {
-            /* There is no previous match to compare with, wait for
-             * the next step to decide.
-             */
-            s->match_available = 1;
-            s->strstart++;
-            s->lookahead--;
-        }
-    }
-    Assert (flush != Z_NO_FLUSH, "no flush?");
-    if (s->match_available) {
-        Tracevv((stderr,"%c", s->window[s->strstart-1]));
-        _tr_tally (s, 0, s->window[s->strstart-1]);
-        s->match_available = 0;
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-/* --- deflate.c */
-
-/* +++ trees.c */
-/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process uses several Huffman trees. The more
- *      common source values are represented by shorter bit sequences.
- *
- *      Each code tree is stored in a compressed form which is itself
- * a Huffman encoding of the lengths of all the code strings (in
- * ascending order by source values).  The actual code strings are
- * reconstructed from the lengths in the inflate process, as described
- * in the deflate specification.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
- *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
- *
- *      Storer, James A.
- *          Data Compression:  Methods and Theory, pp. 49-50.
- *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
- *
- *      Sedgewick, R.
- *          Algorithms, p290.
- *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
- */
-
-/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
-
-/* #include "deflate.h" */
-
-#ifdef DEBUG_ZLIB
-#  include <ctype.h>
-#endif
-
-/* ===========================================================================
- * Constants
- */
-
-#define MAX_BL_BITS 7
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-#define END_BLOCK 256
-/* end of block literal code */
-
-#define REP_3_6      16
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-
-#define REPZ_3_10    17
-/* repeat a zero length 3-10 times  (3 bits of repeat count) */
-
-#define REPZ_11_138  18
-/* repeat a zero length 11-138 times  (7 bits of repeat count) */
-
-local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
-   = {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};
-
-local int extra_dbits[D_CODES] /* extra bits for each distance code */
-   = {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};
-
-local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
-   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
-
-local uch bl_order[BL_CODES]
-   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-#define Buf_size (8 * 2*sizeof(char))
-/* Number of bits used within bi_buf. (bi_buf might be implemented on
- * more than 16 bits on some systems.)
- */
-
-/* ===========================================================================
- * Local data. These are initialized only once.
- */
-
-local ct_data static_ltree[L_CODES+2];
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
- * below).
- */
-
-local ct_data static_dtree[D_CODES];
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-local uch dist_code[512];
-/* distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-local uch length_code[MAX_MATCH-MIN_MATCH+1];
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-local int base_length[LENGTH_CODES];
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-local int base_dist[D_CODES];
-/* First normalized distance for each code (0 = distance of 1) */
-
-struct static_tree_desc_s {
-    ct_data *static_tree;        /* static tree or NULL */
-    intf    *extra_bits;         /* extra bits for each code or NULL */
-    int     extra_base;          /* base index for extra_bits */
-    int     elems;               /* max number of elements in the tree */
-    int     max_length;          /* max bit length for the codes */
-};
-
-local static_tree_desc  static_l_desc =
-{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
-
-local static_tree_desc  static_d_desc =
-{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
-
-local static_tree_desc  static_bl_desc =
-{(ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS};
-
-/* ===========================================================================
- * Local (static) routines in this file.
- */
-
-local void tr_static_init OF((void));
-local void init_block     OF((deflate_state *s));
-local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
-local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
-local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
-local void build_tree     OF((deflate_state *s, tree_desc *desc));
-local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local int  build_bl_tree  OF((deflate_state *s));
-local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
-                              int blcodes));
-local void compress_block OF((deflate_state *s, ct_data *ltree,
-                              ct_data *dtree));
-local void set_data_type  OF((deflate_state *s));
-local unsigned bi_reverse OF((unsigned value, int length));
-local void bi_windup      OF((deflate_state *s));
-local void bi_flush       OF((deflate_state *s));
-local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
-                              int header));
-
-#ifndef DEBUG_ZLIB
-#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
-   /* Send a code of the given tree. c and tree must not have side effects */
-
-#else /* DEBUG_ZLIB */
-#  define send_code(s, c, tree) \
-     { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
-       send_bits(s, tree[c].Code, tree[c].Len); }
-#endif
-
-#define d_code(dist) \
-   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
-/* Mapping from a distance to a distance code. dist is the distance - 1 and
- * must not have side effects. dist_code[256] and dist_code[257] are never
- * used.
- */
-
-/* ===========================================================================
- * Output a short LSB first on the stream.
- * IN assertion: there is enough room in pendingBuf.
- */
-#define put_short(s, w) { \
-    put_byte(s, (uch)((w) & 0xff)); \
-    put_byte(s, (uch)((ush)(w) >> 8)); \
-}
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-#ifdef DEBUG_ZLIB
-local void send_bits      OF((deflate_state *s, int value, int length));
-
-local void send_bits(s, value, length)
-    deflate_state *s;
-    int value;  /* value to send */
-    int length; /* number of bits */
-{
-    Tracevv((stderr," l %2d v %4x ", length, value));
-    Assert(length > 0 && length <= 15, "invalid length");
-    s->bits_sent += (ulg)length;
-
-    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-     * unused bits in value.
-     */
-    if (s->bi_valid > (int)Buf_size - length) {
-        s->bi_buf |= (value << s->bi_valid);
-        put_short(s, s->bi_buf);
-        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
-        s->bi_valid += length - Buf_size;
-    } else {
-        s->bi_buf |= value << s->bi_valid;
-        s->bi_valid += length;
-    }
-}
-#else /* !DEBUG_ZLIB */
-
-#define send_bits(s, value, length) \
-{ int len = length;\
-  if (s->bi_valid > (int)Buf_size - len) {\
-    int val = value;\
-    s->bi_buf |= (val << s->bi_valid);\
-    put_short(s, s->bi_buf);\
-    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
-    s->bi_valid += len - Buf_size;\
-  } else {\
-    s->bi_buf |= (value) << s->bi_valid;\
-    s->bi_valid += len;\
-  }\
-}
-#endif /* DEBUG_ZLIB */
-
-
-#define MAX(a,b) (a >= b ? a : b)
-/* the arguments must not have side effects */
-
-/* ===========================================================================
- * Initialize the various 'constant' tables. In a multi-threaded environment,
- * this function may be called by two threads concurrently, but this is
- * harmless since both invocations do exactly the same thing.
- */
-local void tr_static_init()
-{
-    static int static_init_done;
-    int n;        /* iterates over tree elements */
-    int bits;     /* bit counter */
-    int length;   /* length value */
-    int code;     /* code value */
-    int dist;     /* distance index */
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    if (static_init_done) return;
-
-    /* Initialize the mapping length (0..255) -> length code (0..28) */
-    length = 0;
-    for (code = 0; code < LENGTH_CODES-1; code++) {
-        base_length[code] = length;
-        for (n = 0; n < (1<<extra_lbits[code]); n++) {
-            length_code[length++] = (uch)code;
-        }
-    }
-    Assert (length == 256, "tr_static_init: length != 256");
-    /* Note that the length 255 (match length 258) can be represented
-     * in two different ways: code 284 + 5 bits or code 285, so we
-     * overwrite length_code[255] to use the best encoding:
-     */
-    length_code[length-1] = (uch)code;
-
-    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-    dist = 0;
-    for (code = 0 ; code < 16; code++) {
-        base_dist[code] = dist;
-        for (n = 0; n < (1<<extra_dbits[code]); n++) {
-            dist_code[dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: dist != 256");
-    dist >>= 7; /* from now on, all distances are divided by 128 */
-    for ( ; code < D_CODES; code++) {
-        base_dist[code] = dist << 7;
-        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
-            dist_code[256 + dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: 256+dist != 512");
-
-    /* Construct the codes of the static literal tree */
-    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
-    n = 0;
-    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
-    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
-    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
-    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
-    /* Codes 286 and 287 do not exist, but we must include them in the
-     * tree construction to get a canonical Huffman tree (longest code
-     * all ones)
-     */
-    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
-
-    /* The static distance tree is trivial: */
-    for (n = 0; n < D_CODES; n++) {
-        static_dtree[n].Len = 5;
-        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
-    }
-    static_init_done = 1;
-}
-
-/* ===========================================================================
- * Initialize the tree data structures for a new zlib stream.
- */
-void _tr_init(s)
-    deflate_state *s;
-{
-    tr_static_init();
-
-    s->compressed_len = 0L;
-
-    s->l_desc.dyn_tree = s->dyn_ltree;
-    s->l_desc.stat_desc = &static_l_desc;
-
-    s->d_desc.dyn_tree = s->dyn_dtree;
-    s->d_desc.stat_desc = &static_d_desc;
-
-    s->bl_desc.dyn_tree = s->bl_tree;
-    s->bl_desc.stat_desc = &static_bl_desc;
-
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-#ifdef DEBUG_ZLIB
-    s->bits_sent = 0L;
-#endif
-
-    /* Initialize the first block of the first file: */
-    init_block(s);
-}
-
-/* ===========================================================================
- * Initialize a new block.
- */
-local void init_block(s)
-    deflate_state *s;
-{
-    int n; /* iterates over tree elements */
-
-    /* Initialize the trees. */
-    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
-    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
-    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
-
-    s->dyn_ltree[END_BLOCK].Freq = 1;
-    s->opt_len = s->static_len = 0L;
-    s->last_lit = s->matches = 0;
-}
-
-#define SMALLEST 1
-/* Index within the heap array of least frequent node in the Huffman tree */
-
-
-/* ===========================================================================
- * Remove the smallest element from the heap and recreate the heap with
- * one less element. Updates heap and heap_len.
- */
-#define pqremove(s, tree, top) \
-{\
-    top = s->heap[SMALLEST]; \
-    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
-    pqdownheap(s, tree, SMALLEST); \
-}
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-#define smaller(tree, n, m, depth) \
-   (tree[n].Freq < tree[m].Freq || \
-   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-local void pqdownheap(s, tree, k)
-    deflate_state *s;
-    ct_data *tree;  /* the tree to restore */
-    int k;               /* node to move down */
-{
-    int v = s->heap[k];
-    int j = k << 1;  /* left son of k */
-    while (j <= s->heap_len) {
-        /* Set j to the smallest of the two sons: */
-        if (j < s->heap_len &&
-            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
-            j++;
-        }
-        /* Exit if v is smaller than both sons */
-        if (smaller(tree, v, s->heap[j], s->depth)) break;
-
-        /* Exchange v with the smallest son */
-        s->heap[k] = s->heap[j];  k = j;
-
-        /* And continue down the tree, setting j to the left son of k */
-        j <<= 1;
-    }
-    s->heap[k] = v;
-}
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- *    above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- *     array bl_count contains the frequencies for each bit length.
- *     The length opt_len is updated; static_len is also updated if stree is
- *     not null.
- */
-local void gen_bitlen(s, desc)
-    deflate_state *s;
-    tree_desc *desc;    /* the tree descriptor */
-{
-    ct_data *tree  = desc->dyn_tree;
-    int max_code   = desc->max_code;
-    ct_data *stree = desc->stat_desc->static_tree;
-    intf *extra    = desc->stat_desc->extra_bits;
-    int base       = desc->stat_desc->extra_base;
-    int max_length = desc->stat_desc->max_length;
-    int h;              /* heap index */
-    int n, m;           /* iterate over the tree elements */
-    int bits;           /* bit length */
-    int xbits;          /* extra bits */
-    ush f;              /* frequency */
-    int overflow = 0;   /* number of elements with bit length too large */
-
-    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
-
-    /* In a first pass, compute the optimal bit lengths (which may
-     * overflow in the case of the bit length tree).
-     */
-    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
-
-    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
-        n = s->heap[h];
-        bits = tree[tree[n].Dad].Len + 1;
-        if (bits > max_length) bits = max_length, overflow++;
-        tree[n].Len = (ush)bits;
-        /* We overwrite tree[n].Dad which is no longer needed */
-
-        if (n > max_code) continue; /* not a leaf node */
-
-        s->bl_count[bits]++;
-        xbits = 0;
-        if (n >= base) xbits = extra[n-base];
-        f = tree[n].Freq;
-        s->opt_len += (ulg)f * (bits + xbits);
-        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
-    }
-    if (overflow == 0) return;
-
-    Trace((stderr,"\nbit length overflow\n"));
-    /* This happens for example on obj2 and pic of the Calgary corpus */
-
-    /* Find the first bit length which could increase: */
-    do {
-        bits = max_length-1;
-        while (s->bl_count[bits] == 0) bits--;
-        s->bl_count[bits]--;      /* move one leaf down the tree */
-        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
-        s->bl_count[max_length]--;
-        /* The brother of the overflow item also moves one step up,
-         * but this does not affect bl_count[max_length]
-         */
-        overflow -= 2;
-    } while (overflow > 0);
-
-    /* Now recompute all bit lengths, scanning in increasing frequency.
-     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-     * lengths instead of fixing only the wrong ones. This idea is taken
-     * from 'ar' written by Haruhiko Okumura.)
-     */
-    for (bits = max_length; bits != 0; bits--) {
-        n = s->bl_count[bits];
-        while (n != 0) {
-            m = s->heap[--h];
-            if (m > max_code) continue;
-            if (tree[m].Len != (unsigned) bits) {
-                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
-                s->opt_len += ((long)bits - (long)tree[m].Len)
-                              *(long)tree[m].Freq;
-                tree[m].Len = (ush)bits;
-            }
-            n--;
-        }
-    }
-}
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- *     zero code length.
- */
-local void gen_codes (tree, max_code, bl_count)
-    ct_data *tree;             /* the tree to decorate */
-    int max_code;              /* largest code with non zero frequency */
-    ushf *bl_count;            /* number of codes at each bit length */
-{
-    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
-    ush code = 0;              /* running code value */
-    int bits;                  /* bit index */
-    int n;                     /* code index */
-
-    /* The distribution counts are first used to generate the code values
-     * without bit reversal.
-     */
-    for (bits = 1; bits <= MAX_BITS; bits++) {
-        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
-    }
-    /* Check that the bit counts in bl_count are consistent. The last code
-     * must be all ones.
-     */
-    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
-            "inconsistent bit counts");
-    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
-
-    for (n = 0;  n <= max_code; n++) {
-        int len = tree[n].Len;
-        if (len == 0) continue;
-        /* Now reverse the bits */
-        tree[n].Code = bi_reverse(next_code[len]++, len);
-
-        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
-             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
-    }
-}
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- *     and corresponding code. The length opt_len is updated; static_len is
- *     also updated if stree is not null. The field max_code is set.
- */
-local void build_tree(s, desc)
-    deflate_state *s;
-    tree_desc *desc; /* the tree descriptor */
-{
-    ct_data *tree   = desc->dyn_tree;
-    ct_data *stree  = desc->stat_desc->static_tree;
-    int elems       = desc->stat_desc->elems;
-    int n, m;          /* iterate over heap elements */
-    int max_code = -1; /* largest code with non zero frequency */
-    int node;          /* new node being created */
-
-    /* Construct the initial heap, with least frequent element in
-     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-     * heap[0] is not used.
-     */
-    s->heap_len = 0, s->heap_max = HEAP_SIZE;
-
-    for (n = 0; n < elems; n++) {
-        if (tree[n].Freq != 0) {
-            s->heap[++(s->heap_len)] = max_code = n;
-            s->depth[n] = 0;
-        } else {
-            tree[n].Len = 0;
-        }
-    }
-
-    /* The pkzip format requires that at least one distance code exists,
-     * and that at least one bit should be sent even if there is only one
-     * possible code. So to avoid special checks later on we force at least
-     * two codes of non zero frequency.
-     */
-    while (s->heap_len < 2) {
-        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
-        tree[node].Freq = 1;
-        s->depth[node] = 0;
-        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
-        /* node is 0 or 1 so it does not have extra bits */
-    }
-    desc->max_code = max_code;
-
-    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-     * establish sub-heaps of increasing lengths:
-     */
-    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
-
-    /* Construct the Huffman tree by repeatedly combining the least two
-     * frequent nodes.
-     */
-    node = elems;              /* next internal node of the tree */
-    do {
-        pqremove(s, tree, n);  /* n = node of least frequency */
-        m = s->heap[SMALLEST]; /* m = node of next least frequency */
-
-        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
-        s->heap[--(s->heap_max)] = m;
-
-        /* Create a new node father of n and m */
-        tree[node].Freq = tree[n].Freq + tree[m].Freq;
-        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
-        tree[n].Dad = tree[m].Dad = (ush)node;
-#ifdef DUMP_BL_TREE
-        if (tree == s->bl_tree) {
-            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
-                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
-        }
-#endif
-        /* and insert the new node in the heap */
-        s->heap[SMALLEST] = node++;
-        pqdownheap(s, tree, SMALLEST);
-
-    } while (s->heap_len >= 2);
-
-    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
-
-    /* At this point, the fields freq and dad are set. We can now
-     * generate the bit lengths.
-     */
-    gen_bitlen(s, (tree_desc *)desc);
-
-    /* The field len is now set, we can generate the bit codes */
-    gen_codes ((ct_data *)tree, max_code, s->bl_count);
-}
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree.
- */
-local void scan_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree;   /* the tree to be scanned */
-    int max_code;    /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    if (nextlen == 0) max_count = 138, min_count = 3;
-    tree[max_code+1].Len = (ush)0xffff; /* guard */
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            s->bl_tree[curlen].Freq += count;
-        } else if (curlen != 0) {
-            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
-            s->bl_tree[REP_3_6].Freq++;
-        } else if (count <= 10) {
-            s->bl_tree[REPZ_3_10].Freq++;
-        } else {
-            s->bl_tree[REPZ_11_138].Freq++;
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-local void send_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree; /* the tree to be scanned */
-    int max_code;       /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    /* tree[max_code+1].Len = -1; */  /* guard already set */
-    if (nextlen == 0) max_count = 138, min_count = 3;
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
-
-        } else if (curlen != 0) {
-            if (curlen != prevlen) {
-                send_code(s, curlen, s->bl_tree); count--;
-            }
-            Assert(count >= 3 && count <= 6, " 3_6?");
-            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
-
-        } else if (count <= 10) {
-            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
-
-        } else {
-            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-local int build_bl_tree(s)
-    deflate_state *s;
-{
-    int max_blindex;  /* index of last bit length code of non zero freq */
-
-    /* Determine the bit length frequencies for literal and distance trees */
-    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
-    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
-
-    /* Build the bit length tree: */
-    build_tree(s, (tree_desc *)(&(s->bl_desc)));
-    /* opt_len now includes the length of the tree representations, except
-     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-     */
-
-    /* Determine the number of bit length codes to send. The pkzip format
-     * requires that at least 4 bit length codes be sent. (appnote.txt says
-     * 3 but the actual value used is 4.)
-     */
-    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
-        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
-    }
-    /* Update opt_len to include the bit length tree and counts */
-    s->opt_len += 3*(max_blindex+1) + 5+5+4;
-    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
-            s->opt_len, s->static_len));
-
-    return max_blindex;
-}
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-local void send_all_trees(s, lcodes, dcodes, blcodes)
-    deflate_state *s;
-    int lcodes, dcodes, blcodes; /* number of codes for each tree */
-{
-    int rank;                    /* index in bl_order */
-
-    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
-    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
-            "too many codes");
-    Tracev((stderr, "\nbl counts: "));
-    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
-    send_bits(s, dcodes-1,   5);
-    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
-    for (rank = 0; rank < blcodes; rank++) {
-        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
-        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
-    }
-    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
-    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
-    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
-}
-
-/* ===========================================================================
- * Send a stored block
- */
-void _tr_stored_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
-    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
-    s->compressed_len += (stored_len + 4) << 3;
-
-    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
-}
-
-/* Send just the `stored block' type code without any length bytes or data.
- */
-void _tr_stored_type_only(s)
-    deflate_state *s;
-{
-    send_bits(s, (STORED_BLOCK << 1), 3);
-    bi_windup(s);
-    s->compressed_len = (s->compressed_len + 3) & ~7L;
-}
-
-
-/* ===========================================================================
- * Send one empty static block to give enough lookahead for inflate.
- * This takes 10 bits, of which 7 may remain in the bit buffer.
- * The current inflate code requires 9 bits of lookahead. If the
- * last two codes for the previous block (real code plus EOB) were coded
- * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
- * the last real code. In this case we send two empty static blocks instead
- * of one. (There are no problems if the previous block is stored or fixed.)
- * To simplify the code, we assume the worst case of last real code encoded
- * on one bit only.
- */
-void _tr_align(s)
-    deflate_state *s;
-{
-    send_bits(s, STATIC_TREES<<1, 3);
-    send_code(s, END_BLOCK, static_ltree);
-    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
-    bi_flush(s);
-    /* Of the 10 bits for the empty block, we have already sent
-     * (10 - bi_valid) bits. The lookahead for the last real code (before
-     * the EOB of the previous block) was thus at least one plus the length
-     * of the EOB plus what we have just sent of the empty static block.
-     */
-    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
-        send_bits(s, STATIC_TREES<<1, 3);
-        send_code(s, END_BLOCK, static_ltree);
-        s->compressed_len += 10L;
-        bi_flush(s);
-    }
-    s->last_eob_len = 7;
-}
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and output the encoded block to the zip file. This function
- * returns the total compressed length for the file so far.
- */
-ulg _tr_flush_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block, or NULL if too old */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
-    int max_blindex = 0;  /* index of last bit length code of non zero freq */
-
-    /* Build the Huffman trees unless a stored block is forced */
-    if (s->level > 0) {
-
-	 /* Check if the file is ascii or binary */
-	if (s->data_type == Z_UNKNOWN) set_data_type(s);
-
-	/* Construct the literal and distance trees */
-	build_tree(s, (tree_desc *)(&(s->l_desc)));
-	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-
-	build_tree(s, (tree_desc *)(&(s->d_desc)));
-	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-	/* At this point, opt_len and static_len are the total bit lengths of
-	 * the compressed block data, excluding the tree representations.
-	 */
-
-	/* Build the bit length tree for the above two trees, and get the index
-	 * in bl_order of the last bit length code to send.
-	 */
-	max_blindex = build_bl_tree(s);
-
-	/* Determine the best encoding. Compute first the block length in bytes*/
-	opt_lenb = (s->opt_len+3+7)>>3;
-	static_lenb = (s->static_len+3+7)>>3;
-
-	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
-		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
-		s->last_lit));
-
-	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
-
-    } else {
-        Assert(buf != (char*)0, "lost buf");
-	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
-    }
-
-    /* If compression failed and this is the first and last block,
-     * and if the .zip file can be seeked (to rewrite the local header),
-     * the whole file is transformed into a stored file:
-     */
-#ifdef STORED_FILE_OK
-#  ifdef FORCE_STORED_FILE
-    if (eof && s->compressed_len == 0L) { /* force stored file */
-#  else
-    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
-#  endif
-        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
-        if (buf == (charf*)0) error ("block vanished");
-
-        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
-        s->compressed_len = stored_len << 3;
-        s->method = STORED;
-    } else
-#endif /* STORED_FILE_OK */
-
-#ifdef FORCE_STORED
-    if (buf != (char*)0) { /* force stored block */
-#else
-    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
-                       /* 4: two words for the lengths */
-#endif
-        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-         * Otherwise we can't have processed more than WSIZE input bytes since
-         * the last block flush, because compression would have been
-         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-         * transform a block into a stored block.
-         */
-        _tr_stored_block(s, buf, stored_len, eof);
-
-#ifdef FORCE_STATIC
-    } else if (static_lenb >= 0) { /* force static trees */
-#else
-    } else if (static_lenb == opt_lenb) {
-#endif
-        send_bits(s, (STATIC_TREES<<1)+eof, 3);
-        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
-        s->compressed_len += 3 + s->static_len;
-    } else {
-        send_bits(s, (DYN_TREES<<1)+eof, 3);
-        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
-                       max_blindex+1);
-        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
-        s->compressed_len += 3 + s->opt_len;
-    }
-    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
-    init_block(s);
-
-    if (eof) {
-        bi_windup(s);
-        s->compressed_len += 7;  /* align on byte boundary */
-    }
-    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
-           s->compressed_len-7*eof));
-
-    return s->compressed_len >> 3;
-}
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-int _tr_tally (s, dist, lc)
-    deflate_state *s;
-    unsigned dist;  /* distance of matched string */
-    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
-{
-    s->d_buf[s->last_lit] = (ush)dist;
-    s->l_buf[s->last_lit++] = (uch)lc;
-    if (dist == 0) {
-        /* lc is the unmatched char */
-        s->dyn_ltree[lc].Freq++;
-    } else {
-        s->matches++;
-        /* Here, lc is the match length - MIN_MATCH */
-        dist--;             /* dist = match distance - 1 */
-        Assert((ush)dist < (ush)MAX_DIST(s) &&
-               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
-               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
-
-        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
-        s->dyn_dtree[d_code(dist)].Freq++;
-    }
-
-    /* Try to guess if it is profitable to stop the current block here */
-    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
-        /* Compute an upper bound for the compressed length */
-        ulg out_length = (ulg)s->last_lit*8L;
-        ulg in_length = (ulg)((long)s->strstart - s->block_start);
-        int dcode;
-        for (dcode = 0; dcode < D_CODES; dcode++) {
-            out_length += (ulg)s->dyn_dtree[dcode].Freq *
-                (5L+extra_dbits[dcode]);
-        }
-        out_length >>= 3;
-        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
-               s->last_lit, in_length, out_length,
-               100L - out_length*100L/in_length));
-        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
-    }
-    return (s->last_lit == s->lit_bufsize-1);
-    /* We avoid equality with lit_bufsize because of wraparound at 64K
-     * on 16 bit machines and because stored blocks are restricted to
-     * 64K-1 bytes.
-     */
-}
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-local void compress_block(s, ltree, dtree)
-    deflate_state *s;
-    ct_data *ltree; /* literal tree */
-    ct_data *dtree; /* distance tree */
-{
-    unsigned dist;      /* distance of matched string */
-    int lc;             /* match length or unmatched char (if dist == 0) */
-    unsigned lx = 0;    /* running index in l_buf */
-    unsigned code;      /* the code to send */
-    int extra;          /* number of extra bits to send */
-
-    if (s->last_lit != 0) do {
-        dist = s->d_buf[lx];
-        lc = s->l_buf[lx++];
-        if (dist == 0) {
-            send_code(s, lc, ltree); /* send a literal byte */
-            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
-        } else {
-            /* Here, lc is the match length - MIN_MATCH */
-            code = length_code[lc];
-            send_code(s, code+LITERALS+1, ltree); /* send the length code */
-            extra = extra_lbits[code];
-            if (extra != 0) {
-                lc -= base_length[code];
-                send_bits(s, lc, extra);       /* send the extra length bits */
-            }
-            dist--; /* dist is now the match distance - 1 */
-            code = d_code(dist);
-            Assert (code < D_CODES, "bad d_code");
-
-            send_code(s, code, dtree);       /* send the distance code */
-            extra = extra_dbits[code];
-            if (extra != 0) {
-                dist -= base_dist[code];
-                send_bits(s, dist, extra);   /* send the extra distance bits */
-            }
-        } /* literal or match pair ? */
-
-        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
-        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
-
-    } while (lx < s->last_lit);
-
-    send_code(s, END_BLOCK, ltree);
-    s->last_eob_len = ltree[END_BLOCK].Len;
-}
-
-/* ===========================================================================
- * Set the data type to ASCII or BINARY, using a crude approximation:
- * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
- * IN assertion: the fields freq of dyn_ltree are set and the total of all
- * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
- */
-local void set_data_type(s)
-    deflate_state *s;
-{
-    int n = 0;
-    unsigned ascii_freq = 0;
-    unsigned bin_freq = 0;
-    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
-    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
-    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
-    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
-}
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-local unsigned bi_reverse(code, len)
-    unsigned code; /* the value to invert */
-    int len;       /* its bit length */
-{
-    register unsigned res = 0;
-    do {
-        res |= code & 1;
-        code >>= 1, res <<= 1;
-    } while (--len > 0);
-    return res >> 1;
-}
-
-/* ===========================================================================
- * Flush the bit buffer, keeping at most 7 bits in it.
- */
-local void bi_flush(s)
-    deflate_state *s;
-{
-    if (s->bi_valid == 16) {
-        put_short(s, s->bi_buf);
-        s->bi_buf = 0;
-        s->bi_valid = 0;
-    } else if (s->bi_valid >= 8) {
-        put_byte(s, (Byte)s->bi_buf);
-        s->bi_buf >>= 8;
-        s->bi_valid -= 8;
-    }
-}
-
-/* ===========================================================================
- * Flush the bit buffer and align the output on a byte boundary
- */
-local void bi_windup(s)
-    deflate_state *s;
-{
-    if (s->bi_valid > 8) {
-        put_short(s, s->bi_buf);
-    } else if (s->bi_valid > 0) {
-        put_byte(s, (Byte)s->bi_buf);
-    }
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-#ifdef DEBUG_ZLIB
-    s->bits_sent = (s->bits_sent+7) & ~7;
-#endif
-}
-
-/* ===========================================================================
- * Copy a stored block, storing first the length and its
- * one's complement if requested.
- */
-local void copy_block(s, buf, len, header)
-    deflate_state *s;
-    charf    *buf;    /* the input data */
-    unsigned len;     /* its length */
-    int      header;  /* true if block header must be written */
-{
-    bi_windup(s);        /* align on byte boundary */
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-
-    if (header) {
-        put_short(s, (ush)len);   
-        put_short(s, (ush)~len);
-#ifdef DEBUG_ZLIB
-        s->bits_sent += 2*16;
-#endif
-    }
-#ifdef DEBUG_ZLIB
-    s->bits_sent += (ulg)len<<3;
-#endif
-    /* bundle up the put_byte(s, *buf++) calls */
-    zmemcpy(&s->pending_buf[s->pending], buf, len);
-    s->pending += len;
-}
-/* --- trees.c */
-
-/* +++ inflate.c */
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-
-/* +++ infblock.h */
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1996 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;
-
-extern inflate_blocks_statef * inflate_blocks_new OF((
-    z_streamp z,
-    check_func c,               /* check function */
-    uInt w));                   /* window size */
-
-extern int inflate_blocks OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));                      /* initial return code */
-
-extern void inflate_blocks_reset OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern int inflate_blocks_free OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern void inflate_set_dictionary OF((
-    inflate_blocks_statef *s,
-    const Bytef *d,  /* dictionary */
-    uInt  n));       /* dictionary length */
-
-extern int inflate_addhistory OF((
-    inflate_blocks_statef *,
-    z_streamp));
-
-extern int inflate_packet_flush OF((
-    inflate_blocks_statef *));
-/* --- infblock.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* inflate private state */
-struct internal_state {
-
-  /* mode */
-  enum {
-      METHOD,   /* waiting for method byte */
-      FLAG,     /* waiting for flag byte */
-      DICT4,    /* four dictionary check bytes to go */
-      DICT3,    /* three dictionary check bytes to go */
-      DICT2,    /* two dictionary check bytes to go */
-      DICT1,    /* one dictionary check byte to go */
-      DICT0,    /* waiting for inflateSetDictionary */
-      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_streamp 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_streamp 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);
-  z->state = Z_NULL;
-  Trace((stderr, "inflate: end\n"));
-  return Z_OK;
-}
-
-
-int inflateInit2_(z, w, version, stream_size)
-z_streamp z;
-int w;
-const char *version;
-int stream_size;
-{
-  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-      stream_size != sizeof(z_stream))
-      return Z_VERSION_ERROR;
-
-  /* initialize state */
-  if (z == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-  if (z->zalloc == Z_NULL)
-  {
-    z->zalloc = zcalloc;
-    z->opaque = (voidpf)0;
-  }
-  if (z->zfree == Z_NULL) z->zfree = zcfree;
-#endif
-  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, (uInt)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, version, stream_size)
-z_streamp z;
-const char *version;
-int stream_size;
-{
-  return inflateInit2_(z, DEF_WBITS, version, stream_size);
-}
-
-
-#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_streamp z;
-int f;
-{
-  int r;
-  uInt b;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
-    return Z_STREAM_ERROR;
-  r = Z_BUF_ERROR;
-  while (1) switch (z->state->mode)
-  {
-    case METHOD:
-      NEEDBYTE
-      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"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 = (char*)"invalid window size";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = FLAG;
-    case FLAG:
-      NEEDBYTE
-      b = NEXTBYTE;
-      if (((z->state->sub.method << 8) + b) % 31)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect header check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib header ok\n"));
-      if (!(b & PRESET_DICT))
-      {
-        z->state->mode = BLOCKS;
-	break;
-      }
-      z->state->mode = DICT4;
-    case DICT4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = DICT3;
-    case DICT3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = DICT2;
-    case DICT2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = DICT1;
-    case DICT1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-      z->adler = z->state->sub.check.need;
-      z->state->mode = DICT0;
-      return Z_NEED_DICT;
-    case DICT0:
-      z->state->mode = BAD;
-      z->msg = (char*)"need dictionary";
-      z->state->sub.marker = 0;       /* can try inflateSync */
-      return Z_STREAM_ERROR;
-    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 = (char*)"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->msg = (char *)"need more for packet flush";
-  z->state->sub.marker = 0;       /* can try inflateSync */
-  return Z_DATA_ERROR;
-}
-
-
-int inflateSetDictionary(z, dictionary, dictLength)
-z_streamp z;
-const Bytef *dictionary;
-uInt  dictLength;
-{
-  uInt length = dictLength;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
-    return Z_STREAM_ERROR;
-
-  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
-  z->adler = 1L;
-
-  if (length >= ((uInt)1<<z->state->wbits))
-  {
-    length = (1<<z->state->wbits)-1;
-    dictionary += dictLength - length;
-  }
-  inflate_set_dictionary(z->state->blocks, dictionary, length);
-  z->state->mode = BLOCKS;
-  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.
- */
-
-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_streamp 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
-/* --- inflate.c */
-
-/* +++ infblock.c */
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-
-/* +++ inftrees.h */
-/* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1996 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;
-    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
-  extern uInt inflate_hufts;
-#endif
-
-extern int inflate_trees_bits OF((
-    uIntf *,                    /* 19 code lengths */
-    uIntf *,                    /* bits tree desired/actual depth */
-    inflate_huft * FAR *,       /* bits tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern 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_streamp ));               /* for zalloc, zfree functions */
-
-extern 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 */
-
-extern int inflate_trees_free OF((
-    inflate_huft *,             /* tables to free */
-    z_streamp ));               /* for zfree function */
-
-/* --- inftrees.h */
-
-/* +++ infcodes.h */
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1996 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;
-
-extern inflate_codes_statef *inflate_codes_new OF((
-    uInt, uInt,
-    inflate_huft *, inflate_huft *,
-    z_streamp ));
-
-extern int inflate_codes OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-extern void inflate_codes_free OF((
-    inflate_codes_statef *,
-    z_streamp ));
-
-/* --- infcodes.h */
-
-/* +++ infutil.h */
-/* infutil.h -- types and macros common to blocks and codes
- * Copyright (C) 1995-1996 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.
- */
-
-#ifndef _INFUTIL_H
-#define _INFUTIL_H
-
-typedef 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 */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
-  /* mode */
-  inflate_block_mode  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 */
-    } trees;            /* if DTREE, decoding info for trees */
-    struct {
-      inflate_huft *tl;
-      inflate_huft *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 (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
-#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
-#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-/*   load local pointers */
-#define LOAD {LOADIN LOADOUT}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int inflate_flush OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#endif
-/* --- infutil.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* Table for deflate from PKZIP's appnote.txt. */
-local const 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.
- */
-
-
-void inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  if (s->checkfn != Z_NULL)
-    *c = s->check;
-  if (s->mode == BTREE || s->mode == DTREE)
-    ZFREE(z, s->sub.trees.blens);
-  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)
-    z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
-  Trace((stderr, "inflate:   blocks reset\n"));
-}
-
-
-inflate_blocks_statef *inflate_blocks_new(z, c, w)
-z_streamp 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);
-    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;
-}
-
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-int inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_streamp 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 = (char*)"invalid block type";
-          r = Z_DATA_ERROR;
-          LEAVE
-      }
-      break;
-    case LENS:
-      NEEDBITS(32)
-      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-      {
-        s->mode = BADB;
-        z->msg = (char*)"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 : (s->last ? DRY : 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 = (char*)"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
-      }
-      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)
-	{
-	  ZFREE(z, s->sub.trees.blens);
-          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))
-          {
-            inflate_trees_free(s->sub.trees.tb, z);
-            ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-            z->msg = (char*)"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;
-#ifdef DEBUG_ZLIB
-      inflate_hufts = 0;
-#endif
-        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)
-	  {
-	    ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-	  }
-          r = t;
-          LEAVE
-        }
-        Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
-              inflate_hufts, sizeof(inflate_huft)));
-        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.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
-  }
-}
-
-
-int inflate_blocks_free(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  inflate_blocks_reset(s, z, c);
-  ZFREE(z, s->window);
-  ZFREE(z, s);
-  Trace((stderr, "inflate:   blocks freed\n"));
-  return Z_OK;
-}
-
-
-void inflate_set_dictionary(s, d, n)
-inflate_blocks_statef *s;
-const Bytef *d;
-uInt  n;
-{
-  zmemcpy((charf *)s->window, d, n);
-  s->read = s->write = s->window + n;
-}
-
-/*
- * 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 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 */
-/*      WWRAP  */ 	/* expand WWRAP 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.
- */
-int inflate_packet_flush(s)
-    inflate_blocks_statef *s;
-{
-    if (s->mode != LENS)
-	return Z_DATA_ERROR;
-    s->mode = TYPE;
-    return Z_OK;
-}
-/* --- infblock.c */
-
-/* +++ inftrees.c */
-/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-
-char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state  {int dummy;}; /* for buggy compilers */
-#endif
-
-/* 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 */
-    const uIntf *,      /* list of base values for non-simple codes */
-    const uIntf *,      /* list of extra bits for non-simple codes */
-    inflate_huft * FAR*,/* result: starting table */
-    uIntf *,            /* maximum lookup bits (returns actual) */
-    z_streamp ));       /* for zalloc function */
-
-local voidpf falloc OF((
-    voidpf,             /* opaque pointer (not used) */
-    uInt,               /* number of items */
-    uInt));             /* size of item */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-local const uInt cplens[31] = { /* 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};
-        /* see note #13 above about 258 */
-local const uInt cplext[31] = { /* 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, 112, 112}; /* 112==invalid */
-local const uInt cpdist[30] = { /* 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 const uInt cpdext[30] = { /* 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) */
-const uIntf *d;         /* list of base values for non-simple codes */
-const 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_streamp 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 (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);
-  n = x[g];                   /* set n to length of v */
-
-
-  /* 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 = g - w;
-        z = z > (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 */
-        }
-#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;
-}
-
-
-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_streamp 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 = (char*)"oversubscribed dynamic bit lengths tree";
-  else if (r == Z_BUF_ERROR || *bb == 0)
-  {
-    inflate_trees_free(*tb, z);
-    z->msg = (char*)"incomplete dynamic bit lengths tree";
-    r = Z_DATA_ERROR;
-  }
-  return r;
-}
-
-
-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_streamp z;            /* for zfree function */
-{
-  int r;
-
-  /* build literal/length tree */
-  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
-  if (r != Z_OK || *bl == 0)
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed literal/length tree";
-    else if (r != Z_MEM_ERROR)
-    {
-      inflate_trees_free(*tl, z);
-      z->msg = (char*)"incomplete literal/length tree";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-  }
-
-  /* build distance tree */
-  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
-  if (r != Z_OK || (*bd == 0 && nl > 257))
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed distance tree";
-    else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
-      r = Z_OK;
-    }
-#else
-      inflate_trees_free(*td, z);
-      z->msg = (char*)"incomplete distance tree";
-      r = Z_DATA_ERROR;
-    }
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"empty distance tree with lengths";
-      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_built = 0;
-#define FIXEDH 530      /* number of hufts used by fixed tables */
-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 */
-uInt n;         /* number of items */
-uInt s;         /* size of item */
-{
-  Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
-         "inflate_trees falloc overflow");
-  *(intf *)q -= n+s-s; /* s-s to avoid warning */
-  return (voidpf)(fixed_mem + *(intf *)q);
-}
-
-
-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 already (multiple overlapped executions ok) */
-  if (!fixed_built)
-  {
-    int k;              /* temporary variable */
-    unsigned c[288];    /* length list for huft_build */
-    z_stream z;         /* for falloc function */
-    int f = FIXEDH;     /* number of hufts left in fixed_mem */
-
-    /* set up fake z_stream for memory routines */
-    z.zalloc = falloc;
-    z.zfree = Z_NULL;
-    z.opaque = (voidpf)&f;
-
-    /* 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 */
-    Assert(f == 0, "invalid build of fixed tables");
-    fixed_built = 1;
-  }
-  *bl = fixed_bl;
-  *bd = fixed_bd;
-  *tl = fixed_tl;
-  *td = fixed_td;
-  return Z_OK;
-}
-
-
-int inflate_trees_free(t, z)
-inflate_huft *t;        /* table to free */
-z_streamp 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, *r;
-
-  /* Reverse linked list */
-  p = Z_NULL;
-  q = t;
-  while (q != Z_NULL)
-  {
-    r = (q - 1)->next;
-    (q - 1)->next = p;
-    p = q;
-    q = r;
-  }
-  /* Go through linked list, freeing from the malloced (t[-1]) address. */
-  while (p != Z_NULL)
-  {
-    q = (--p)->next;
-    ZFREE(z,p);
-    p = q;
-  } 
-  return Z_OK;
-}
-/* --- inftrees.c */
-
-/* +++ infcodes.c */
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-/* +++ inffast.h */
-/* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1996 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.
- */
-
-extern int inflate_fast OF((
-    uInt,
-    uInt,
-    inflate_huft *,
-    inflate_huft *,
-    inflate_blocks_statef *,
-    z_streamp ));
-/* --- inffast.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 */
-
-};
-
-
-inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-z_streamp 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;
-}
-
-
-int inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_streamp 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 = (char*)"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 = (char*)"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 - (uInt)(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
-  }
-}
-
-
-void inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_streamp z;
-{
-  ZFREE(z, c);
-  Tracev((stderr, "inflate:       codes free\n"));
-}
-/* --- infcodes.c */
-
-/* +++ infutil.c */
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-/* #include "inftrees.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt inflate_mask[17] = {
-    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 */
-int inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt n;
-  Bytef *p;
-  Bytef *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)
-    z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-  /* copy as far as end of window */
-  if (p != Z_NULL) {
-    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)
-      z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-    /* copy */
-    if (p != Z_NULL) {
-      zmemcpy(p, q, n);
-      p += n;
-    }
-    q += n;
-  }
-
-  /* update pointers */
-  z->next_out = p;
-  s->read = q;
-
-  /* done */
-  return r;
-}
-/* --- infutil.c */
-
-/* +++ inffast.c */
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-/* #include "inffast.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* 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. */
-
-int inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-inflate_blocks_statef *s;
-z_streamp 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 - (uInt)(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 = (char*)"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 = (char*)"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;
-}
-/* --- inffast.c */
-
-/* +++ zutil.c */
-/* zutil.c -- target dependent utility functions for the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
-
-/* #include "zutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#ifndef STDC
-extern void exit OF((int));
-#endif
-
-const char *z_errmsg[10] = {
-"need dictionary",     /* Z_NEED_DICT       2  */
-"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) */
-"incompatible version",/* Z_VERSION_ERROR (-6) */
-""};
-
-
-const char *zlibVersion()
-{
-    return ZLIB_VERSION;
-}
-
-#ifdef DEBUG_ZLIB
-void z_error (m)
-    char *m;
-{
-    fprintf(stderr, "%s\n", m);
-    exit(1);
-}
-#endif
-
-#ifndef HAVE_MEMCPY
-
-void zmemcpy(dest, source, len)
-    Bytef* dest;
-    Bytef* source;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = *source++; /* ??? to be unrolled */
-    } while (--len != 0);
-}
-
-int zmemcmp(s1, s2, len)
-    Bytef* s1;
-    Bytef* s2;
-    uInt  len;
-{
-    uInt j;
-
-    for (j = 0; j < len; j++) {
-        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
-    }
-    return 0;
-}
-
-void zmemzero(dest, len)
-    Bytef* dest;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = 0;  /* ??? to be unrolled */
-    } while (--len != 0);
-}
-#endif
-
-#ifdef __TURBOC__
-#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
-/* Small and medium model in Turbo C are for now limited to near allocation
- * with reduced MAX_WBITS and MAX_MEM_LEVEL
- */
-#  define MY_ZCALLOC
-
-/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
- * and farmalloc(64K) returns a pointer with an offset of 8, so we
- * must fix the pointer. Warning: the pointer must be put back to its
- * original form in order to free it, use zcfree().
- */
-
-#define MAX_PTR 10
-/* 10*64K = 640K */
-
-local int next_ptr = 0;
-
-typedef struct ptr_table_s {
-    voidpf org_ptr;
-    voidpf new_ptr;
-} ptr_table;
-
-local ptr_table table[MAX_PTR];
-/* This table is used to remember the original form of pointers
- * to large buffers (64K). Such pointers are normalized with a zero offset.
- * Since MSDOS is not a preemptive multitasking OS, this table is not
- * protected from concurrent access. This hack doesn't work anyway on
- * a protected system like OS/2. Use Microsoft C instead.
- */
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    voidpf buf = opaque; /* just to make some compilers happy */
-    ulg bsize = (ulg)items*size;
-
-    /* If we allocate less than 65520 bytes, we assume that farmalloc
-     * will return a usable pointer which doesn't have to be normalized.
-     */
-    if (bsize < 65520L) {
-        buf = farmalloc(bsize);
-        if (*(ush*)&buf != 0) return buf;
-    } else {
-        buf = farmalloc(bsize + 16L);
-    }
-    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
-    table[next_ptr].org_ptr = buf;
-
-    /* Normalize the pointer to seg:0 */
-    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
-    *(ush*)&buf = 0;
-    table[next_ptr++].new_ptr = buf;
-    return buf;
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    int n;
-    if (*(ush*)&ptr != 0) { /* object < 64K */
-        farfree(ptr);
-        return;
-    }
-    /* Find the original pointer */
-    for (n = 0; n < next_ptr; n++) {
-        if (ptr != table[n].new_ptr) continue;
-
-        farfree(table[n].org_ptr);
-        while (++n < next_ptr) {
-            table[n-1] = table[n];
-        }
-        next_ptr--;
-        return;
-    }
-    ptr = opaque; /* just to make some compilers happy */
-    Assert(0, "zcfree: ptr not found");
-}
-#endif
-#endif /* __TURBOC__ */
-
-
-#if defined(M_I86) && !defined(__32BIT__)
-/* Microsoft C in 16-bit mode */
-
-#  define MY_ZCALLOC
-
-#if (!defined(_MSC_VER) || (_MSC_VER < 600))
-#  define _halloc  halloc
-#  define _hfree   hfree
-#endif
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    return _halloc((long)items, size);
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    _hfree(ptr);
-}
-
-#endif /* MSC */
-
-
-#ifndef MY_ZCALLOC /* Any system without a special alloc function */
-
-#ifndef STDC
-extern voidp  calloc OF((uInt items, uInt size));
-extern void   free   OF((voidpf ptr));
-#endif
-
-voidpf zcalloc (opaque, items, size)
-    voidpf opaque;
-    unsigned items;
-    unsigned size;
-{
-    if (opaque) items += size - size; /* make compiler happy */
-    return (voidpf)calloc(items, size);
-}
-
-void  zcfree (opaque, ptr)
-    voidpf opaque;
-    voidpf ptr;
-{
-    free(ptr);
-    if (opaque) return; /* make compiler happy */
-}
-
-#endif /* MY_ZCALLOC */
-/* --- zutil.c */
-
-/* +++ adler32.c */
-/* adler32.c -- compute the Adler-32 checksum of a data stream
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
-
-/* #include "zlib.h" */
-
-#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,i)  {s1 += buf[i]; s2 += s1;}
-#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf)   DO8(buf,0); DO8(buf,8);
-
-/* ========================================================================= */
-uLong adler32(adler, buf, len)
-    uLong adler;
-    const 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);
-	    buf += 16;
-            k -= 16;
-        }
-        if (k != 0) do {
-            s1 += *buf++;
-	    s2 += s1;
-        } while (--k);
-        s1 %= BASE;
-        s2 %= BASE;
-    }
-    return (s2 << 16) | s1;
-}
-/* --- adler32.c */
diff -urN linux-2.4.20-pre1/drivers/net/zlib.h linux-2.4.20-pre2/drivers/net/zlib.h
--- linux-2.4.20-pre1/drivers/net/zlib.h	Tue Dec 23 10:57:31 1997
+++ linux-2.4.20-pre2/drivers/net/zlib.h	Wed Dec 31 16:00:00 1969
@@ -1,1010 +0,0 @@
-/*	$Id: zlib.h,v 1.2 1997/12/23 10:47:44 paulus Exp $	*/
-
-/*
- * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
- * 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 971127==
- *
- * 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 */
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.0.4, Jul 24th, 1996.
-
-  Copyright (C) 1995-1996 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
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef _ZLIB_H
-#define _ZLIB_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* +++ zconf.h */
-/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
-
-#ifndef _ZCONF_H
-#define _ZCONF_H
-
-/*
- * If you *really* need a unique prefix for all types and library functions,
- * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
- */
-#ifdef Z_PREFIX
-#  define deflateInit_	z_deflateInit_
-#  define deflate	z_deflate
-#  define deflateEnd	z_deflateEnd
-#  define inflateInit_ 	z_inflateInit_
-#  define inflate	z_inflate
-#  define inflateEnd	z_inflateEnd
-#  define deflateInit2_	z_deflateInit2_
-#  define deflateSetDictionary z_deflateSetDictionary
-#  define deflateCopy	z_deflateCopy
-#  define deflateReset	z_deflateReset
-#  define deflateParams	z_deflateParams
-#  define inflateInit2_	z_inflateInit2_
-#  define inflateSetDictionary z_inflateSetDictionary
-#  define inflateSync	z_inflateSync
-#  define inflateReset	z_inflateReset
-#  define compress	z_compress
-#  define uncompress	z_uncompress
-#  define adler32	z_adler32
-#  define crc32		z_crc32
-#  define get_crc_table z_get_crc_table
-
-#  define Byte		z_Byte
-#  define uInt		z_uInt
-#  define uLong		z_uLong
-#  define Bytef	        z_Bytef
-#  define charf		z_charf
-#  define intf		z_intf
-#  define uIntf		z_uIntf
-#  define uLongf	z_uLongf
-#  define voidpf	z_voidpf
-#  define voidp		z_voidp
-#endif
-
-#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
-#  define WIN32
-#endif
-#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
-#  ifndef __32BIT__
-#    define __32BIT__
-#  endif
-#endif
-#if defined(__MSDOS__) && !defined(MSDOS)
-#  define MSDOS
-#endif
-
-/*
- * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
- * than 64k bytes at a time (needed on systems with 16-bit int).
- */
-#if defined(MSDOS) && !defined(__32BIT__)
-#  define MAXSEG_64K
-#endif
-#ifdef MSDOS
-#  define UNALIGNED_OK
-#endif
-
-#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
-#  define STDC
-#endif
-#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
-#  define STDC
-#endif
-
-#ifndef STDC
-#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
-#    define const
-#  endif
-#endif
-
-/* Some Mac compilers merge all .h files incorrectly: */
-#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
-#  define NO_DUMMY_DECL
-#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
-
-/* 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
-
-/* The following definitions for FAR are needed only for MSDOS mixed
- * model programming (small or medium model with some far allocations).
- * This was tested only with MSC; for other MSDOS compilers you may have
- * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
- * just define FAR to be empty.
- */
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
-   /* MSC small or medium model */
-#  define SMALL_MEDIUM
-#  ifdef _MSC_VER
-#    define FAR __far
-#  else
-#    define FAR far
-#  endif
-#endif
-#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
-#  ifndef __32BIT__
-#    define SMALL_MEDIUM
-#    define FAR __far
-#  endif
-#endif
-#ifndef FAR
-#   define FAR
-#endif
-
-typedef unsigned char  Byte;  /* 8 bits */
-typedef unsigned int   uInt;  /* 16 bits or more */
-typedef unsigned long  uLong; /* 32 bits or more */
-
-#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
-   /* Borland C/C++ ignores FAR inside typedef */
-#  define Bytef Byte FAR
-#else
-   typedef Byte  FAR Bytef;
-#endif
-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
-
-
-/* Compile with -DZLIB_DLL for Windows DLL support */
-#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
-#  include <windows.h>
-#  define EXPORT  WINAPI
-#else
-#  define EXPORT
-#endif
-
-#endif /* _ZCONF_H */
-/* --- zconf.h */
-
-#define ZLIB_VERSION "1.0.4P"
-
-/* 
-     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.
-
-     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.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-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 */
-    voidpf     opaque;  /* private data object passed to zalloc and zfree */
-
-    int     data_type;  /* best guess about the data type: ascii or binary */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-   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_PACKET_FLUSH	2
-#define Z_SYNC_FLUSH    3
-#define Z_FULL_FLUSH    4
-#define Z_FINISH        5
-/* Allowed flush values; see deflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#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
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_ASCII    1
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-#define zlib_version zlibVersion()
-/* for compatibility with versions < 1.0.2 */
-
-                        /* basic functions */
-
-extern const char * EXPORT zlibVersion OF((void));
-/* The application can compare zlibVersion 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.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/* 
-extern int EXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-extern int EXPORT deflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Compress 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 and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
-  block is terminated and flushed to the output buffer so that the
-  decompressor can get all input data available so far. For method 9, a future
-  variant on method 8, the current block will be flushed but not terminated.
-  Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
-  output is byte aligned (the compressor can clear its internal bit buffer)
-  and the current block is always terminated; this can be useful if the
-  compressor has to be restarted from scratch after an interruption (in which
-  case the internal state of the compressor may be lost).
-    If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
-  special marker is output and the compression dictionary is discarded; this
-  is useful to allow the decompressor to synchronize if one compressed block
-  has been damaged (see inflateSync below).  Flushing degrades compression and
-  so should be used only when necessary.  Using Z_FULL_FLUSH too often can
-  seriously degrade the compression. If deflate returns with avail_out == 0,
-  this function must be called again with the same value of the flush
-  parameter and more output space (updated avail_out), until the flush is
-  complete (deflate returns with non-zero avail_out).
-
-    If the parameter flush is set to Z_PACKET_FLUSH, the compression
-  block is terminated, and a zero-length stored block is output,
-  omitting the length bytes (the effect of this is that the 3-bit type
-  code 000 for a stored block is output, and the output is then
-  byte-aligned).  This is designed for use at the end of a PPP packet.
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-  
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() may update data_type if it can make a good guess about
-  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
-*/
-
-
-extern int EXPORT deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-/* 
-extern int EXPORT inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   zalloc, zfree and opaque 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, Z_VERSION_ERROR if the zlib library version is incompatible
-   with the version assumed by the caller.  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 EXPORT inflate OF((z_streamp 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() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  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 inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    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_NEED_DICT if a preset dictionary is needed at this point (see
-  inflateSetDictionary below), 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.
-  In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
-  dictionary chosen by the compressor.
-*/
-
-
-extern int EXPORT inflateEnd OF((z_streamp 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 */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*   
-extern int EXPORT deflateInit2 OF((z_streamp strm,
-                                   int  level,
-                                   int  method,
-                                   int  windowBits,
-                                   int  memLevel,
-                                   int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library. (Method 9 will allow a 64K history buffer and
-   partial block flushes.)
-
-     The windowBits parameter is the base two logarithm of the 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 for method 9). Larger
-   values of this parameter result in better compression at the expense of
-   memory usage. The default value is 15 if deflateInit is used instead.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match).  Filtered data consists mostly of small values with a
-   somewhat random distribution. In this case, the compression algorithm is
-   tuned to compress them better. The effect of Z_FILTERED is to force more
-   Huffman coding and less string matching; it is somewhat intermediate
-   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-   the compression ratio but not the correctness of the compressed output even
-   if it is not set appropriately.
-
-     If next_in is not null, the library will use this buffer to hold also
-   some history information; the buffer must either hold the entire input
-   data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
-   is null, the library will allocate its own history buffer (and leave next_in
-   null). next_out need not be provided here but must be provided by the
-   application for the next call of deflate().
-
-     If the history buffer is provided by the application, next_in must
-   must never be changed by the application since the compressor maintains
-   information inside this buffer from call to call; the application
-   must provide more input only by increasing avail_in. next_in is always
-   reset by the library in this case.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   an invalid method). msg is set to null if there is no error message.
-   deflateInit2 does not perform any compression: this will be done by
-   deflate(). 
-*/
-                            
-extern int EXPORT deflateSetDictionary OF((z_streamp strm,
-                                           const Bytef *dictionary,
-				           uInt  dictLength));
-/*
-     Initializes the compression dictionary (history buffer) from the given
-   byte sequence without producing any compressed output. This function must
-   be called immediately after deflateInit or deflateInit2, before any call
-   of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and
-   can be predicted with good accuracy; the data can then be compressed better
-   than with the default empty dictionary. In this version of the library,
-   only the last 32K bytes of the dictionary are used.
-     Upon return of this function, strm->adler is set to the Adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The Adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.)
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state
-   is inconsistent (for example if deflate has already been called for this
-   stream). deflateSetDictionary does not perform any compression: this will
-   be done by deflate(). 
-*/
-
-extern int EXPORT deflateCopy OF((z_streamp dest,
-                                  z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.  If
-   the source stream is using an application-supplied history buffer, a new
-   buffer is allocated for the destination stream.  The compressed output
-   buffer is always application-supplied. It's the responsibility of the
-   application to provide the correct values of next_out and avail_out for the
-   next call of deflate.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-extern int EXPORT deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset 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 EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
-/*
-     Dynamically update the compression level and compression strategy.
-   This can be used to switch between compression and straight copy of
-   the input data, or to switch to a different kind of input data requiring
-   a different strategy. If the compression level is changed, the input
-   available so far is compressed with the old level (and may be flushed);
-   the new level will take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-extern int EXPORT deflateOutputPending OF((z_streamp strm));
-/*
-     Returns the number of bytes of output which are immediately
-   available from the compressor (i.e. without any further input
-   or flush).
-*/
-
-/*   
-extern int EXPORT inflateInit2 OF((z_streamp strm,
-                                   int  windowBits));
-
-     This is another version of inflateInit with more compression options. The
-   fields next_out, zalloc, zfree and opaque 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 EXPORT inflateSetDictionary OF((z_streamp strm,
-				           const Bytef *dictionary,
-					   uInt  dictLength));
-/*
-     Initializes the decompression dictionary (history buffer) from the given
-   uncompressed byte sequence. This function must be called immediately after
-   a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
-   by the compressor can be determined from the Adler32 value returned by this
-   call of inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-extern int EXPORT inflateSync OF((z_streamp 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 EXPORT inflateReset OF((z_streamp 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).
-*/
-
-                        /* utility functions */
-
-/*
-     The following utility functions are implemented on top of the
-   basic stream-oriented functions. To simplify the interface, some
-   default options are assumed (compression level, window size,
-   standard memory allocation functions). The source code of these
-   utility functions can easily be modified if you need special options.
-*/
-
-extern int EXPORT compress OF((Bytef *dest,   uLongf *destLen,
-			       const Bytef *source, uLong sourceLen));
-/*
-     Compresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be at least 0.1% larger than
-   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
-   compressed buffer.
-     This function can be used to compress a whole file at once if the
-   input file is mmap'ed.
-     compress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer.
-*/
-
-extern int EXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
-				 const Bytef *source, uLong sourceLen));
-/*
-     Decompresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be large enough to hold the
-   entire uncompressed data. (The size of the uncompressed data must have
-   been saved previously by the compressor and transmitted to the decompressor
-   by some mechanism outside the scope of this compression library.)
-   Upon exit, destLen is the actual size of the compressed buffer.
-     This function can be used to decompress a whole file at once if the
-   input file is mmap'ed.
-
-     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer, or Z_DATA_ERROR if the input data was corrupted.
-*/
-
-
-typedef voidp gzFile;
-
-extern gzFile EXPORT gzopen  OF((const char *path, const char *mode));
-/*
-     Opens a gzip (.gz) file for reading or writing. The mode parameter
-   is as in fopen ("rb" or "wb") but can also include a compression level
-   ("wb9").  gzopen can be used to read a file which is not in gzip format;
-   in this case gzread will directly read from the file without decompression.
-     gzopen returns NULL if the file could not be opened or if there was
-   insufficient memory to allocate the (de)compression state; errno
-   can be checked to distinguish the two cases (if errno is zero, the
-   zlib error is Z_MEM_ERROR).
-*/
-
-extern gzFile EXPORT gzdopen  OF((int fd, const char *mode));
-/*
-     gzdopen() associates a gzFile with the file descriptor fd.  File
-   descriptors are obtained from calls like open, dup, creat, pipe or
-   fileno (in the file has been previously opened with fopen).
-   The mode parameter is as in gzopen.
-     The next call of gzclose on the returned gzFile will also close the
-   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
-   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
-     gzdopen returns NULL if there was insufficient memory to allocate
-   the (de)compression state.
-*/
-
-extern int EXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
-/*
-     Reads the given number of uncompressed bytes from the compressed file.
-   If the input file was not in gzip format, gzread copies the given number
-   of bytes into the buffer.
-     gzread returns the number of uncompressed bytes actually read (0 for
-   end of file, -1 for error). */
-
-extern int EXPORT    gzwrite OF((gzFile file, const voidp buf, unsigned len));
-/*
-     Writes the given number of uncompressed bytes into the compressed file.
-   gzwrite returns the number of uncompressed bytes actually written
-   (0 in case of error).
-*/
-
-extern int EXPORT    gzflush OF((gzFile file, int flush));
-/*
-     Flushes all pending output into the compressed file. The parameter
-   flush is as in the deflate() function. The return value is the zlib
-   error number (see function gzerror below). gzflush returns Z_OK if
-   the flush parameter is Z_FINISH and all output could be flushed.
-     gzflush should be called only when strictly necessary because it can
-   degrade compression.
-*/
-
-extern int EXPORT    gzclose OF((gzFile file));
-/*
-     Flushes all pending output if necessary, closes the compressed file
-   and deallocates all the (de)compression state. The return value is the zlib
-   error number (see function gzerror below).
-*/
-
-extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
-/*
-     Returns the error message for the last error which occurred on the
-   given compressed file. errnum is set to zlib error number. If an
-   error occurred in the file system and not in the compression library,
-   errnum is set to Z_ERRNO and the application may consult errno
-   to get the exact error code.
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-extern uLong EXPORT adler32 OF((uLong adler, const 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();
-*/
-
-extern uLong EXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running crc with the bytes buf[0..len-1] and return the updated
-   crc. If buf is NULL, this function returns the required initial value
-   for the crc. Pre- and post-conditioning (one's complement) is performed
-   within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
-			           const char *version, int stream_size));
-extern int EXPORT inflateInit_ OF((z_streamp strm,
-				   const char *version, int stream_size));
-extern int EXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
-				    int windowBits, int memLevel, int strategy,
-				    const char *version, int stream_size));
-extern int EXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
-				    const char *version, int stream_size));
-#define deflateInit(strm, level) \
-        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit(strm) \
-        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
-#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-		      (strategy),           ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit2(strm, windowBits) \
-        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-
-#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZLIB_H */
-/* --- zlib.h */
diff -urN linux-2.4.20-pre1/drivers/s390/char/hwc.h linux-2.4.20-pre2/drivers/s390/char/hwc.h
--- linux-2.4.20-pre1/drivers/s390/char/hwc.h	Wed Jul 25 14:12:02 2001
+++ linux-2.4.20-pre2/drivers/s390/char/hwc.h	Mon Aug 12 16:34:16 2002
@@ -22,6 +22,7 @@
 #define ET_PMsgCmd		0x09
 #define ET_CntlProgOpCmd	0x20
 #define ET_CntlProgIdent	0x0B
+#define ET_SigQuiesce	0x1D
 
 #define ET_OpCmd_Mask	0x80000000
 #define ET_Msg_Mask		0x40000000
@@ -29,6 +30,7 @@
 #define ET_PMsgCmd_Mask	0x00800000
 #define ET_CtlProgOpCmd_Mask	0x00000001
 #define ET_CtlProgIdent_Mask	0x00200000
+#define ET_SigQuiesce_Mask	0x00000008
 
 #define GMF_DOM		0x8000
 #define GMF_SndAlrm	0x4000
@@ -214,7 +216,8 @@
 	0x0000,
 	0x0000,
 	sizeof (_hwcb_mask_t),
-	ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask,
+	ET_OpCmd_Mask | ET_PMsgCmd_Mask |
+	ET_StateChange_Mask | ET_SigQuiesce_Mask,
 	ET_Msg_Mask | ET_PMsgCmd_Mask | ET_CtlProgIdent_Mask
 };
 
diff -urN linux-2.4.20-pre1/drivers/s390/char/hwc_rw.c linux-2.4.20-pre2/drivers/s390/char/hwc_rw.c
--- linux-2.4.20-pre1/drivers/s390/char/hwc_rw.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.20-pre2/drivers/s390/char/hwc_rw.c	Mon Aug 12 16:34:16 2002
@@ -35,6 +35,8 @@
 #define MIN(a,b) (((a<b) ? a : b))
 #endif
 
+extern void ctrl_alt_del (void);
+
 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
 
 #define  USE_VM_DETECTION
@@ -172,6 +174,7 @@
 	unsigned char read_nonprio:1;
 	unsigned char read_prio:1;
 	unsigned char read_statechange:1;
+	unsigned char sig_quiesce:1;
 
 	unsigned char flags;
 
@@ -222,6 +225,7 @@
 	    0,
 	    0,
 	    0,
+	    0,
 	    NULL,
 	    NULL
 
@@ -231,6 +235,8 @@
 static unsigned long cr0_save __attribute__ ((aligned (8)));
 static unsigned char psw_mask __attribute__ ((aligned (8)));
 
+static ext_int_info_t ext_int_info_hwc;
+
 #define DELAYED_WRITE 0
 #define IMMEDIATE_WRITE 1
 
@@ -1527,6 +1533,19 @@
 				       HWC_RW_PRINT_HEADER
 				 "can not read state change notifications\n");
 
+	hwc_data.sig_quiesce
+	    = ((mask & ET_SigQuiesce_Mask) == ET_SigQuiesce_Mask);
+	if (hwc_data.sig_quiesce)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can receive signal quiesce\n");
+	else
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can not receive signal quiesce\n");
+
 	hwc_data.read_nonprio
 	    = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask);
 	if (hwc_data.read_nonprio)
@@ -1607,6 +1626,48 @@
 	return retval;
 }
 
+#ifdef CONFIG_SMP
+extern unsigned long cpu_online_map;
+static volatile unsigned long cpu_quiesce_map;
+
+static void 
+do_load_quiesce_psw (void)
+{
+	psw_t quiesce_psw;
+
+	clear_bit (smp_processor_id (), &cpu_quiesce_map);
+	if (smp_processor_id () == 0) {
+
+		while (cpu_quiesce_map != 0) ;
+
+		quiesce_psw.mask = _DW_PSW_MASK;
+		quiesce_psw.addr = 0xfff;
+		__load_psw (quiesce_psw);
+	}
+	signal_processor (smp_processor_id (), sigp_stop);
+}
+
+static void 
+do_machine_quiesce (void)
+{
+	cpu_quiesce_map = cpu_online_map;
+	smp_call_function (do_load_quiesce_psw, NULL, 0, 0);
+	do_load_quiesce_psw ();
+}
+
+#else
+static void 
+do_machine_quiesce (void)
+{
+	psw_t quiesce_psw;
+
+	quiesce_psw.mask = _DW_PSW_MASK;
+	queisce_psw.addr = 0xfff;
+	__load_psw (quiesce_psw);
+}
+
+#endif
+
 static int 
 process_evbufs (void *start, void *end)
 {
@@ -1642,6 +1703,13 @@
 			retval += eval_statechangebuf
 			    ((statechangebuf_t *) evbuf);
 			break;
+		case ET_SigQuiesce:
+
+			_machine_restart = do_machine_quiesce;
+			_machine_halt = do_machine_quiesce;
+			_machine_power_off = do_machine_quiesce;
+			ctrl_alt_del ();
+			break;
 		default:
 			internal_print (
 					       DELAYED_WRITE,
@@ -2004,7 +2072,8 @@
 
 #endif
 
-	if (register_external_interrupt (0x2401, hwc_interrupt_handler) != 0)
+	if (register_early_external_interrupt (0x2401, hwc_interrupt_handler,
+					       &ext_int_info_hwc) != 0)
 		panic ("Couldn't request external interrupts 0x2401");
 
 	spin_lock_init (&hwc_data.lock);
diff -urN linux-2.4.20-pre1/drivers/s390/char/tubfs.c linux-2.4.20-pre2/drivers/s390/char/tubfs.c
--- linux-2.4.20-pre1/drivers/s390/char/tubfs.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.20-pre2/drivers/s390/char/tubfs.c	Mon Aug 12 16:34:16 2002
@@ -42,11 +42,11 @@
 {
 	char name[16];
 
-	sprintf(name, "tub%.3x", tubp->devno);
+	sprintf(name, "tub%.4x", tubp->devno);
 	devfs_register(fs3270_devfs_dir, name, DEVFS_FL_DEFAULT,
 		       IBM_FS3270_MAJOR, tubp->minor,
 		       S_IFCHR | S_IRUSR | S_IWUSR, &fs3270_fops, NULL);
-	sprintf(name, "tty%.3x", tubp->devno);
+	sprintf(name, "tty%.4x", tubp->devno);
 	tty_register_devfs_name(&tty3270_driver, 0, tubp->minor,
 				fs3270_devfs_dir, name);
 }
@@ -56,12 +56,12 @@
 	char name[16];
 	devfs_handle_t handle;
 
-	sprintf(name, "tub%.3x", tubp->devno);
+	sprintf(name, "tub%.4x", tubp->devno);
 	handle = devfs_find_handle (fs3270_devfs_dir, name,
 				    IBM_FS3270_MAJOR, tubp->minor,
 				    DEVFS_SPECIAL_CHR, 0);
 	devfs_unregister (handle);
-	sprintf(name, "tty%.3x", tubp->devno);
+	sprintf(name, "tty%.4x", tubp->devno);
 	handle = devfs_find_handle (fs3270_devfs_dir, name,
 				    IBM_TTY3270_MAJOR, tubp->minor,
 				    DEVFS_SPECIAL_CHR, 0);
diff -urN linux-2.4.20-pre1/drivers/s390/char/tubtty.c linux-2.4.20-pre2/drivers/s390/char/tubtty.c
--- linux-2.4.20-pre1/drivers/s390/char/tubtty.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/s390/char/tubtty.c	Mon Aug 12 16:34:16 2002
@@ -471,11 +471,11 @@
 			tubp = (*tubminors)[i];
 #ifdef CONFIG_TN3270_CONSOLE
 			if (CONSOLE_IS_3270 && tubp == tub3270_con_tubp)
-				len += sprintf(buf + len, "%.3x CONSOLE %d\n",
+				len += sprintf(buf + len, "%.4x CONSOLE %d\n",
 					       tubp->devno, i);
 			else
 #endif
-				len += sprintf(buf + len, "%.3x %d %d\n",
+				len += sprintf(buf + len, "%.4x %d %d\n",
 					       tubp->devno, tty3270_major, i);
 			if (begin + len > off + count)
 				break;
diff -urN linux-2.4.20-pre1/drivers/s390/misc/chandev.c linux-2.4.20-pre2/drivers/s390/misc/chandev.c
--- linux-2.4.20-pre1/drivers/s390/misc/chandev.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/s390/misc/chandev.c	Mon Aug 12 16:34:16 2002
@@ -2013,7 +2013,7 @@
 		/* This is required because the device can go & come back */
                 /* even before we realize it is gone owing to the waits in our kernel threads */
 		/* & the device will be marked as not owned but its status will be good */
-                /* & an attempt to accidentally reprobe it may be done. */ 
+                /* & an attempt to accidently reprobe it may be done. */ 
 		remove:
 		chandev_remove(chandev_get_by_irq(curr_irqinfo->sch.irq));
 		
diff -urN linux-2.4.20-pre1/drivers/s390/s390io.c linux-2.4.20-pre2/drivers/s390/s390io.c
--- linux-2.4.20-pre1/drivers/s390/s390io.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/s390/s390io.c	Mon Aug 12 16:34:16 2002
@@ -1,6 +1,7 @@
 /*
  *  drivers/s390/s390io.c
  *   S/390 common I/O routines
+ *   $Revision: 1.171.2.21 $
  *
  *  S390 version
  *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
@@ -26,8 +27,22 @@
  *               08/02/2001 Cornelia Huck not already known devices can be blacklisted
  *                                        by piping to /proc/cio_ignore
  *               09/xx/2001 couple more fixes
+ *               10/15/2001 Cornelia Huck xsch - internal only for now
  *               10/29/2001 Cornelia Huck Blacklisting reworked again
  *               10/29/2001 Cornelia Huck improved utilization of debug feature
+ *               10/29/2001 Cornelia Huck more work on cancel_IO - use the flag
+ *                                        DOIO_CANCEL_ON_TIMEOUT in do_IO to get
+ *                                        io cancelled
+ *               11/15/2001 Cornelia Huck proper behaviour with procfs off
+ *               12/10/2001 Cornelia Huck added private_data + functions to 
+ *                                        ioinfo_t
+ *               11-12/2001 Cornelia Huck various cleanups
+ *               01/09/2002 Cornelia Huck PGID fixes
+ *                                        process css machine checks 
+ *               01/10/2002 Cornelia Huck added /proc/chpids
+ *               04/10/2002 Cornelia Huck fixed reaction on css machine checks
+ *               04/23/2002 Cornelia Huck fixed console isc (un)setting
+ *               06/06/2002 Cornelia Huck added detection of locked devices
  */
 
 #include <linux/module.h>
@@ -46,7 +61,7 @@
 #include <linux/bootmem.h>
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
-#endif 
+#endif
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -57,7 +72,7 @@
 #include <asm/processor.h>
 #include <asm/lowcore.h>
 #include <asm/idals.h>
-#include <asm/uaccess.h> 
+#include <asm/uaccess.h>
 #include <asm/cpcmd.h>
 
 #include <asm/s390io.h>
@@ -76,96 +91,148 @@
 		return (-ENODEV); \
 	if (ioinfo[irq] == INVALID_STORAGE_AREA) \
 		return (-ENODEV); \
-	} while(0) 
+        if (ioinfo[irq]->st) \
+                return -ENODEV; \
+	} while(0)
+
+#define CIO_TRACE_EVENT(imp, txt) do { \
+	if (cio_debug_initialized) \
+		debug_text_event(cio_debug_trace_id, \
+				 imp, \
+				 txt); \
+        }while (0)
+
+#define CIO_MSG_EVENT(imp, args...) do { \
+        if (cio_debug_initialized) \
+                debug_sprintf_event(cio_debug_msg_id, \
+                                    imp, \
+                                    ##args); \
+        } while (0)
+
+#define CIO_CRW_EVENT(imp, args...) do { \
+        if (cio_debug_initialized) \
+                debug_sprintf_event(cio_debug_crw_id, \
+                                    imp, \
+                                    ##args); \
+        } while (0)
 
 #undef  CONFIG_DEBUG_IO
 #define CONFIG_DEBUG_CRW
+#define CONFIG_DEBUG_CHSC
 
-unsigned int           highest_subchannel;
-ioinfo_t              *ioinfo_head = NULL;
-ioinfo_t              *ioinfo_tail = NULL;
-ioinfo_t              *ioinfo[__MAX_SUBCHANNELS] = {
-	[0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA
+unsigned int highest_subchannel;
+ioinfo_t *ioinfo_head = NULL;
+ioinfo_t *ioinfo_tail = NULL;
+ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = {
+	[0 ... (__MAX_SUBCHANNELS - 1)] = INVALID_STORAGE_AREA
 };
 
-static atomic_t    sync_isc     = ATOMIC_INIT(-1);
-static int         sync_isc_cnt = 0;      // synchronous irq processing lock
-
-static spinlock_t  adapter_lock = SPIN_LOCK_UNLOCKED;
-                                          // adapter interrupt lock
-static int        cons_dev          = -1; // identify console device
-static int        init_IRQ_complete = 0;
-static int        cio_show_msg      = 0;
-static schib_t   *p_init_schib      = NULL;
-static irb_t     *p_init_irb        = NULL;
-static __u64      irq_IPL_TOD;
-static adapter_int_handler_t adapter_handler   = NULL;
+#ifdef CONFIG_CHSC
+__u64 chpids[4] = {0,0,0,0};
+__u64 chpids_logical[4] = {-1,-1,-1,-1};
+__u64 chpids_known[4] = {0,0,0,0};
+#endif /* CONFIG_CHSC */
+
+static atomic_t sync_isc = ATOMIC_INIT (-1);
+static int sync_isc_cnt = 0;	/* synchronous irq processing lock */
+
+static spinlock_t adapter_lock = SPIN_LOCK_UNLOCKED;	/* adapter interrupt lock */
+static int cons_dev = -1;	/* identify console device */
+static int init_IRQ_complete = 0;
+static int cio_show_msg = 0;
+static schib_t *p_init_schib = NULL;
+static irb_t *p_init_irb = NULL;
+static __u64 irq_IPL_TOD;
+static adapter_int_handler_t adapter_handler = NULL;
+static pgid_t * global_pgid;
 
 /* for use of debug feature */
-debug_info_t *cio_debug_msg_id = NULL;  
+debug_info_t *cio_debug_msg_id = NULL;
 debug_info_t *cio_debug_trace_id = NULL;
 debug_info_t *cio_debug_crw_id = NULL;
 int cio_debug_initialized = 0;
 
-static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
-static void s390_process_subchannels( void);
-static void s390_device_recognition_all( void);
-static void s390_device_recognition_irq( int irq);
+#ifdef CONFIG_CHSC
+int cio_chsc_desc_avail = 0;
+int cio_chsc_err_msg = 0;
+#endif
+
+static void init_IRQ_handler (int irq, void *dev_id, struct pt_regs *regs);
+static void s390_process_subchannels (void);
+static void s390_device_recognition_all (void);
+static void s390_device_recognition_irq (int irq);
 #ifdef CONFIG_PROC_FS
-static void s390_redo_validation(void);
+static void s390_redo_validation (void);
 #endif
-static int  s390_validate_subchannel( int irq, int enable);
-static int  s390_SenseID( int irq, senseid_t *sid, __u8 lpm);
-static int  s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
-static int  s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid);
-static int  s390_process_IRQ( unsigned int irq );
-static int  enable_subchannel( unsigned int irq);
-static int  disable_subchannel( unsigned int irq);
+static int s390_validate_subchannel (int irq, int enable);
+static int s390_SenseID (int irq, senseid_t * sid, __u8 lpm);
+static int s390_SetPGID (int irq, __u8 lpm);
+static int s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid);
+static int s390_process_IRQ (unsigned int irq);
+static int enable_subchannel (unsigned int irq);
+static int disable_subchannel (unsigned int irq);
+int cancel_IO (int irq);
+int s390_start_IO (int irq, ccw1_t * cpa, unsigned long user_intparm,
+		   __u8 lpm, unsigned long flag);
+
+static int s390_send_nop(int irq, __u8 lpm);
 
 #ifdef CONFIG_PROC_FS
-static int chan_proc_init( void );
-#endif 
+static int chan_proc_init (void);
+#endif
 
-static inline void do_adapter_IO( __u32 intparm );
+static inline void do_adapter_IO (__u32 intparm);
 
-int  s390_DevicePathVerification( int irq, __u8 domask );
-int  s390_register_adapter_interrupt( adapter_int_handler_t handler );
-int  s390_unregister_adapter_interrupt( adapter_int_handler_t handler );
+int s390_DevicePathVerification (int irq, __u8 domask);
+int s390_register_adapter_interrupt (adapter_int_handler_t handler);
+int s390_unregister_adapter_interrupt (adapter_int_handler_t handler);
 
-extern int  do_none(unsigned int irq, int cpu, struct pt_regs * regs);
-extern int  enable_none(unsigned int irq);
-extern int  disable_none(unsigned int irq);
+extern int do_none (unsigned int irq, int cpu, struct pt_regs *regs);
+extern int enable_none (unsigned int irq);
+extern int disable_none (unsigned int irq);
 
-asmlinkage void do_IRQ( struct pt_regs regs );
+asmlinkage void do_IRQ (struct pt_regs regs);
+
+#ifdef CONFIG_CHSC
+static chsc_area_t *chsc_area_ssd = NULL;
+static chsc_area_t *chsc_area_sei = NULL;
+static spinlock_t chsc_lock_ssd = SPIN_LOCK_UNLOCKED;
+static spinlock_t chsc_lock_sei = SPIN_LOCK_UNLOCKED;
+static int chsc_get_sch_descriptions( void );
+int s390_vary_chpid( __u8 chpid, int on );
+#endif
 
 #ifdef CONFIG_PROC_FS
 #define MAX_CIO_PROCFS_ENTRIES 0x300
 /* magic number; we want to have some room to spare */
 
-int cio_procfs_device_create(int devno);
-int cio_procfs_device_remove(int devno);
-int cio_procfs_device_purge(void);
+int cio_procfs_device_create (int devno);
+int cio_procfs_device_remove (int devno);
+int cio_procfs_device_purge (void);
 #endif
 
 int cio_notoper_msg = 1;
+
 #ifdef CONFIG_PROC_FS
-int cio_proc_devinfo = 0; /* switch off the /proc/deviceinfo/ stuff by default
-			     until problems are dealt with */
+int cio_proc_devinfo = 0;	/* switch off the /proc/deviceinfo/ stuff by default
+				   until problems are dealt with */
 #endif
 
-unsigned long s390_irq_count[NR_CPUS]; /* trace how many irqs have occured per cpu... */
-int cio_count_irqs = 1;       /* toggle use here... */
+unsigned long s390_irq_count[NR_CPUS];	/* trace how many irqs have occured per cpu... */
+int cio_count_irqs = 1;		/* toggle use here... */
+
+int cio_sid_with_pgid = 0;     /* if we need a PGID for SenseID, switch this on */
 
 /* 
  * "Blacklisting" of certain devices:
  * Device numbers given in the commandline as cio_ignore=... won't be known to Linux
  * These can be single devices or ranges of devices
- *
+ * 
  * 10/23/01 reworked to get rid of lists
  */
 
-static unsigned long bl_dev[2048] = {0,};
-    
+static u32 bl_dev[2048];
+
 static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
 static int highest_ignored = 0;
 static int nr_ignored = 0;
@@ -175,31 +242,36 @@
  * Blacklist the devices from-to
  */
 
-static inline void blacklist_range_add( int from, int to,int locked)
+static inline void
+blacklist_range_add (int from, int to, int locked)
 {
- 
-     unsigned long flags;
-     int i;
 
-     if (to && (from>to)) {
-	     printk(KERN_WARNING "Invalid blacklist range %x to %x, skipping\n", from, to);
-	     return;
-     }
-     if(!locked)
-	     spin_lock_irqsave( &blacklist_lock, flags );
+	unsigned long flags;
+	int i;
 
-     if (!to) 
-	     to = from;
-     for (i=from;i<=to;i++) {
-	     set_bit(i,&bl_dev);
-	     nr_ignored++;
-     }
+	if ((to && (from > to))
+	    || (to<0) || (to > 0xffff)
+	    || (from<0) || (from > 0xffff)) {
+		printk (KERN_WARNING
+			"Invalid blacklist range %x to %x, skipping\n", from,
+			to);
+		return;
+	}
+	if (!locked)
+		spin_lock_irqsave (&blacklist_lock, flags);
+
+	if (!to)
+		to = from;
+	for (i = from; i <= to; i++) {
+		set_bit (i, &bl_dev);
+		nr_ignored++;
+	}
 
-     if (to>=highest_ignored)
-	     highest_ignored = to;
+	if (to >= highest_ignored)
+		highest_ignored = to;
 
-     if(!locked)
-	     spin_unlock_irqrestore( &blacklist_lock, flags );
+	if (!locked)
+		spin_unlock_irqrestore (&blacklist_lock, flags);
 }
 
 /* 
@@ -207,22 +279,34 @@
  * Removes a range from the blacklist chain
  */
 
-static inline void blacklist_range_remove( int from, int to )
+static inline void
+blacklist_range_remove (int from, int to)
 {
-     long flags;
+	long flags;
 	int i;
 
-     spin_lock_irqsave( &blacklist_lock, flags );
-     
-	for (i=from;i<=to;i++) {
-		clear_bit(i,&bl_dev);
+	if ((to<0) || (to > 0xffff)
+	    || (from<0) || (from > 0xffff)) {
+		printk (KERN_WARNING
+			"Invalid blacklist range %x to %x, "
+			"not freeing\n",
+			from, to);
+		return;
+	}
+
+	spin_lock_irqsave (&blacklist_lock, flags);
+
+	for (i = from; i <= to; i++) {
+		clear_bit (i, &bl_dev);
 		nr_ignored--;
 	}
 
-	if (to == highest_ignored) 
-		for (highest_ignored=from;(highest_ignored>0) && (!test_bit(highest_ignored,&bl_dev));highest_ignored--);
+	if (to == highest_ignored)
+		for (highest_ignored = from; (highest_ignored > 0)
+		     && (!test_bit (highest_ignored, &bl_dev));
+		     highest_ignored--) ;
 
-     spin_unlock_irqrestore( &blacklist_lock, flags );
+	spin_unlock_irqrestore (&blacklist_lock, flags);
 }
 
 /* Parsing the commandline for blacklist parameters */
@@ -231,13 +315,14 @@
  * Variable to hold the blacklisted devices given by the parameter line
  * cio_ignore=...
  */
-char *blacklist[256] = {NULL, };
+char *blacklist[256] = { NULL, };
 
 /*
  * Get the cio_ignore=... items from the parameter line
  */
 
-static void blacklist_split_parm_string (char *str)
+static void
+blacklist_split_parm_string (char *str)
 {
 	char *tmp = str;
 	int count = 0;
@@ -252,9 +337,11 @@
 			*end = '\0';
 			end++;
 		}
-		blacklist[count] = alloc_bootmem (len * sizeof (char) );
+		blacklist[count] = alloc_bootmem (len * sizeof (char));
 		if (blacklist == NULL) {
-			printk (KERN_WARNING "can't store cio_ignore= parameter no %d\n", count + 1);
+			printk (KERN_WARNING
+				"can't store cio_ignore= parameter no %d\n",
+				count + 1);
 			break;
 		}
 		memset (blacklist[count], 0, len * sizeof (char));
@@ -268,21 +355,21 @@
  * The blacklist parameters as one concatenated string
  */
 
-static char blacklist_parm_string[1024] __initdata = {0,};
-
+static char blacklist_parm_string[1024] __initdata = { 0, };
 
 /* 
  * function: blacklist_strtoul
  * Strip leading '0x' and interpret the values as Hex
  */
-static inline int blacklist_strtoul (char *str, char **stra)
+static inline int
+blacklist_strtoul (char *str, char **stra)
 {
 	char *temp = str;
 	int val;
 	if (*temp == '0') {
-		temp++;		                /* strip leading zero */
+		temp++;		/* strip leading zero */
 		if (*temp == 'x')
-			temp++;	                /* strip leading x */
+			temp++;	/* strip leading x */
 	}
 	val = simple_strtoul (temp, &temp, 16);	/* interpret anything as hex */
 	*stra = temp;
@@ -295,52 +382,53 @@
  * Add the blacklisted devices to the blacklist chain
  */
 
-static inline void blacklist_parse( char **str )
+static inline void
+blacklist_parse (char **str)
 {
-     char *temp;
-     int from, to;
+	char *temp;
+	int from, to;
 
-     while (*str) {
-	  temp = *str;
-	  from = 0;
-	  to = 0;
-	  
-	  from = blacklist_strtoul( temp, &temp );
-	  if (*temp == '-') {
-	       temp++;
-	       to = blacklist_strtoul( temp, &temp );
-	  }
-	  blacklist_range_add( from, to, 0 );
+	while (*str) {
+		temp = *str;
+		from = 0;
+		to = 0;
+
+		from = blacklist_strtoul (temp, &temp);
+		if (*temp == '-') {
+			temp++;
+			to = blacklist_strtoul (temp, &temp);
+		}
+		blacklist_range_add (from, to, 0);
 #ifdef CONFIG_DEBUG_IO
-	  printk( KERN_INFO "Blacklisted range from %X to %X\n", from, to );
+		printk (KERN_INFO "Blacklisted range from %X to %X\n", from,
+			to);
 #endif
-	  str++;
-     }
+		str++;
+	}
 }
 
-
 /*
  * Initialisation of blacklist 
  */
 
-void __init blacklist_init( void )
+void __init
+blacklist_init (void)
 {
-#ifdef CONFIG_DEBUG_IO     
-     printk( KERN_DEBUG "Reading blacklist...\n");
+#ifdef CONFIG_DEBUG_IO
+	printk (KERN_DEBUG "Reading blacklist...\n");
 #endif
-     if (cio_debug_initialized)
-	     debug_sprintf_event(cio_debug_msg_id, 6,
-				 "Reading blacklist\n");
-     blacklist_split_parm_string( blacklist_parm_string );
-     blacklist_parse( blacklist );
-}
+	CIO_MSG_EVENT(6, "Reading blacklist\n");
 
+	blacklist_split_parm_string (blacklist_parm_string);
+	blacklist_parse (blacklist);
+}
 
 /*
  * Get all the blacklist parameters from parameter line
  */
 
-void __init blacklist_setup (char *str, int *ints)
+void __init
+blacklist_setup (char *str, int *ints)
 {
 	int len = strlen (blacklist_parm_string);
 	if (len != 0) {
@@ -349,19 +437,20 @@
 	strcat (blacklist_parm_string, str);
 }
 
-int __init blacklist_call_setup (char *str)
+int __init
+blacklist_call_setup (char *str)
 {
-        int dummy;
+	int dummy;
 #ifdef CONFIG_DEBUG_IO
-	printk( KERN_DEBUG "Reading blacklist parameters...\n" );
+	printk (KERN_DEBUG "Reading blacklist parameters...\n");
 #endif
-	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_msg_id, 6,
-				    "Reading blacklist parameters\n");
-        blacklist_setup(str,&dummy);
-	
-	blacklist_init(); /* Blacklist ranges must be ready when device recognition starts */
-       
+	CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
+
+	blacklist_setup (str, &dummy);
+
+	/* Blacklist ranges must be ready when device recognition starts */
+	blacklist_init ();
+
 	return 1;
 }
 
@@ -374,18 +463,19 @@
  * Returns 1 if the given devicenumber can be found in the blacklist, otherwise 0.
  */
 
-static inline int is_blacklisted( int devno )
+static inline int
+is_blacklisted (int devno)
 {
-     long flags;
-     int retval=0;
+	long flags;
+	int retval = 0;
 
-     spin_lock_irqsave( &blacklist_lock, flags ); 
+	spin_lock_irqsave (&blacklist_lock, flags);
 
-     if (test_bit(devno,&bl_dev)) 
-		     retval=1;
+	if (test_bit (devno, &bl_dev))
+		retval = 1;
 
-     spin_unlock_irqrestore( &blacklist_lock, flags );
-     return retval;
+	spin_unlock_irqrestore (&blacklist_lock, flags);
+	return retval;
 }
 
 /*
@@ -393,19 +483,20 @@
  * set all blacklisted devices free...
  */
 
-void blacklist_free_all_ranges(void) 
+void
+blacklist_free_all_ranges (void)
 {
 	unsigned long flags;
 	int i;
 
-	spin_lock_irqsave( &blacklist_lock, flags ); 
+	spin_lock_irqsave (&blacklist_lock, flags);
 
-	for (i=0;i<=highest_ignored;i++)
-		clear_bit(i,&bl_dev);
+	for (i = 0; i <= highest_ignored; i++)
+		clear_bit (i, &bl_dev);
 	highest_ignored = 0;
 	nr_ignored = 0;
 
-	spin_unlock_irqrestore( &blacklist_lock, flags );
+	spin_unlock_irqrestore (&blacklist_lock, flags);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -413,7 +504,8 @@
  * Function: blacklist_parse_proc_parameters
  * parse the stuff which is piped to /proc/cio_ignore
  */
-void blacklist_parse_proc_parameters(char *buf)
+void
+blacklist_parse_proc_parameters (char *buf)
 {
 	char *tmp;
 	int i;
@@ -426,194 +518,227 @@
 	int err = 0;
 
 	tmp = buf;
-	if (strstr(tmp, "free ")) {
-		for (i=0; i<5; i++) {
+	if (strstr (tmp, "free ")) {
+		for (i = 0; i < 5; i++) {
 			tmp++;
 		}
-		if (strstr(tmp, "all")) {
-			blacklist_free_all_ranges();
-			s390_redo_validation();
+		if (strstr (tmp, "all")) {
+			blacklist_free_all_ranges ();
+			s390_redo_validation ();
 		} else {
 			while (tmp != NULL) {
-				end = strchr(tmp, ',');
+				end = strchr (tmp, ',');
 				if (end == NULL) {
-					len = strlen(tmp) + 1;
+					len = strlen (tmp) + 1;
 				} else {
-					len = (long)end - (long) tmp + 1;
+					len = (long) end - (long) tmp + 1;
 					*end = '\0';
 					end++;
 				}
-				param =  (char*) kmalloc(len * sizeof(char) + 1, GFP_KERNEL);
-				strncpy(param, (const char *) tmp, len);
+				param =
+				    (char *) kmalloc (len * sizeof (char) + 1,
+						      GFP_KERNEL);
+				strncpy (param, (const char *) tmp, len);
 				tmp = end;
-				from = blacklist_strtoul(param, &param);
+				from = blacklist_strtoul (param, &param);
 				if (*param == '-') {
 					param++;
-					to = blacklist_strtoul(param, &param);
+					to = blacklist_strtoul (param, &param);
 				} else {
 					to = from;
 				}
-				blacklist_range_remove( from, to );
-				kfree(param);
+				blacklist_range_remove (from, to);
+				kfree (param);
 			}
-				s390_redo_validation();
+			s390_redo_validation ();
 		}
-	} else if (strstr(tmp, "add ")) {
-		for (i=0;i<4;i++){
+	} else if (strstr (tmp, "add ")) {
+		for (i = 0; i < 4; i++) {
 			tmp++;
 		}
 		while (tmp != NULL) {
-			end = strchr(tmp, ',');
+			end = strchr (tmp, ',');
 			if (end == NULL) {
-				len = strlen(tmp) + 1;
+				len = strlen (tmp) + 1;
 			} else {
-				len = (long)end - (long) tmp + 1;
+				len = (long) end - (long) tmp + 1;
 				*end = '\0';
 				end++;
 			}
-			param =  (char*) kmalloc(len * sizeof(char) + 1, GFP_KERNEL);
-			strncpy(param, (const char *) tmp, len);
+			param =
+			    (char *) kmalloc (len * sizeof (char) + 1,
+					      GFP_KERNEL);
+			strncpy (param, (const char *) tmp, len);
 			tmp = end;
-			from = blacklist_strtoul(param, &param);
+			from = blacklist_strtoul (param, &param);
 			if (*param == '-') {
 				param++;
-				to = blacklist_strtoul(param, &param);
+				to = blacklist_strtoul (param, &param);
 			} else {
 				to = from;
 			}
-			spin_lock_irqsave( &blacklist_lock, flags ); 
-			
+			spin_lock_irqsave (&blacklist_lock, flags);
+
 			/*
 			 * Don't allow for already known devices to be
 			 * blacklisted
 			 * The criterion is a bit dumb, devices which once were
 			 * there but are already gone are also caught...
 			 */
-			
+
 			err = 0;
-			for (i=0; i<=highest_subchannel; i++) {
-				if (ioinfo[i]!=INVALID_STORAGE_AREA) {
-					if (   (ioinfo[i]->schib.pmcw.dev >= from)
-					    && (ioinfo[i]->schib.pmcw.dev <= to)  ) {
-						printk(KERN_WARNING "cio_ignore: Won't blacklist "
-						       "already known devices, skipping range "
-						       "%x to %x\n", from, to);
-						err = 1;
-						break;
-					}
+			for (i = 0; i <= highest_subchannel; i++) {
+				if (ioinfo[i] != INVALID_STORAGE_AREA) {
+					if (!ioinfo[i]->st) 
+						if ((ioinfo[i]->schib.pmcw.dev >= from)
+						    && (ioinfo[i]->schib.pmcw.dev <=
+							to)) {
+							printk (KERN_WARNING
+								"cio_ignore: Won't blacklist "
+								"already known devices, "
+								"skipping range %x to %x\n",
+								from, to);
+							err = 1;
+							break;
+						}
 				}
 			}
 
-			if (!err) 
-				blacklist_range_add(from, to, 1);
-			
-			spin_unlock_irqrestore( &blacklist_lock, flags );
-			kfree(param);
+			if (!err)
+				blacklist_range_add (from, to, 1);
+
+			spin_unlock_irqrestore (&blacklist_lock, flags);
+			kfree (param);
 		}
 
 	} else {
-		printk( KERN_WARNING "cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n");
-		printk( KERN_WARNING "or 'add <devno-range>,<devno-range>,...'\n");
+		printk (KERN_WARNING
+			"cio_ignore: Parse error; "
+			"try using 'free all|<devno-range>,<devno-range>,...'\n");
+		printk (KERN_WARNING
+			"or 'add <devno-range>,<devno-range>,...'\n");
 	}
 }
 #endif
 /* End of blacklist handling */
 
+void s390_displayhex (char *str, void *ptr, s32 cnt);
+void s390_displayhex2 (char *str, void *ptr, s32 cnt, int level);
 
-void s390_displayhex(char *str,void *ptr,s32 cnt);
-void s390_displayhex2(char *str, void *ptr, s32 cnt, int level);
-
-void s390_displayhex(char *str,void *ptr,s32 cnt)
+void
+s390_displayhex (char *str, void *ptr, s32 cnt)
 {
-	s32	cnt1,cnt2,maxcnt2;
-	u32	*currptr=(__u32 *)ptr;
+	s32 cnt1, cnt2, maxcnt2;
+	u32 *currptr = (__u32 *) ptr;
 
-	printk("\n%s\n",str);
+	printk ("\n%s\n", str);
 
-	for(cnt1=0;cnt1<cnt;cnt1+=16)
-	{
-		printk("%08lX ",(unsigned long)currptr);
-		maxcnt2=cnt-cnt1;
-		if(maxcnt2>16)
-			maxcnt2=16;
-		for(cnt2=0;cnt2<maxcnt2;cnt2+=4)
-			printk("%08X ",*currptr++);
-		printk("\n");
+	for (cnt1 = 0; cnt1 < cnt; cnt1 += 16) {
+		printk ("%08lX ", (unsigned long) currptr);
+		maxcnt2 = cnt - cnt1;
+		if (maxcnt2 > 16)
+			maxcnt2 = 16;
+		for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
+			printk ("%08X ", *currptr++);
+		printk ("\n");
 	}
 }
 
-void s390_displayhex2(char *str, void *ptr, s32 cnt, int level)
+void
+s390_displayhex2 (char *str, void *ptr, s32 cnt, int level)
 {
 	s32 cnt1, cnt2, maxcnt2;
-	u32 *currptr = (__u32 *)ptr;
-	char buffer[cnt*12];
+	u32 *currptr = (__u32 *) ptr;
+	char buffer[cnt * 12];
 
-	debug_sprintf_event(cio_debug_msg_id, level, "%s\n", str);
+	debug_text_event (cio_debug_msg_id, level, str);
 
-	for (cnt1 = 0; cnt1<cnt; cnt1+=16) {
-		sprintf(buffer, "%08lX ", (unsigned long)currptr);
+	for (cnt1 = 0; cnt1 < cnt; cnt1 += 16) {
+		sprintf (buffer, "%08lX ", (unsigned long) currptr);
 		maxcnt2 = cnt - cnt1;
 		if (maxcnt2 > 16)
 			maxcnt2 = 16;
 		for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
-			sprintf(buffer, "%08X ", *currptr++);
+			sprintf (buffer, "%08X ", *currptr++);
 	}
-	debug_sprintf_event(cio_debug_msg_id, level, "%s\n",buffer);
+	debug_text_event (cio_debug_msg_id, level, buffer);
 }
 
-static int __init cio_setup( char *parm )
+static int __init
+cio_setup (char *parm)
 {
-	if ( !strcmp( parm, "yes") )
-	{
+	if (!strcmp (parm, "yes")) {
 		cio_show_msg = 1;
-	}
-	else if ( !strcmp( parm, "no") )
-	{
+	} else if (!strcmp (parm, "no")) {
 		cio_show_msg = 0;
-	}
-	else
-	{
-		printk( KERN_ERR "cio_setup : invalid cio_msg parameter '%s'", parm);
+	} else {
+		printk (KERN_ERR "cio_setup : invalid cio_msg parameter '%s'",
+			parm);
 
-	} /* endif */
+	}
 
 	return 1;
 }
 
-__setup("cio_msg=", cio_setup);
+__setup ("cio_msg=", cio_setup);
 
-static int __init cio_notoper_setup(char *parm)
+static int __init
+cio_notoper_setup (char *parm)
 {
-	if (!strcmp(parm, "yes")) {
+	if (!strcmp (parm, "yes")) {
 		cio_notoper_msg = 1;
-	} else if (!strcmp(parm, "no")) {
+	} else if (!strcmp (parm, "no")) {
 		cio_notoper_msg = 0;
 	} else {
-		printk( KERN_ERR "cio_notoper_setup: invalid cio_notoper_msg parameter '%s'", parm);
+		printk (KERN_ERR
+			"cio_notoper_setup: "
+			"invalid cio_notoper_msg parameter '%s'", parm);
 	}
 
 	return 1;
 }
-	
-__setup("cio_notoper_msg=", cio_notoper_setup);
+
+__setup ("cio_notoper_msg=", cio_notoper_setup);
 
 #ifdef CONFIG_PROC_FS
-static int __init cio_proc_devinfo_setup(char *parm)
+static int __init
+cio_proc_devinfo_setup (char *parm)
 {
-	if (!strcmp(parm, "yes")) {
+	if (!strcmp (parm, "yes")) {
 		cio_proc_devinfo = 1;
-	} else if (!strcmp(parm, "no")) {
+	} else if (!strcmp (parm, "no")) {
 		cio_proc_devinfo = 0;
 	} else {
-		printk( KERN_ERR "cio_proc_devinfo_setup: invalid parameter '%s'\n",parm);
+		printk (KERN_ERR
+			"cio_proc_devinfo_setup: invalid parameter '%s'\n",
+			parm);
 	}
 
 	return 1;
 }
 
-__setup("cio_proc_devinfo=", cio_proc_devinfo_setup);
+__setup ("cio_proc_devinfo=", cio_proc_devinfo_setup);
 #endif
 
+static int __init
+cio_pgid_setup (char *parm)
+{
+	if (!strcmp (parm, "yes")) {
+		cio_sid_with_pgid = 1;
+	} else if (!strcmp (parm, "no")) {
+		cio_sid_with_pgid = 0;
+	} else {
+		printk (KERN_ERR 
+			"cio_pgid_setup : invalid cio_msg parameter '%s'",
+			parm);
+
+	}
+
+	return 1;
+}
+
+__setup ("cio_sid_with_pgid=", cio_pgid_setup);
+
 /*
  * register for adapter interrupts
  *
@@ -625,590 +750,629 @@
  *  being shared interrupts, and thus build a linked list
  *  of adapter handlers ... to be evaluated ...
  */
-int  s390_register_adapter_interrupt( adapter_int_handler_t handler )
+int
+s390_register_adapter_interrupt (adapter_int_handler_t handler)
 {
 	int ret = 0;
 	char dbf_txt[15];
-	
-	if (cio_debug_initialized)
-		debug_text_event(cio_debug_trace_id, 4, "rgaint");
 
-	spin_lock( &adapter_lock );
+	CIO_TRACE_EVENT (4, "rgaint");
 
-	if ( handler == NULL )
+	spin_lock (&adapter_lock);
+
+	if (handler == NULL)
 		ret = -EINVAL;
-	else if ( adapter_handler )
+	else if (adapter_handler)
 		ret = -EBUSY;
 	else
 		adapter_handler = handler;
-  	
-	spin_unlock( &adapter_lock ); 	
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"ret:%d",ret);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	spin_unlock (&adapter_lock);
 
-	return( ret);
-}
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
+	return (ret);
+}
 
-int  s390_unregister_adapter_interrupt( adapter_int_handler_t handler )
+int
+s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
 {
 	int ret = 0;
 	char dbf_txt[15];
-	
-	if (cio_debug_initialized)
-		debug_text_event(cio_debug_trace_id, 4, "urgaint");
 
-	spin_lock( &adapter_lock ); 	
+	CIO_TRACE_EVENT (4, "urgaint");
 
-	if ( handler == NULL )
+	spin_lock (&adapter_lock);
+
+	if (handler == NULL)
 		ret = -EINVAL;
-	else if ( handler != adapter_handler )
+	else if (handler != adapter_handler)
 		ret = -EINVAL;
 	else
 		adapter_handler = NULL;
-  	
-	spin_unlock( &adapter_lock ); 	
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"ret:%d",ret);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	spin_unlock (&adapter_lock);
 
-	return( ret);
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	return (ret);
 }
 
-static inline void do_adapter_IO( __u32 intparm )
+static inline void
+do_adapter_IO (__u32 intparm)
 {
-	if (cio_debug_initialized)
-		debug_text_event(cio_debug_trace_id, 4, "doaio");
+	CIO_TRACE_EVENT (4, "doaio");
+
+	spin_lock (&adapter_lock);
+
+	if (adapter_handler)
+		(*adapter_handler) (intparm);
+
+	spin_unlock (&adapter_lock);
+
+	return;
+}
+
+
+/*
+ * Function: s390_send_nop
+ * 
+ * sends a nop CCW to the specified subchannel down the given path(s)
+ */
+static int
+s390_send_nop(int irq, __u8 lpm)
+{
+	char dbf_txt[15];
+	ccw1_t *nop_ccw;
+	devstat_t devstat;
+	devstat_t *pdevstat = &devstat;
+	unsigned long flags;
+
+	int irq_ret = 0;
+	int inlreq = 0;
+
+	SANITY_CHECK(irq);
+
+	if (!ioinfo[irq]->ui.flags.oper)
+		/* no sense in trying */
+		return -ENODEV;
+
+	sprintf(dbf_txt, "snop%x", irq);
+	CIO_TRACE_EVENT(5, dbf_txt);
+
+	if (!ioinfo[irq]->ui.flags.ready) {
+		/*
+		 * If there's no handler, use our dummy handler.
+		 */
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE,
+				       "SNOP",
+				       pdevstat);
+		if (!irq_ret)
+			inlreq = 1;
+	} else {
+		pdevstat = ioinfo[irq]->irq_desc.dev_id;
+	}
+	
+	if (irq_ret)
+		return irq_ret;
+
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	if (init_IRQ_complete)
+		nop_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA);
+	else
+		nop_ccw = alloc_bootmem_low (sizeof (ccw1_t));
+
+	nop_ccw->cmd_code = CCW_CMD_NOOP;
+	nop_ccw->cda = 0;
+	nop_ccw->count = 0;
+	nop_ccw->flags = CCW_FLAG_SLI;
+
+	memset (pdevstat, '\0', sizeof (devstat_t));
+	
+	irq_ret = s390_start_IO (irq, nop_ccw, 0xE2D5D6D7, lpm,
+				 DOIO_WAIT_FOR_INTERRUPT
+				 | DOIO_TIMEOUT
+				 | DOIO_DONT_CALL_INTHDLR
+				 | DOIO_VALID_LPM);
 	
-	spin_lock( &adapter_lock ); 	
+	if (irq_ret == -ETIMEDOUT) {
+
+		/* better cancel... */
+		cancel_IO(irq);
+	}
+
+	if (init_IRQ_complete) 
+		kfree (nop_ccw);
+	else
+		free_bootmem ((unsigned long) nop_ccw, sizeof (ccw1_t));
 
-	if ( adapter_handler )
-		(*adapter_handler)( intparm );
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-	spin_unlock( &adapter_lock );
+	if (inlreq)
+		free_irq (irq, pdevstat);
+
+	return irq_ret;
 
-	return;  	
 }
 
+
+
 /*
  * Note : internal use of irqflags SA_PROBE for NOT path grouping 
  *
  */
-int s390_request_irq_special( int                      irq,
-                              io_handler_func_t        io_handler,
-                              not_oper_handler_func_t  not_oper_handler,
-                              unsigned long            irqflags,
-                              const char              *devname,
-                              void                    *dev_id)
-{
-	int		retval = 0;
-	unsigned long	flags;
-	char            dbf_txt[15];
-	int             retry;
+int
+s390_request_irq_special (int irq,
+			  io_handler_func_t io_handler,
+			  not_oper_handler_func_t not_oper_handler,
+			  unsigned long irqflags,
+			  const char *devname, void *dev_id)
+{
+	int retval = 0;
+	unsigned long flags;
+	char dbf_txt[15];
+	int retry;
 
 	if (irq >= __MAX_SUBCHANNELS)
 		return -EINVAL;
 
-	if ( !io_handler || !dev_id )
+	if (!io_handler || !dev_id)
 		return -EINVAL;
 
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return -ENODEV;
+	
+	if (ioinfo[irq]->st)
 		return -ENODEV;
 
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "reqsp%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "reqs%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/*
 	 * The following block of code has to be executed atomically
 	 */
-	s390irq_spin_lock_irqsave( irq, flags);
+	s390irq_spin_lock_irqsave (irq, flags);
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
+	if (!ioinfo[irq]->ui.flags.ready) {
 		retry = 5;
-		
+
 		ioinfo[irq]->irq_desc.handler = io_handler;
-		ioinfo[irq]->irq_desc.name    = devname;
-		ioinfo[irq]->irq_desc.dev_id  = dev_id;
-		ioinfo[irq]->ui.flags.ready   = 1;
-		
-		
+		ioinfo[irq]->irq_desc.name = devname;
+		ioinfo[irq]->irq_desc.dev_id = dev_id;
+		ioinfo[irq]->ui.flags.ready = 1;
+
 		do {
-			retval = enable_subchannel(irq);
+			retval = enable_subchannel (irq);
 			if (retval) {
 				ioinfo[irq]->ui.flags.ready = 0;
 				break;
 			}
-			
-			stsch(irq,&ioinfo[irq]->schib);
-			if (ioinfo[irq]->schib.pmcw.ena) 
+
+			stsch (irq, &ioinfo[irq]->schib);
+			if (ioinfo[irq]->schib.pmcw.ena)
 				retry = 0;
 			else
 				retry--;
 
 		} while (retry);
-	}
-	else
-	{
+	} else {
 		/*
 		 *  interrupt already owned, and shared interrupts
 		 *   aren't supported on S/390.
 		 */
 		retval = -EBUSY;
 
-	} /* endif */
-
-	s390irq_spin_unlock_irqrestore(irq,flags);
-
+	}
 
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-	if ( retval == 0 )
-	{
-		if ( !(irqflags & SA_PROBE))
-			s390_DevicePathVerification( irq, 0 );
+	if (retval == 0) {
+		if (!(irqflags & SA_PROBE) &&
+		    (!ioinfo[irq]->ui.flags.unfriendly)) 
+			s390_DevicePathVerification (irq, 0);
 
 		ioinfo[irq]->ui.flags.newreq = 1;
-		ioinfo[irq]->nopfunc         = not_oper_handler;  	
+		ioinfo[irq]->nopfunc = not_oper_handler;
 	}
 
 	if (cio_debug_initialized)
-		debug_int_event(cio_debug_trace_id, 4, retval);
+		debug_int_event (cio_debug_trace_id, 4, retval);
 
 	return retval;
 }
 
-
-int s390_request_irq( unsigned int   irq,
-                      void           (*handler)(int, void *, struct pt_regs *),
-                      unsigned long  irqflags,
-                      const char    *devname,
-                      void          *dev_id)
+int
+s390_request_irq (unsigned int irq,
+		  void (*handler) (int, void *, struct pt_regs *),
+		  unsigned long irqflags, const char *devname, void *dev_id)
 {
 	int ret;
 
-	ret = s390_request_irq_special( irq,
-                                   (io_handler_func_t)handler,
-                                   NULL,
-                                   irqflags,
-                                   devname,
-                                   dev_id);
+	ret = s390_request_irq_special (irq,
+					(io_handler_func_t) handler,
+					NULL, irqflags, devname, dev_id);
 
-	if ( ret == 0 )
-	{
+	if (ret == 0) {
 		ioinfo[irq]->ui.flags.newreq = 0;
 
-	} /* endif */
-
-	return( ret);
+	}
+	return (ret);
 }
 
-void s390_free_irq(unsigned int irq, void *dev_id)
+void
+s390_free_irq (unsigned int irq, void *dev_id)
 {
 	unsigned long flags;
-	int          ret;
+	int ret;
 
 	char dbf_txt[15];
 
-	if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
+	if (irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA)
 		return;
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "free%x", irq);
-		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-	}
+	if (ioinfo[irq]->st)
+		return;
 
-	s390irq_spin_lock_irqsave( irq, flags);
+	sprintf (dbf_txt, "free%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	s390irq_spin_lock_irqsave (irq, flags);
 
 #ifdef  CONFIG_KERNEL_DEBUG
-	if ( irq != cons_dev )
-		printk( KERN_DEBUG "Trying to free IRQ%d\n",irq);
+	if (irq != cons_dev)
+		printk (KERN_DEBUG "Trying to free IRQ%d\n", irq);
 #endif
-	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_msg_id, 2, "Trying to free IRQ %d\n", irq);
+	CIO_MSG_EVENT(2, "Trying to free IRQ %d\n", irq);
 
 	/*
 	 * disable the device and reset all IRQ info if
 	 *  the IRQ is actually owned by the handler ...
 	 */
-	if ( ioinfo[irq]->ui.flags.ready ) {
-		if ( dev_id == ioinfo[irq]->irq_desc.dev_id ) {
+	if (ioinfo[irq]->ui.flags.ready) {
+		if (dev_id == ioinfo[irq]->irq_desc.dev_id) {
 			/* start deregister */
 			ioinfo[irq]->ui.flags.unready = 1;
 
-			/*
-			 * Try to stop IO first...
-			 * ... it seems disable_subchannel is sometimes
-			 * successfully called with IO still pending.
-			 */
-			halt_IO( irq,
-				 0xC8C1D3E3,
-				 DOIO_WAIT_FOR_INTERRUPT );
+			ret = disable_subchannel (irq);
 
-				ret = disable_subchannel( irq);
+			if (ret == -EBUSY) {
 
-			if ( ret == -EBUSY ) {
-
-					/*
-					 * kill it !
-					 * ... we first try sync and eventually
-					 *  try terminating the current I/O by
-					 *  an async request, twice halt, then
-					 *  clear.
-					 */
-				ret = halt_IO( irq,
-						                0xC8C1D3E3,
-						                DOIO_WAIT_FOR_INTERRUPT );
-   	
-				if ( ret == -EBUSY ) {
-							halt_IO( irq, 0xC8C1D3E3, 0);
-							s390irq_spin_unlock_irqrestore( irq, flags);
-							udelay( 200000 ); /* 200 ms */
-							s390irq_spin_lock_irqsave( irq, flags);
+				/*
+				 * kill it !
+				 * We try to terminate the I/O by halt_IO first,
+				 * then clear_IO.
+				 * Because the device may be gone (machine 
+				 * check handling), we can't use sync I/O.
+				 */
 
-						} /* endif */
-				
-				ret = disable_subchannel(irq);
+				halt_IO (irq, 0xC8C1D3E3, 0);
+				s390irq_spin_unlock_irqrestore (irq, flags);
+				udelay (200000);	/* 200 ms */
+				s390irq_spin_lock_irqsave (irq, flags);
+				ret = disable_subchannel (irq);
 
 				if (ret == -EBUSY) {
-   	
-					clear_IO( irq, 0x40C3D3D9,0 );
-							s390irq_spin_unlock_irqrestore( irq, flags);
-							udelay( 1000000 ); /* 1000 ms */
-							s390irq_spin_lock_irqsave( irq, flags);
-
-						/* give it a very last try ... */
-						disable_subchannel( irq);
-
-					if ( ioinfo[irq]->ui.flags.busy ) {
-							printk( KERN_CRIT"free_irq(%04X) "
-							       "- device %04X busy, retry "
-							       "count exceeded\n",
-								irq,
-								ioinfo[irq]->devstat.devno);
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 0,
-										    "free_irq(%04X) - device %04X busy, retry count exceeded\n",
-										    irq, ioinfo[irq]->devstat.devno);
 
-						} /* endif */
+					clear_IO (irq, 0x40C3D3D9, 0);
+					s390irq_spin_unlock_irqrestore (irq,
+									flags);
+					udelay (1000000);	/* 1000 ms */
+					s390irq_spin_lock_irqsave (irq, flags);
+
+					/* give it a very last try ... */
+					disable_subchannel (irq);
+
+					if (ioinfo[irq]->ui.flags.busy) {
+						printk (KERN_CRIT
+							"free_irq(%04X) "
+							"- device %04X busy, retry "
+							"count exceeded\n", irq,
+							ioinfo[irq]->devstat.
+							devno);
+						CIO_MSG_EVENT( 0,
+							       "free_irq(%04X) - "
+							       "device %04X busy, "
+							       "retry count exceeded\n",
+							       irq,
+							       ioinfo[irq]->
+							       devstat.devno);
 						
-					} /* endif */
+					}
+				}
+			}
 
-				} /* endif */
-		
-			ioinfo[irq]->ui.flags.ready   = 0;
-			ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
+			ioinfo[irq]->ui.flags.ready = 0;
+			ioinfo[irq]->ui.flags.unready = 0;	/* deregister ended */
 
 			ioinfo[irq]->nopfunc = NULL;
 
-			s390irq_spin_unlock_irqrestore( irq, flags);
+			s390irq_spin_unlock_irqrestore (irq, flags);
 		} else {
-			s390irq_spin_unlock_irqrestore( irq, flags);
+			s390irq_spin_unlock_irqrestore (irq, flags);
 
-			printk( KERN_ERR "free_irq(%04X) : error, "
-			        "dev_id does not match !\n", irq);
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 0, 
-						    "free_irq(%04X) : error, dev_id does not match !\n", irq);
+			printk (KERN_ERR "free_irq(%04X) : error, "
+				"dev_id does not match !\n", irq);
+			CIO_MSG_EVENT( 0,
+				       "free_irq(%04X) : error, "
+				       "dev_id does not match !\n",
+				       irq);
 
-		} /* endif */
+		}
 	} else {
-		s390irq_spin_unlock_irqrestore( irq, flags);
-
-		printk( KERN_ERR "free_irq(%04X) : error, "
-		        "no action block ... !\n", irq);
-		if (cio_debug_initialized)
-			debug_sprintf_event(cio_debug_msg_id, 0,
-					    "free_irq(%04X) : error, no action block ... !\n", irq);
+		s390irq_spin_unlock_irqrestore (irq, flags);
 
-	} /* endif */
+		printk (KERN_ERR "free_irq(%04X) : error, "
+			"no action block ... !\n", irq);
+		CIO_MSG_EVENT(0,
+			      "free_irq(%04X) : error, "
+			      "no action block ... !\n", irq);
 
+	}
 }
 
 /*
  * Generic enable/disable code
  */
-int disable_irq(unsigned int irq)
+int
+disable_irq (unsigned int irq)
 {
 	unsigned long flags;
-	int           ret;
+	int ret;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( !ioinfo[irq]->ui.flags.ready )
+	if (!ioinfo[irq]->ui.flags.ready)
 		return -ENODEV;
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "disirq%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "dirq%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	s390irq_spin_lock_irqsave(irq, flags);
-	ret = disable_subchannel(irq);
-	s390irq_spin_unlock_irqrestore(irq, flags);
+	s390irq_spin_lock_irqsave (irq, flags);
+	ret = disable_subchannel (irq);
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-	synchronize_irq();
+	synchronize_irq ();
 
-	if (cio_debug_initialized) 
-		debug_int_event(cio_debug_trace_id, 4, ret);
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	return( ret);
+	return (ret);
 }
 
-int enable_irq(unsigned int irq)
+int
+enable_irq (unsigned int irq)
 {
 	unsigned long flags;
-	int           ret;
+	int ret;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( !ioinfo[irq]->ui.flags.ready )
+	if (!ioinfo[irq]->ui.flags.ready)
 		return -ENODEV;
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "enirq%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "eirq%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	s390irq_spin_lock_irqsave(irq, flags);
-	ret = enable_subchannel(irq);
-	s390irq_spin_unlock_irqrestore(irq, flags);
+	s390irq_spin_lock_irqsave (irq, flags);
+	ret = enable_subchannel (irq);
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-	if (cio_debug_initialized) 
-		debug_int_event(cio_debug_trace_id, 4, ret);
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	return(ret);
+	return (ret);
 }
 
 /*
  * Enable IRQ by modifying the subchannel
  */
-static int enable_subchannel( unsigned int irq)
+static int
+enable_subchannel (unsigned int irq)
 {
-	int   ret = 0;
-	int   ccode;
-	int   retry = 5;
+	int ret = 0;
+	int ccode;
+	int retry = 5;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "ensch%x", irq);
-		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-	}
+	sprintf (dbf_txt, "esch%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
 	/*
 	 * If a previous disable request is pending we reset it. However, this
 	 *  status implies that the device may (still) be not-operational.
 	 */
-	if (  ioinfo[irq]->ui.flags.d_disable )
-	{
+	if (ioinfo[irq]->ui.flags.d_disable) {
 		ioinfo[irq]->ui.flags.d_disable = 0;
-		ret                             = 0;
-	}
-	else
-	{
-		ccode = stsch(irq, &(ioinfo[irq]->schib) );
+		ret = 0;
+	} else {
+		ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-		if ( ccode )
-		{
+		if (ccode) {
 			ret = -ENODEV;
-		}
-		else
-		{
+		} else {
 			ioinfo[irq]->schib.pmcw.ena = 1;
 
-			if ( irq == cons_dev )
-			{
+			if (irq == cons_dev) {
 				ioinfo[irq]->schib.pmcw.isc = 7;
-			}
-			else	
-			{
+			} else {
 				ioinfo[irq]->schib.pmcw.isc = 3;
 
-			} /* endif */
+			}
 
-			do
-			{
-				ccode = msch( irq, &(ioinfo[irq]->schib) );
+			do {
+				ccode = msch (irq, &(ioinfo[irq]->schib));
 
 				switch (ccode) {
-				case 0: /* ok */
+				case 0:	/* ok */
 					ret = 0;
 					retry = 0;
 					break;
 
-				case 1: /* status pending */
+				case 1:	/* status pending */
 
 					ioinfo[irq]->ui.flags.s_pend = 1;
-					s390_process_IRQ( irq );
+					s390_process_IRQ (irq);
 					ioinfo[irq]->ui.flags.s_pend = 0;
 
-					ret = -EIO;    /* might be overwritten */
-					               /* ... on re-driving    */
-					               /* ... the msch()       */
+					ret = -EIO;
+					/* 
+					 * might be overwritten on re-driving 
+					 * the msch()       
+					 */
 					retry--;
 					break;
 
-				case 2: /* busy */
-					udelay(100);	/* allow for recovery */
+				case 2:	/* busy */
+					udelay (100);	/* allow for recovery */
 					ret = -EBUSY;
 					retry--;
 					break;
 
-				case 3: /* not oper */
+				case 3:	/* not oper */
 					ioinfo[irq]->ui.flags.oper = 0;
 					retry = 0;
 					ret = -ENODEV;
 					break;
 				}
 
-			} while ( retry );
-
-		} /* endif */
+			} while (retry);
 
-	}  /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"ret:%d",ret);
-		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+		}
 	}
 
-	return( ret );
-}
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
+	return (ret);
+}
 
 /*
  * Disable IRQ by modifying the subchannel
  */
-static int disable_subchannel( unsigned int irq)
+static int
+disable_subchannel (unsigned int irq)
 {
-	int  cc;          /* condition code */
-	int  ret = 0;     /* function return value */
-	int  retry = 5;
+	int cc;			/* condition code */
+	int ret = 0;		/* function return value */
+	int retry = 5;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
-	
-	if ( ioinfo[irq]->ui.flags.busy )
-	{
+	SANITY_CHECK (irq);
+
+	sprintf (dbf_txt, "dsch%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	if (ioinfo[irq]->ui.flags.busy) {
 		/*
 		 * the disable function must not be called while there are
 		 *  requests pending for completion !
 		 */
 		ret = -EBUSY;
-	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "dissch%x", irq);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}
-		
+	} else {
+
 		/*
 		 * If device isn't operational we have to perform delayed
 		 *  disabling when the next interrupt occurs - unless the
 		 *  irq is re-requested prior to the interrupt to occur.
 		 */
-		cc = stsch(irq, &(ioinfo[irq]->schib) );
+		cc = stsch (irq, &(ioinfo[irq]->schib));
 
-		if ( cc == 3 )
-		{
-			ioinfo[irq]->ui.flags.oper      = 0;
+		if (cc == 3) {
+			ioinfo[irq]->ui.flags.oper = 0;
 			ioinfo[irq]->ui.flags.d_disable = 1;
 
 			ret = 0;
-		}
-		else // cc == 0
-		{
+		} else {	/* cc == 0 */
+
 			ioinfo[irq]->schib.pmcw.ena = 0;
 
-			do
-			{
-				cc = msch( irq, &(ioinfo[irq]->schib) );
+			do {
+				cc = msch (irq, &(ioinfo[irq]->schib));
 
 				switch (cc) {
-				case 0: /* ok */
+				case 0:	/* ok */
 					retry = 0;
-					ret = 0;   
+					ret = 0;
 					break;
 
-				case 1: /* status pending */
+				case 1:	/* status pending */
 					ioinfo[irq]->ui.flags.s_pend = 1;
-					s390_process_IRQ( irq );
+					s390_process_IRQ (irq);
 					ioinfo[irq]->ui.flags.s_pend = 0;
 
-					ret = -EIO; /* might be overwritten  */
-					            /* ... on re-driving the */
-					            /* ... msch() call       */
+					ret = -EIO;
+					/* 
+					 * might be overwritten on re-driving 
+					 * the msch() call       
+					 */
 					retry--;
 					break;
 
-				case 2: /* busy; this should not happen! */
-					printk( KERN_CRIT"disable_subchannel(%04X) "
-					        "- unexpected busy condition for "
-						"device %04X received !\n",
-					        irq,
-					        ioinfo[irq]->devstat.devno);
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 0, 
-								    "disable_subchannel(%04X) - unexpected busy condition for device %04X received !\n",
-								    irq, ioinfo[irq]->devstat.devno);
+				case 2:	/* busy; this should not happen! */
+					printk (KERN_CRIT
+						"disable_subchannel(%04X) "
+						"- unexpected busy condition for "
+						"device %04X received !\n", irq,
+						ioinfo[irq]->devstat.devno);
+					CIO_MSG_EVENT(0,
+						      "disable_subchannel(%04X) "
+						      "- unexpected busy condition "
+						      "for device %04X received !\n",
+						      irq,
+						      ioinfo[irq]->devstat.
+						      devno);
 					retry = 0;
 					ret = -EBUSY;
 					break;
 
-				case 3: /* not oper */
+				case 3:	/* not oper */
 					/*
 					 * should hardly occur ?!
 					 */
-					ioinfo[irq]->ui.flags.oper      = 0;
+					ioinfo[irq]->ui.flags.oper = 0;
 					ioinfo[irq]->ui.flags.d_disable = 1;
 					retry = 0;
 
-					ret = 0; /* if the device has gone we */
-					         /* ... don't need to disable */
-					         /* ... it anymore !          */
+					ret = 0;
+					/* 
+					 * if the device has gone, we don't need 
+					 * to disable it anymore !          
+					 */
 					break;
 
-				} /* endswitch */
-
-			} while ( retry );
-
-		} /* endif */
+				}
 
-	} /* endif */
+			} while (retry);
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "ret:%d",ret);
-		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+		}
 	}
 
-	return( ret);
-}
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
+	return (ret);
+}
 
-void s390_init_IRQ( void )
+void
+s390_init_IRQ (void)
 {
-	unsigned long flags;     /* PSW flags */
-	long          cr6 __attribute__ ((aligned (8)));
+	unsigned long flags;	/* PSW flags */
+	long cr6 __attribute__ ((aligned (8)));
 
-	asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
+	asm volatile ("STCK %0":"=m" (irq_IPL_TOD));
+
+	p_init_schib = alloc_bootmem_low (sizeof (schib_t));
+	p_init_irb = alloc_bootmem_low (sizeof (irb_t));
 
-	p_init_schib = alloc_bootmem_low( sizeof(schib_t));
-	p_init_irb   = alloc_bootmem_low( sizeof(irb_t));
-	
-	
 	/*
 	 * As we don't know about the calling environment
 	 *  we assure running disabled. Before leaving the
@@ -1218,96 +1382,103 @@
 	 *        we shouldn't use cli(), but __cli() as this
 	 *        affects the current CPU only.
 	 */
-	__save_flags(flags);
-	__cli();
+	__save_flags (flags);
+	__cli ();
 
 	/*
 	 * disable all interrupts
 	 */
 	cr6 = 0;
-	__ctl_load( cr6, 6, 6);
+	__ctl_load (cr6, 6, 6);
 
-	s390_process_subchannels();
+	s390_process_subchannels ();
 
 	if (cio_count_irqs) {
 		int i;
-		for (i=0; i<NR_CPUS; i++) 
-			s390_irq_count[i]=0;
+		for (i = 0; i < NR_CPUS; i++)
+			s390_irq_count[i] = 0;
 	}
 
+	
+	/*
+	 * Let's build our path group ID here.
+	 */
+	
+	global_pgid = (pgid_t *)alloc_bootmem(sizeof(pgid_t));
+
+	global_pgid->cpu_addr = *(__u16 *) __LC_CPUADDR;
+	global_pgid->cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
+	global_pgid->cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
+	global_pgid->tod_high = *(__u32 *) & irq_IPL_TOD;
+
+
 	/*
 	 * enable default I/O-interrupt sublass 3
 	 */
 	cr6 = 0x10000000;
-	__ctl_load( cr6, 6, 6);
+	__ctl_load (cr6, 6, 6);
 
-	s390_device_recognition_all();
+	s390_device_recognition_all ();
 
 	init_IRQ_complete = 1;
 
-	__restore_flags(flags);
+	__restore_flags (flags);
 
 	return;
 }
 
-
 /*
  * dummy handler, used during init_IRQ() processing for compatibility only
  */
-void  init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs)
+void
+init_IRQ_handler (int irq, void *dev_id, struct pt_regs *regs)
 {
-   /* this is a dummy handler only ... */
+	/* this is a dummy handler only ... */
 }
 
-
-int s390_start_IO( int            irq,      /* IRQ */
-                   ccw1_t        *cpa,      /* logical channel prog addr */
-                   unsigned long  user_intparm,  /* interruption parameter */
-                   __u8           lpm,      /* logical path mask */
-                   unsigned long  flag)     /* flags */
-{
-	int            ccode;
-	int            ret = 0;
+int
+s390_start_IO (int irq,		/* IRQ */
+	       ccw1_t * cpa,	/* logical channel prog addr */
+	       unsigned long user_intparm,	/* interruption parameter */
+	       __u8 lpm,	/* logical path mask */
+	       unsigned long flag)
+{				/* flags */
+	int ccode;
+	int ret = 0;
 	char buffer[80];
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
 	/*
 	 * The flag usage is mutal exclusive ...
 	 */
-	if (    (flag & DOIO_EARLY_NOTIFICATION)
-	     && (flag & DOIO_REPORT_ALL     ) )
-	{
-		return( -EINVAL );
-
-	} /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "stIO%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	if ((flag & DOIO_EARLY_NOTIFICATION)
+	    && (flag & DOIO_REPORT_ALL)) {
+		return (-EINVAL);
+
 	}
 
+	sprintf (dbf_txt, "stIO%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
 	/*
 	 * setup ORB
 	 */
-  	ioinfo[irq]->orb.intparm = (__u32)(long)&ioinfo[irq]->u_intparm;
-	ioinfo[irq]->orb.fmt     = 1;
+	ioinfo[irq]->orb.intparm = (__u32) (long) &ioinfo[irq]->u_intparm;
+	ioinfo[irq]->orb.fmt = 1;
 
 	ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
-	ioinfo[irq]->orb.spnd =  (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE);
-	ioinfo[irq]->orb.ssic =  (    (flag & DOIO_ALLOW_SUSPEND )
-	                           && (flag & DOIO_SUPPRESS_INTER) );
+	ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE);
+	ioinfo[irq]->orb.ssic = ((flag & DOIO_ALLOW_SUSPEND)
+				 && (flag & DOIO_SUPPRESS_INTER));
 
-	if ( flag & DOIO_VALID_LPM )
-	{
+	if (flag & DOIO_VALID_LPM) {
 		ioinfo[irq]->orb.lpm = lpm;
-	}
-	else
-	{
+	} else {
 		ioinfo[irq]->orb.lpm = ioinfo[irq]->opm;
 
-	} /* endif */
+	}
 
 #ifdef CONFIG_ARCH_S390X
 	/* 
@@ -1317,72 +1488,64 @@
 	ioinfo[irq]->orb.i2k = 0;
 #endif
 
-	ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);
+	ioinfo[irq]->orb.cpa = (__u32) virt_to_phys (cpa);
 
 	/*
 	 * If sync processing was requested we lock the sync ISC, modify the
 	 *  device to present interrupts for this ISC only and switch the
 	 *  CPU to handle this ISC + the console ISC exclusively.
 	 */
-	if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-	{
-		ret = enable_cpu_sync_isc( irq);
-	
-		if ( ret )
-		{
-			return( ret);
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		ret = enable_cpu_sync_isc (irq);
+
+		if (ret) {
+			return (ret);
 		}
 
-	} /* endif */
+	}
 
-	if ( flag & DOIO_DONT_CALL_INTHDLR )
-	{
+	if (flag & DOIO_DONT_CALL_INTHDLR) {
 		ioinfo[irq]->ui.flags.repnone = 1;
 
-	} /* endif */
+	}
 
 	/*
 	 * Issue "Start subchannel" and process condition code
 	 */
-	ccode = ssch( irq, &(ioinfo[irq]->orb) );
+	ccode = ssch (irq, &(ioinfo[irq]->orb));
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "ccode:%d", ccode);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	switch ( ccode ) {
+	switch (ccode) {
 	case 0:
 
-		if ( !ioinfo[irq]->ui.flags.w4sense )
-		{
+		if (!ioinfo[irq]->ui.flags.w4sense) {
 			/*
 			 * init the device driver specific devstat irb area
 			 *
 			 * Note : don´t clear saved irb info in case of sense !
 			 */
-			memset( &((devstat_t *)ioinfo[irq]->irq_desc.dev_id)->ii.irb,
-				'\0', sizeof( irb_t) );
-		} /* endif */
-
-		memset( &ioinfo[irq]->devstat.ii.irb,
-		        '\0',
-		        sizeof( irb_t) );
+			memset (&((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->
+				ii.irb, '\0', sizeof (irb_t));
+		}
+
+		memset (&ioinfo[irq]->devstat.ii.irb, '\0', sizeof (irb_t));
 
 		/*
 		 * initialize device status information
 		 */
-		ioinfo[irq]->ui.flags.busy   = 1;
-		ioinfo[irq]->ui.flags.doio   = 1;
+		ioinfo[irq]->ui.flags.busy = 1;
+		ioinfo[irq]->ui.flags.doio = 1;
 
-		ioinfo[irq]->u_intparm       = user_intparm;
-		ioinfo[irq]->devstat.cstat   = 0;
-		ioinfo[irq]->devstat.dstat   = 0;
-		ioinfo[irq]->devstat.lpum    = 0;
-		ioinfo[irq]->devstat.flag    = DEVSTAT_START_FUNCTION;
-		ioinfo[irq]->devstat.scnt    = 0;
+		ioinfo[irq]->u_intparm = user_intparm;
+		ioinfo[irq]->devstat.cstat = 0;
+		ioinfo[irq]->devstat.dstat = 0;
+		ioinfo[irq]->devstat.lpum = 0;
+		ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION;
+		ioinfo[irq]->devstat.scnt = 0;
 
-		ioinfo[irq]->ui.flags.fast   = 0;
+		ioinfo[irq]->ui.flags.fast = 0;
 		ioinfo[irq]->ui.flags.repall = 0;
 
 		/*
@@ -1390,15 +1553,12 @@
 		 *  or if we are to return all interrupt info.
 		 * Default is to call IRQ handler at secondary status only
 		 */
-		if ( flag & DOIO_EARLY_NOTIFICATION )
-		{
+		if (flag & DOIO_EARLY_NOTIFICATION) {
 			ioinfo[irq]->ui.flags.fast = 1;
-		}
-		else if ( flag & DOIO_REPORT_ALL )
-		{
+		} else if (flag & DOIO_REPORT_ALL) {
 			ioinfo[irq]->ui.flags.repall = 1;
 
-		} /* endif */
+		}
 
 		ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;
 
@@ -1410,17 +1570,15 @@
 		 *  for the first interrupt, but must poll until ours
 		 *  pops up.
 		 */
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			unsigned long    psw_mask;
-			int              ccode;
-			uint64_t         time_start;    	
-			uint64_t         time_curr;    	
-
-			int              ready    = 0;
-			int              io_sub   = -1;
-			struct _lowcore *lc       = NULL;
-			int              do_retry = 1;
+		if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+			unsigned long psw_mask;
+			int ccode;
+			uint64_t time_start;
+			uint64_t time_curr;
+
+			int ready = 0;
+			int io_sub = -1;
+			int do_retry = 1;
 
 			/*
 			 * We shouldn't perform a TPI loop, waiting for an
@@ -1431,104 +1589,100 @@
 			 *  its original value.
 			 */
 
-			ccode = iac();
+			ccode = iac ();
 
 			switch (ccode) {
-			case 0:  		// primary-space
+			case 0:	/* primary-space */
 				psw_mask = _IO_PSW_MASK
 				    | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
 				break;
-			case 1:			// secondary-space
+			case 1:	/* secondary-space */
 				psw_mask = _IO_PSW_MASK
 				    | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
 				break;
-			case 2:			// access-register
+			case 2:	/* access-register */
 				psw_mask = _IO_PSW_MASK
 				    | _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
 				break;
-			case 3:			// home-space	
+			case 3:	/* home-space */
 				psw_mask = _IO_PSW_MASK
 				    | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
 				break;
 			default:
-				panic( "start_IO() : unexpected "
-				       "address-space-control %d\n",
-				       ccode);
+				panic ("start_IO() : unexpected "
+				       "address-space-control %d\n", ccode);
 				break;
-			} /* endswitch */
+			}
 
 			/*
 			 * Martin didn't like modifying the new PSW, now we take
 			 *  a fast exit in do_IRQ() instead
 			 */
-			*(__u32 *)__LC_SYNC_IO_WORD  = 1;
+			*(__u32 *) __LC_SYNC_IO_WORD = 1;
 
-			asm volatile ("STCK %0" : "=m" (time_start));
+			asm volatile ("STCK %0":"=m" (time_start));
 
 			time_start = time_start >> 32;
 
-			do
-			{
-				if ( flag & DOIO_TIMEOUT )
-				{
-					tpi_info_t tpi_info={0,};
+			do {
+				if (flag & DOIO_TIMEOUT) {
+					tpi_info_t tpi_info = { 0, };
 
-					do
-					{
-						if ( tpi(&tpi_info) == 1 )
-						{
+					do {
+						if (tpi (&tpi_info) == 1) {
 							io_sub = tpi_info.irq;
 							break;
-						}
-						else
-						{
-							udelay(100); /* usecs */
-							asm volatile ("STCK %0" : "=m" (time_curr));
+						} else {
+							udelay (100);	/* usecs */
+							asm volatile
+							 ("STCK %0":"=m"
+							  (time_curr));
+
+							if (((time_curr >> 32) -
+							     time_start) >= 3)
+								do_retry = 0;
 
-							if ( ((time_curr >> 32) - time_start ) >= 3 )
-								do_retry = 0;          							
+						}
 
-						} /* endif */
-				
-					} while ( do_retry );
-				}
-				else
-				{
-					__load_psw_mask( psw_mask );
+					} while (do_retry);
+				} else {
+					__load_psw_mask (psw_mask);
 
-					io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
+					io_sub =
+					    (__u32) *
+					    (__u16 *) __LC_SUBCHANNEL_NR;
 
-				} /* endif */
+				}
 
- 				if ( do_retry )
-					ready = s390_process_IRQ( io_sub );
+				if (do_retry)
+					ready = s390_process_IRQ (io_sub);
 
 				/*
 				 * surrender when retry count's exceeded ...
 				 */
-			} while ( !(     ( io_sub == irq )
-			              && ( ready  == 1   ))
-			            && do_retry             );
+			} while (!((io_sub == irq)
+				   && (ready == 1))
+				 && do_retry);
 
-			*(__u32 *)__LC_SYNC_IO_WORD = 0;
+			*(__u32 *) __LC_SYNC_IO_WORD = 0;
 
-			if ( !do_retry )
+			if (!do_retry)
 				ret = -ETIMEDOUT;
 
-		} /* endif */
+		}
 
 		break;
 
-	case 1 :            /* status pending */
+	case 1:		/* status pending */
 
-		ioinfo[irq]->devstat.flag =   DEVSTAT_START_FUNCTION
-		                            | DEVSTAT_STATUS_PENDING;
+		ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION
+		    | DEVSTAT_STATUS_PENDING;
 
 		/*
 		 * initialize the device driver specific devstat irb area
 		 */
-		memset( &((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->ii.irb,
-		        '\0', sizeof( irb_t) );
+		memset (&((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->ii.irb,
+			'\0', sizeof (irb_t));
 
 		/*
 		 * Let the common interrupt handler process the pending status.
@@ -1538,20 +1692,20 @@
 		 *  must terminate synchronously - especially if device sensing
 		 *  is required.
 		 */
-		ioinfo[irq]->ui.flags.s_pend   = 1;
-		ioinfo[irq]->ui.flags.busy     = 1;
-		ioinfo[irq]->ui.flags.doio     = 1;
-
-		s390_process_IRQ( irq );
+		ioinfo[irq]->ui.flags.s_pend = 1;
+		ioinfo[irq]->ui.flags.busy = 1;
+		ioinfo[irq]->ui.flags.doio = 1;
+
+		s390_process_IRQ (irq);
+
+		ioinfo[irq]->ui.flags.s_pend = 0;
+		ioinfo[irq]->ui.flags.busy = 0;
+		ioinfo[irq]->ui.flags.doio = 0;
 
-		ioinfo[irq]->ui.flags.s_pend   = 0;
-		ioinfo[irq]->ui.flags.busy     = 0;
-		ioinfo[irq]->ui.flags.doio     = 0;
-
-		ioinfo[irq]->ui.flags.repall   = 0;
-		ioinfo[irq]->ui.flags.w4final  = 0;
+		ioinfo[irq]->ui.flags.repall = 0;
+		ioinfo[irq]->ui.flags.w4final = 0;
 
-		ioinfo[irq]->devstat.flag     |= DEVSTAT_FINAL_STATUS;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
 
 		/*
 		 * In multipath mode a condition code 3 implies the last path
@@ -1560,225 +1714,216 @@
 		 *  results in return code EIO as well as 3 with another path
 		 *  than the one used (i.e. path available mask is non-zero).
 		 */
-		if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
-		{
-			if ( flag & DOIO_VALID_LPM )
-			{
-				ioinfo[irq]->opm &= ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum);
-			}
-			else
-			{
+		if (ioinfo[irq]->devstat.ii.irb.scsw.cc == 3) {
+			if (flag & DOIO_VALID_LPM) {
+				ioinfo[irq]->opm &=
+				    ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.
+				      lpum);
+			} else {
 				ioinfo[irq]->opm = 0;
 
-			} /* endif */
-	
-			if ( ioinfo[irq]->opm == 0 ) 	
-			{
-				ret                         = -ENODEV;
-				ioinfo[irq]->ui.flags.oper  = 0;
 			}
-			else
-			{
+
+			if (ioinfo[irq]->opm == 0) {
+				ret = -ENODEV;
+				ioinfo[irq]->ui.flags.oper = 0;
+			} else {
 				ret = -EIO;
 
-			} /* endif */
+			}
 
-			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
+			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
 
 #ifdef CONFIG_DEBUG_IO
 			{
 
-			stsch(irq, &(ioinfo[irq]->schib) );
+				stsch (irq, &(ioinfo[irq]->schib));
 
-			sprintf( buffer, "s390_start_IO(%04X) - irb for "
-			         "device %04X, after status pending\n",
-			         irq,
-			         ioinfo[irq]->devstat.devno );
-
-			s390_displayhex( buffer,
-			                 &(ioinfo[irq]->devstat.ii.irb) ,
-			                 sizeof(irb_t));
+				sprintf (buffer,
+					 "s390_start_IO(%04X) - irb for "
+					 "device %04X, after status pending\n",
+					 irq, ioinfo[irq]->devstat.devno);
 
-			sprintf( buffer, "s390_start_IO(%04X) - schib for "
-			         "device %04X, after status pending\n",
-			         irq,
-			         ioinfo[irq]->devstat.devno );
+				s390_displayhex (buffer,
+						 &(ioinfo[irq]->devstat.ii.irb),
+						 sizeof (irb_t));
 
-			s390_displayhex( buffer,
-			                 &(ioinfo[irq]->schib) ,
-			                 sizeof(schib_t));
+				sprintf (buffer,
+					 "s390_start_IO(%04X) - schib for "
+					 "device %04X, after status pending\n",
+					 irq, ioinfo[irq]->devstat.devno);
 
+				s390_displayhex (buffer,
+						 &(ioinfo[irq]->schib),
+						 sizeof (schib_t));
+
+				if (ioinfo[irq]->devstat.
+				    flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+					sprintf (buffer,
+						 "s390_start_IO(%04X) "
+						 "- sense data for device %04X,"
+						 " after status pending\n",
+						 irq,
+						 ioinfo[irq]->devstat.devno);
 
-			if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL)
-			{
-				sprintf( buffer, "s390_start_IO(%04X) - sense "
-				         "data for "
-				         "device %04X, after status pending\n",
-				         irq,
-				         ioinfo[irq]->devstat.devno );
-
-				s390_displayhex( buffer,
-					ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
-					ioinfo[irq]->irq_desc.dev_id->rescnt);
+					s390_displayhex (buffer,
+							 ioinfo[irq]->irq_desc.
+							 dev_id->ii.sense.data,
+							 ioinfo[irq]->irq_desc.
+							 dev_id->rescnt);
 
-			} /* endif */
+				}
 			}
 #endif
 			if (cio_debug_initialized) {
-				stsch(irq, &(ioinfo[irq]->schib) );
-				
-				sprintf( buffer, "s390_start_IO(%04X) - irb for "
+				stsch (irq, &(ioinfo[irq]->schib));
+
+				sprintf (buffer,
+					 "s390_start_IO(%04X) - irb for "
 					 "device %04X, after status pending\n",
-					 irq,
-					 ioinfo[irq]->devstat.devno );
-				
-				s390_displayhex2( buffer,
-						 &(ioinfo[irq]->devstat.ii.irb) ,
-						 sizeof(irb_t), 2);
-				
-				sprintf( buffer, "s390_start_IO(%04X) - schib for "
+					 irq, ioinfo[irq]->devstat.devno);
+
+				s390_displayhex2 (buffer,
+						  &(ioinfo[irq]->devstat.ii.
+						    irb), sizeof (irb_t), 2);
+
+				sprintf (buffer,
+					 "s390_start_IO(%04X) - schib for "
 					 "device %04X, after status pending\n",
-					 irq,
-					 ioinfo[irq]->devstat.devno );
-				
-				s390_displayhex2( buffer,
-						 &(ioinfo[irq]->schib) ,
-						 sizeof(schib_t), 2);
-				
-				
-				if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) {
-					sprintf( buffer, "s390_start_IO(%04X) - sense "
-						 "data for "
-						 "device %04X, after status pending\n",
+					 irq, ioinfo[irq]->devstat.devno);
+
+				s390_displayhex2 (buffer,
+						  &(ioinfo[irq]->schib),
+						  sizeof (schib_t), 2);
+
+				if (ioinfo[irq]->devstat.
+				    flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+					sprintf (buffer,
+						 "s390_start_IO(%04X) "
+						 "- sense data for device %04X,"
+						 " after status pending\n",
 						 irq,
-						 ioinfo[irq]->devstat.devno );
-					
-					s390_displayhex2( buffer,
-							  ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
-							  ioinfo[irq]->irq_desc.dev_id->rescnt, 2);
-					
-				} /* endif */
+						 ioinfo[irq]->devstat.devno);
+
+					s390_displayhex2 (buffer,
+							  ioinfo[irq]->irq_desc.
+							  dev_id->ii.sense.data,
+							  ioinfo[irq]->irq_desc.
+							  dev_id->rescnt, 2);
+
+				}
 			}
-		}
-		else
-		{
-			ret                         = -EIO;
-			ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
-			ioinfo[irq]->ui.flags.oper  = 1;
+		} else {
+			ret = -EIO;
+			ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
+			ioinfo[irq]->ui.flags.oper = 1;
 
-		} /* endif */
+		}
 
 		break;
 
-	case 2 :            /* busy */
+	case 2:		/* busy */
 
 		ret = -EBUSY;
 		break;
 
-	default:            /* device/path not operational */
-		
-		if ( flag & DOIO_VALID_LPM )
-		{
+	default:		/* device/path not operational */
+
+		if (flag & DOIO_VALID_LPM) {
 			ioinfo[irq]->opm &= ~lpm;
-		}
-		else
-		{
+		} else {
 			ioinfo[irq]->opm = 0;
 
-		} /* endif */
-	
-		if ( ioinfo[irq]->opm == 0 ) 	
-		{
-			ioinfo[irq]->ui.flags.oper  = 0;
-			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
+		}
 
-		} /* endif */
+		if (ioinfo[irq]->opm == 0) {
+			ioinfo[irq]->ui.flags.oper = 0;
+			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
 
-		ret = -ENODEV;
+		}
 
-		memcpy( ioinfo[irq]->irq_desc.dev_id,
-		        &(ioinfo[irq]->devstat),
-		        sizeof( devstat_t) );
+		ret = -ENODEV;
 
+		memcpy (ioinfo[irq]->irq_desc.dev_id,
+			&(ioinfo[irq]->devstat), sizeof (devstat_t));
 
 #ifdef CONFIG_DEBUG_IO
 
-   			stsch(irq, &(ioinfo[irq]->schib) );
+		stsch (irq, &(ioinfo[irq]->schib));
+
+		sprintf (buffer, "s390_start_IO(%04X) - schib for "
+			 "device %04X, after 'not oper' status\n",
+			 irq, ioinfo[irq]->devstat.devno);
 
-			sprintf( buffer, "s390_start_IO(%04X) - schib for "
-			         "device %04X, after 'not oper' status\n",
-			         irq,
-			         ioinfo[irq]->devstat.devno );
-
-			s390_displayhex( buffer,
-			                 &(ioinfo[irq]->schib),
-			                 sizeof(schib_t));
+		s390_displayhex (buffer,
+				 &(ioinfo[irq]->schib), sizeof (schib_t));
 #endif
 		if (cio_debug_initialized) {
-			stsch(irq, &(ioinfo[irq]->schib) );
+			stsch (irq, &(ioinfo[irq]->schib));
 
-			sprintf( buffer, "s390_start_IO(%04X) - schib for "
-			         "device %04X, after 'not oper' status\n",
-			         irq,
-			         ioinfo[irq]->devstat.devno );
-
-			s390_displayhex2( buffer,
-			                 &(ioinfo[irq]->schib),
-			                 sizeof(schib_t), 2);
+			sprintf (buffer, "s390_start_IO(%04X) - schib for "
+				 "device %04X, after 'not oper' status\n",
+				 irq, ioinfo[irq]->devstat.devno);
+
+			s390_displayhex2 (buffer,
+					  &(ioinfo[irq]->schib),
+					  sizeof (schib_t), 2);
 		}
-			
+
 		break;
 
-	} /* endswitch */
+	}
 
-	if ( flag & DOIO_WAIT_FOR_INTERRUPT)
-	{
-		disable_cpu_sync_isc( irq );
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		disable_cpu_sync_isc (irq);
 
-	} /* endif */
+	}
 
-	if ( flag & DOIO_DONT_CALL_INTHDLR )
-	{
+	if (flag & DOIO_DONT_CALL_INTHDLR) {
 		ioinfo[irq]->ui.flags.repnone = 0;
 
-   } /* endif */
+	}
 
-	return( ret);
+	return (ret);
 }
 
-int do_IO( int            irq,          /* IRQ */
-           ccw1_t        *cpa,          /* channel program address */
-           unsigned long  user_intparm, /* interruption parameter */
-           __u8           lpm,          /* logical path mask */
-           unsigned long  flag)         /* flags : see above */
-{
+int
+do_IO (int irq,			/* IRQ */
+       ccw1_t * cpa,		/* channel program address */
+       unsigned long user_intparm,	/* interruption parameter */
+       __u8 lpm,		/* logical path mask */
+       unsigned long flag)
+{				/* flags : see above */
 	int ret = 0;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
 	/* handler registered ? or free_irq() in process already ? */
-	if ( !ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready )
-	{
-		return( -ENODEV );
-
-	} /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "doIO%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	if (!ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready) {
+		return (-ENODEV);
+
 	}
 
+	sprintf (dbf_txt, "doIO%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
 	/*
 	 * Note: We ignore the device operational status - if not operational,
 	 *        the SSCH will lead to an -ENODEV condition ...
 	 */
-	if ( !ioinfo[irq]->ui.flags.busy )         /* last I/O completed ? */
-	{
-		ret = s390_start_IO( irq, cpa, user_intparm, lpm, flag);
-	}
-	else if ( ioinfo[irq]->ui.flags.fast )
-	{
+	if (!ioinfo[irq]->ui.flags.busy) {	/* last I/O completed ? */
+		ret = s390_start_IO (irq, cpa, user_intparm, lpm, flag);
+		if ((ret == -ETIMEDOUT) && (flag & DOIO_CANCEL_ON_TIMEOUT)) {
+			/*
+			 * We should better cancel the io request here
+			 * or we might not be able to do io on this sch
+			 * again
+			 */
+			cancel_IO (irq);
+		}
+
+	} else if (ioinfo[irq]->ui.flags.fast) {
 		/*
 		 * If primary status was received and ending status is missing,
 		 *  the device driver won't be notified on the ending status
@@ -1788,92 +1933,81 @@
 		 *  needs to be issued and the queued request must be deleted
 		 *  but its intparm must be returned (see halt_IO() processing)
 		 */
-		if (     ioinfo[irq]->ui.flags.w4final
-		      && !ioinfo[irq]->ui.flags.doio_q )
-		{
-			ioinfo[irq]->qflag    = flag;
-			ioinfo[irq]->qcpa     = cpa;
+		if (ioinfo[irq]->ui.flags.w4final
+		    && !ioinfo[irq]->ui.flags.doio_q) {
+			ioinfo[irq]->qflag = flag;
+			ioinfo[irq]->qcpa = cpa;
 			ioinfo[irq]->qintparm = user_intparm;
-			ioinfo[irq]->qlpm     = lpm;
-		}
-		else
-		{
+			ioinfo[irq]->qlpm = lpm;
+		} else {
 			ret = -EBUSY;
 
-		} /* endif */
-	}
-	else
-	{
+		}
+	} else {
 		ret = -EBUSY;
 
-	} /* endif */
+	}
 
-	return( ret );
+	return (ret);
 
 }
 
 /*
  * resume suspended I/O operation
  */
-int resume_IO( int irq)
+int
+resume_IO (int irq)
 {
 	int ret = 0;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "resIO%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "rsIO%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/*
 	 * We allow for 'resume' requests only for active I/O operations
 	 */
-	if ( ioinfo[irq]->ui.flags.busy )
-	{
+	if (ioinfo[irq]->ui.flags.busy) {
 		int ccode;
 
-		ccode = rsch( irq);
+		ccode = rsch (irq);
 
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "ccode:%d",ccode);
-			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-		}
+		sprintf (dbf_txt, "ccode:%d", ccode);
+		CIO_TRACE_EVENT (4, dbf_txt);
 
 		switch (ccode) {
-		case 0 :
+		case 0:
 			break;
 
-		case 1 :
-		  	s390_process_IRQ( irq );
+		case 1:
+			s390_process_IRQ (irq);
 			ret = -EBUSY;
 			break;
 
-		case 2 :
+		case 2:
 			ret = -EINVAL;
 			break;
 
-		case 3 :
+		case 3:
 			/*
 			 * useless to wait for request completion
 			 *  as device is no longer operational !
 			 */
 			ioinfo[irq]->ui.flags.oper = 0;
 			ioinfo[irq]->ui.flags.busy = 0;
-			ret                        = -ENODEV;
+			ret = -ENODEV;
 			break;
 
-		} /* endswitch */          	
-		
-	}
-	else
-	{
+		}
+
+	} else {
 		ret = -ENOTCONN;
 
-	} /* endif  */
+	}
 
-	return( ret);
+	return (ret);
 }
 
 /*
@@ -1882,247 +2016,218 @@
  *       it allows the device interrupt handler to associate the upcoming
  *       interrupt with the halt_IO() request.
  */
-int halt_IO( int           irq,
-             unsigned long user_intparm,
-             unsigned long flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
-	int            ret;
-	int            ccode;
+int
+halt_IO (int irq, unsigned long user_intparm, unsigned long flag)
+{				/* possible DOIO_WAIT_FOR_INTERRUPT */
+	int ret;
+	int ccode;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
 	/*
 	 * we only allow for halt_IO if the device has an I/O handler associated
 	 */
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		ret = -ENODEV;
+	if (!ioinfo[irq]->ui.flags.ready) {
+		return -ENODEV;
 	}
 	/*
 	 * we ignore the halt_io() request if ending_status was received but
 	 *  a SENSE operation is waiting for completion.
 	 */
-	else if ( ioinfo[irq]->ui.flags.w4sense )
-	{
-		ret = 0;
+	if (ioinfo[irq]->ui.flags.w4sense) {
+		return 0;
 	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "haltIO%x", irq);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}
-		/*
-		 * If sync processing was requested we lock the sync ISC,
-		 *  modify the device to present interrupts for this ISC only
-		 *  and switch the CPU to handle this ISC + the console ISC
-		 *  exclusively.
-		 */
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			ret = enable_cpu_sync_isc( irq);
-
-			if ( ret )
-			{
-				return( ret);
-  	
-			} /* endif */
+	CIO_TRACE_EVENT (2, "haltIO");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
-		} /* endif */
+	/*
+	 * If sync processing was requested we lock the sync ISC,
+	 *  modify the device to present interrupts for this ISC only
+	 *  and switch the CPU to handle this ISC + the console ISC
+	 *  exclusively.
+	 */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		ret = enable_cpu_sync_isc (irq);
 
-		/*
-		 * Issue "Halt subchannel" and process condition code
-		 */
-		ccode = hsch( irq );
+		if (ret)
+			return (ret);
+	}
 
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "ccode:%d",ccode);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}		
+	/*
+	 * Issue "Halt subchannel" and process condition code
+	 */
+	ccode = hsch (irq);
 
-		switch ( ccode ) {
-		case 0:
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
-			ioinfo[irq]->ui.flags.haltio = 1;
+	switch (ccode) {
+	case 0:
 
-			if ( !ioinfo[irq]->ui.flags.doio )
-			{
-				ioinfo[irq]->ui.flags.busy   = 1;
-				ioinfo[irq]->u_intparm       = user_intparm;
-				ioinfo[irq]->devstat.cstat   = 0;
-				ioinfo[irq]->devstat.dstat   = 0;
-				ioinfo[irq]->devstat.lpum    = 0;
-				ioinfo[irq]->devstat.flag    = DEVSTAT_HALT_FUNCTION;
-				ioinfo[irq]->devstat.scnt    = 0;
+		ioinfo[irq]->ui.flags.haltio = 1;
 
-			}
-			else
-			{
-				ioinfo[irq]->devstat.flag   |= DEVSTAT_HALT_FUNCTION;
+		if (!ioinfo[irq]->ui.flags.doio) {
+			ioinfo[irq]->ui.flags.busy = 1;
+			ioinfo[irq]->u_intparm = user_intparm;
+			ioinfo[irq]->devstat.cstat = 0;
+			ioinfo[irq]->devstat.dstat = 0;
+			ioinfo[irq]->devstat.lpum = 0;
+			ioinfo[irq]->devstat.flag = DEVSTAT_HALT_FUNCTION;
+			ioinfo[irq]->devstat.scnt = 0;
 
-			} /* endif */
+		} else {
+			ioinfo[irq]->devstat.flag |= DEVSTAT_HALT_FUNCTION;
 
-			/*
-			 * If synchronous I/O processing is requested, we have
-			 *  to wait for the corresponding interrupt to occur by
-			 *  polling the interrupt condition. However, as multiple
-			 *  interrupts may be outstanding, we must not just wait
-			 *  for the first interrupt, but must poll until ours
-			 *  pops up.
-			 */
-			if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-			{
-				int              io_sub;
-				__u32            io_parm;
-				unsigned long    psw_mask;
-				int              ccode;
-  	
-				int              ready = 0;
-				struct _lowcore *lc    = NULL;
+		}
 
-				/*
-				 * We shouldn't perform a TPI loop, waiting for
-				 *  an interrupt to occur, but should load a
-				 *  WAIT PSW instead. Otherwise we may keep the
-				 *  channel subsystem busy, not able to present
-				 *  the interrupt. When our sync. interrupt
-				 *  arrived we reset the I/O old PSW to its
-				 *  original value.
-				 */
+		/*
+		 * If synchronous I/O processing is requested, we have
+		 *  to wait for the corresponding interrupt to occur by
+		 *  polling the interrupt condition. However, as multiple
+		 *  interrupts may be outstanding, we must not just wait
+		 *  for the first interrupt, but must poll until ours
+		 *  pops up.
+		 */
+		if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+			int io_sub;
+			__u32 io_parm;
+			unsigned long psw_mask;
+			int ccode;
 
-				ccode = iac();
+			int ready = 0;
 
-				switch (ccode) {
-				case 0:  		// primary-space
-					psw_mask = _IO_PSW_MASK
-						| _PSW_PRIM_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 1:			// secondary-space
-					psw_mask = _IO_PSW_MASK
-						| _PSW_SEC_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 2:			// access-register
-					psw_mask = _IO_PSW_MASK
-						| _PSW_ACC_REG_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 3:			// home-space	
-					psw_mask = _IO_PSW_MASK
-						| _PSW_HOME_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				default:
-					panic( "halt_IO() : unexpected "
-					       "address-space-control %d\n",
-					       ccode);
-					break;
-				} /* endswitch */
+			/*
+			 * We shouldn't perform a TPI loop, waiting for
+			 *  an interrupt to occur, but should load a
+			 *  WAIT PSW instead. Otherwise we may keep the
+			 *  channel subsystem busy, not able to present
+			 *  the interrupt. When our sync. interrupt
+			 *  arrived we reset the I/O old PSW to its
+			 *  original value.
+			 */
 
-				/*
-				 * Martin didn't like modifying the new PSW, now we take
-				 *  a fast exit in do_IRQ() instead
-				 */
-				*(__u32 *)__LC_SYNC_IO_WORD  = 1;
+			ccode = iac ();
 
-				do
-				{
+			switch (ccode) {
+			case 0:	/* primary-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			case 1:	/* secondary-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			case 2:	/* access-register */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
+				break;
+			case 3:	/* home-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			default:
+				panic ("halt_IO() : unexpected "
+				       "address-space-control %d\n", ccode);
+				break;
+			}
 
-					__load_psw_mask( psw_mask );
+			/*
+			 * Martin didn't like modifying the new PSW, now we take
+			 *  a fast exit in do_IRQ() instead
+			 */
+			*(__u32 *) __LC_SYNC_IO_WORD = 1;
 
-				   io_parm = *(__u32 *)__LC_IO_INT_PARM;
-				   io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
+			do {
+				__load_psw_mask (psw_mask);
 
-				   ready = s390_process_IRQ( io_sub );
+				io_parm = *(__u32 *) __LC_IO_INT_PARM;
+				io_sub = (__u32) * (__u16 *) __LC_SUBCHANNEL_NR;
 
-				} while ( !((io_sub == irq) && (ready == 1)) );
+				ready = s390_process_IRQ (io_sub);
 
-				*(__u32 *)__LC_SYNC_IO_WORD = 0;
+			} while (!((io_sub == irq) && (ready == 1)));
 
-			} /* endif */
+			*(__u32 *) __LC_SYNC_IO_WORD = 0;
 
-			ret = 0;
-			break;
+		}
 
-		case 1 :            /* status pending */
-	
-			ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
+		ret = 0;
+		break;
 
-			/*
-			 * initialize the device driver specific devstat irb area
-			 */
-			memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb,
-			        '\0', sizeof( irb_t) );
+	case 1:		/* status pending */
 
-			/*
-			 * Let the common interrupt handler process the pending
-			 *  status. However, we must avoid calling the user
-			 *  action handler, as it won't be prepared to handle
-			 *  a pending status during do_IO() processing inline.
-			 *  This also implies that s390_process_IRQ must
-			 *  terminate synchronously - especially if device
-			 *  sensing is required.
-			 */
-			ioinfo[irq]->ui.flags.s_pend   = 1;
-			ioinfo[irq]->ui.flags.busy     = 1;
-			ioinfo[irq]->ui.flags.doio     = 1;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
 
-			s390_process_IRQ( irq );
-			
-			ioinfo[irq]->ui.flags.s_pend   = 0;
-			ioinfo[irq]->ui.flags.busy     = 0;
-			ioinfo[irq]->ui.flags.doio     = 0;
-			ioinfo[irq]->ui.flags.repall   = 0;
-			ioinfo[irq]->ui.flags.w4final  = 0;
+		/*
+		 * initialize the device driver specific devstat irb area
+		 */
+		memset (&ioinfo[irq]->irq_desc.dev_id->ii.irb,
+			'\0', sizeof (irb_t));
 
-			ioinfo[irq]->devstat.flag     |= DEVSTAT_FINAL_STATUS;
+		/*
+		 * Let the common interrupt handler process the pending
+		 *  status. However, we must avoid calling the user
+		 *  action handler, as it won't be prepared to handle
+		 *  a pending status during do_IO() processing inline.
+		 *  This also implies that s390_process_IRQ must
+		 *  terminate synchronously - especially if device
+		 *  sensing is required.
+		 */
+		ioinfo[irq]->ui.flags.s_pend = 1;
+		ioinfo[irq]->ui.flags.busy = 1;
+		ioinfo[irq]->ui.flags.doio = 1;
+
+		s390_process_IRQ (irq);
+
+		ioinfo[irq]->ui.flags.s_pend = 0;
+		ioinfo[irq]->ui.flags.busy = 0;
+		ioinfo[irq]->ui.flags.doio = 0;
+		ioinfo[irq]->ui.flags.repall = 0;
+		ioinfo[irq]->ui.flags.w4final = 0;
 
-			/*
-			 * In multipath mode a condition code 3 implies the last
-			 *  path has gone, except we have previously restricted
-			 *  the I/O to a particular path. A condition code 1
-			 *  (0 won't occur) results in return code EIO as well
-			 *  as 3 with another path than the one used (i.e. path available mask is non-zero).
-			 */
-			if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
-			{
-				ret                         = -ENODEV;
-				ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
-				ioinfo[irq]->ui.flags.oper  = 0;
-			}
-			else
-			{
-				ret                         = -EIO;
-				ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
-				ioinfo[irq]->ui.flags.oper  = 1;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
 
-			} /* endif */
+		/*
+		 * In multipath mode a condition code 3 implies the last
+		 *  path has gone, except we have previously restricted
+		 *  the I/O to a particular path. A condition code 1
+		 *  (0 won't occur) results in return code EIO as well
+		 *  as 3 with another path than the one used (i.e. path 
+		 *  available mask is non-zero).
+		 */
+		if (ioinfo[irq]->devstat.ii.irb.scsw.cc == 3) {
+			ret = -ENODEV;
+			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+			ioinfo[irq]->ui.flags.oper = 0;
+		} else {
+			ret = -EIO;
+			ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
+			ioinfo[irq]->ui.flags.oper = 1;
 
-			break;
+		}
 
-		case 2 :            /* busy */
+		break;
 
-			ret = -EBUSY;
-			break;
+	case 2:		/* busy */
 
-		default:            /* device not operational */
+		ret = -EBUSY;
+		break;
 
-			ret = -ENODEV;
-			break;
+	default:		/* device not operational */
 
-		} /* endswitch */
+		ret = -ENODEV;
+		break;
 
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			disable_cpu_sync_isc( irq );
+	}
 
-		} /* endif */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		disable_cpu_sync_isc (irq);
 
-	} /* endif */
+	}
 
-	return( ret );
+	return (ret);
 }
 
 /*
@@ -2131,201 +2236,220 @@
  *       it allows the device interrupt handler to associate the upcoming
  *       interrupt with the clear_IO() request.
  */
-int clear_IO( int           irq,
-              unsigned long user_intparm,
-              unsigned long flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
-	int            ret = 0;
-	int            ccode;
+int
+clear_IO (int irq, unsigned long user_intparm, unsigned long flag)
+{				/* possible DOIO_WAIT_FOR_INTERRUPT */
+	int ret = 0;
+	int ccode;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-   }
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return (-ENODEV);
 
 	/*
 	 * we only allow for clear_IO if the device has an I/O handler associated
 	 */
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		ret = -ENODEV;
-	}
+	if (!ioinfo[irq]->ui.flags.ready)
+		return -ENODEV;
 	/*
 	 * we ignore the clear_io() request if ending_status was received but
 	 *  a SENSE operation is waiting for completion.
 	 */
-	else if ( ioinfo[irq]->ui.flags.w4sense )
-	{
-		ret = 0;
-	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "clearIO%x", irq);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}
-		/*
-		 * If sync processing was requested we lock the sync ISC,
-		 *  modify the device to present interrupts for this ISC only
-		 *  and switch the CPU to handle this ISC + the console ISC
-		 *  exclusively.
-		 */
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			ret = enable_cpu_sync_isc( irq);
+	if (ioinfo[irq]->ui.flags.w4sense)
+		return 0;
 
-			if ( ret )
-			{
-				return( ret);
-  	
-			} /* endif */
+	CIO_TRACE_EVENT (2, "clearIO");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
-		} /* endif */
+	/*
+	 * If sync processing was requested we lock the sync ISC,
+	 *  modify the device to present interrupts for this ISC only
+	 *  and switch the CPU to handle this ISC + the console ISC
+	 *  exclusively.
+	 */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		ret = enable_cpu_sync_isc (irq);
 
-		/*
-		 * Issue "Clear subchannel" and process condition code
-		 */
-		ccode = csch( irq );
+		if (ret)
+			return (ret);
+	}
 
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "ccode:%d",ccode);
-			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
-		}
+	/*
+	 * Issue "Clear subchannel" and process condition code
+	 */
+	ccode = csch (irq);
 
-		switch ( ccode ) {
-		case 0:
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (2, dbf_txt);
 
-			ioinfo[irq]->ui.flags.haltio = 1;
+	switch (ccode) {
+	case 0:
 
-			if ( !ioinfo[irq]->ui.flags.doio )
-			{
-				ioinfo[irq]->ui.flags.busy   = 1;
-				ioinfo[irq]->u_intparm       = user_intparm;
-				ioinfo[irq]->devstat.cstat   = 0;
-				ioinfo[irq]->devstat.dstat   = 0;
-				ioinfo[irq]->devstat.lpum    = 0;
-				ioinfo[irq]->devstat.flag    = DEVSTAT_CLEAR_FUNCTION;
-				ioinfo[irq]->devstat.scnt    = 0;
+		ioinfo[irq]->ui.flags.haltio = 1;
 
-			}
-			else
-			{
-				ioinfo[irq]->devstat.flag   |= DEVSTAT_CLEAR_FUNCTION;
+		if (!ioinfo[irq]->ui.flags.doio) {
+			ioinfo[irq]->ui.flags.busy = 1;
+			ioinfo[irq]->u_intparm = user_intparm;
+			ioinfo[irq]->devstat.cstat = 0;
+			ioinfo[irq]->devstat.dstat = 0;
+			ioinfo[irq]->devstat.lpum = 0;
+			ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION;
+			ioinfo[irq]->devstat.scnt = 0;
+
+		} else {
+			ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION;
+
+		}
+
+		/*
+		 * If synchronous I/O processing is requested, we have
+		 *  to wait for the corresponding interrupt to occur by
+		 *  polling the interrupt condition. However, as multiple
+		 *  interrupts may be outstanding, we must not just wait
+		 *  for the first interrupt, but must poll until ours
+		 *  pops up.
+		 */
+		if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+			int io_sub;
+			__u32 io_parm;
+			unsigned long psw_mask;
+			int ccode;
 
-			} /* endif */
+			int ready = 0;
 
 			/*
-			 * If synchronous I/O processing is requested, we have
-			 *  to wait for the corresponding interrupt to occur by
-			 *  polling the interrupt condition. However, as multiple
-			 *  interrupts may be outstanding, we must not just wait
-			 *  for the first interrupt, but must poll until ours
-			 *  pops up.
+			 * We shouldn't perform a TPI loop, waiting for
+			 *  an interrupt to occur, but should load a
+			 *  WAIT PSW instead. Otherwise we may keep the
+			 *  channel subsystem busy, not able to present
+			 *  the interrupt. When our sync. interrupt
+			 *  arrived we reset the I/O old PSW to its
+			 *  original value.
 			 */
-			if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-			{
-				int              io_sub;
-				__u32            io_parm;
-				unsigned long    psw_mask;
-				int              ccode;
-  	
-				int              ready = 0;
-				struct _lowcore *lc    = NULL;
 
-				/*
-				 * We shouldn't perform a TPI loop, waiting for
-				 *  an interrupt to occur, but should load a
-				 *  WAIT PSW instead. Otherwise we may keep the
-				 *  channel subsystem busy, not able to present
-				 *  the interrupt. When our sync. interrupt
-				 *  arrived we reset the I/O old PSW to its
-				 *  original value.
-				 */
+			ccode = iac ();
+
+			switch (ccode) {
+			case 0:	/* primary-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			case 1:	/* secondary-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			case 2:	/* access-register */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
+				break;
+			case 3:	/* home-space */
+				psw_mask = _IO_PSW_MASK
+				    | _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
+				break;
+			default:
+				panic ("clear_IO() : unexpected "
+				       "address-space-control %d\n", ccode);
+				break;
+			}
 
-				ccode = iac();
+			/*
+			 * Martin didn't like modifying the new PSW, now we take
+			 *  a fast exit in do_IRQ() instead
+			 */
+			*(__u32 *) __LC_SYNC_IO_WORD = 1;
 
-				switch (ccode) {
-				case 0:  		// primary-space
-					psw_mask = _IO_PSW_MASK
-						| _PSW_PRIM_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 1:			// secondary-space
-					psw_mask = _IO_PSW_MASK
-						| _PSW_SEC_SPACE_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 2:			// access-register
-					psw_mask = _IO_PSW_MASK
-						| _PSW_ACC_REG_MODE
-						| _PSW_IO_WAIT;
-					break;
-				case 3:			// home-space	
-					psw_mask =   _IO_PSW_MASK
-					        | _PSW_HOME_SPACE_MODE
-					        | _PSW_IO_WAIT;
-					break;
-				default:
-					panic( "clear_IO() : unexpected "
-					       "address-space-control %d\n",
-					       ccode);
-					break;
-				} /* endswitch */
+			do {
+				__load_psw_mask (psw_mask);
 
-				/*
-				 * Martin didn't like modifying the new PSW, now we take
-				 *  a fast exit in do_IRQ() instead
-				 */
-				*(__u32 *)__LC_SYNC_IO_WORD  = 1;
+				io_parm = *(__u32 *) __LC_IO_INT_PARM;
+				io_sub = (__u32) * (__u16 *) __LC_SUBCHANNEL_NR;
 
-				do
-				{
-					__load_psw_mask( psw_mask );
+				ready = s390_process_IRQ (io_sub);
 
-				   io_parm = *(__u32 *)__LC_IO_INT_PARM;
-				   io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
+			} while (!((io_sub == irq) && (ready == 1)));
 
-				   ready = s390_process_IRQ( io_sub );
+			*(__u32 *) __LC_SYNC_IO_WORD = 0;
 
-				} while ( !((io_sub == irq) && (ready == 1)) );
+		}
 
-				*(__u32 *)__LC_SYNC_IO_WORD = 0;
+		ret = 0;
+		break;
 
-			} /* endif */
+	case 1:		/* no status pending for csh */
+		BUG ();
+		break;
 
-			ret = 0;
-			break;
+	case 2:		/* no busy for csh */
+		BUG ();
+		break;
 
-		case 1 :            /* no status pending for csh */
-			BUG();
-			break;
+	default:		/* device not operational */
 
+		ret = -ENODEV;
+		break;
 
-		case 2 :            /* no busy for csh*/
-			BUG();
-			break;
+	}
 
-		default:            /* device not operational */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		disable_cpu_sync_isc (irq);
 
-			ret = -ENODEV;
-			break;
+	}
 
-		} /* endswitch */
+	return (ret);
+}
 
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			disable_cpu_sync_isc( irq );
+/*
+ * Function: cancel_IO
+ * Issues a "Cancel Subchannel" on the specified subchannel
+ * Note: We don't need any fancy intparms and flags here
+ *       since xsch is executed synchronously.
+ * Only for common I/O internal use as for now.
+ */
+int
+cancel_IO (int irq)
+{
 
-		} /* endif */
+	int ccode;
+	char dbf_txt[15];
+	int ret = 0;
 
-	} /* endif */
+	SANITY_CHECK (irq);
 
-	return( ret );
-}
+	CIO_TRACE_EVENT (2, "cancelIO");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	ccode = xsch (irq);
+
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	switch (ccode) {
+
+	case 0:		/* success */
+		ret = 0;
+		break;
+
+	case 1:		/* status pending */
+
+		/* process the pending irq... */
+		s390_process_IRQ (irq);
+		ret = -EBUSY;
+		break;
+
+	case 2:		/* not applicable */
+		ret = -EINVAL;
+		break;
+
+	default:		/* not oper */
+		ret = -ENODEV;
+	}
 
+	return ret;
+}
 
 /*
  * do_IRQ() handles all normal I/O device IRQ's (the special
@@ -2333,13 +2457,14 @@
  *          handlers).
  *
  */
-asmlinkage void do_IRQ( struct pt_regs regs )
+asmlinkage void
+do_IRQ (struct pt_regs regs)
 {
 	/*
 	 * Get interrupt info from lowcore
 	 */
-	volatile tpi_info_t *tpi_info = (tpi_info_t*)(__LC_SUBCHANNEL_ID);
-	int cpu = smp_processor_id();
+	volatile tpi_info_t *tpi_info = (tpi_info_t *) (__LC_SUBCHANNEL_ID);
+	int cpu = smp_processor_id ();
 
 	/*
 	 * take fast exit if CPU is in sync. I/O state
@@ -2348,30 +2473,26 @@
 	 *       interrupts prior to return as this was the initial
 	 *       entry condition to synchronous I/O.
 	 */
- 	if (    *(__u32 *)__LC_SYNC_IO_WORD )
-	{
+	if (*(__u32 *) __LC_SYNC_IO_WORD) {
 		regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
 		return;
-	} /* endif */
-
+	}
+	/* endif */
 #ifdef CONFIG_FAST_IRQ
 	do {
-#endif /*  CONFIG_FAST_IRQ */
-		
+#endif				/* CONFIG_FAST_IRQ */
+
 		/*
 		 * Non I/O-subchannel thin interrupts are processed differently
 		 */
-		if ( tpi_info->adapter_IO == 1 &&
-		     tpi_info->int_type == IO_INTERRUPT_TYPE )
-		{
-			irq_enter(cpu, -1);
-			do_adapter_IO( tpi_info->intparm );
-			irq_exit(cpu, -1);
-		} 
-		else 
-		{
+		if (tpi_info->adapter_IO == 1 &&
+		    tpi_info->int_type == IO_INTERRUPT_TYPE) {
+			irq_enter (cpu, -1);
+			do_adapter_IO (tpi_info->intparm);
+			irq_exit (cpu, -1);
+		} else {
 			unsigned int irq = tpi_info->irq;
-	
+
 			/*
 			 * fix me !!!
 			 *
@@ -2379,16 +2500,22 @@
 			 * recognition, the interrupt stays pending. We need to
 			 * dynamically allocate an ioinfo structure, etc..
 			 */
-			if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-			{
+			if (ioinfo[irq] == INVALID_STORAGE_AREA) {
 				return;	/* this keeps the device boxed ... */
 			}
-	
-			irq_enter(cpu, irq);
-			s390irq_spin_lock( irq );
-			s390_process_IRQ( irq );
-			s390irq_spin_unlock( irq );
-			irq_exit(cpu, irq);
+
+			if (ioinfo[irq]->st) {
+				/* How can that be? */
+				printk(KERN_WARNING "Received interrupt on "
+				       "non-IO subchannel %x!\n", irq);
+				return;
+			}
+
+			irq_enter (cpu, irq);
+			s390irq_spin_lock (irq);
+			s390_process_IRQ (irq);
+			s390irq_spin_unlock (irq);
+			irq_exit (cpu, irq);
 		}
 
 #ifdef CONFIG_FAST_IRQ
@@ -2398,14 +2525,13 @@
 		 * If so, the tpi instruction will update the lowcore 
 		 * to hold the info for the next interrupt.
 		 */
-	} while ( tpi( NULL ) != 0 );
+	} while (tpi (NULL) != 0);
 
-#endif /*  CONFIG_FAST_IRQ */
+#endif				/* CONFIG_FAST_IRQ */
 
 	return;
 }
 
-
 /*
  * s390_process_IRQ() handles status pending situations and interrupts
  *
@@ -2417,48 +2543,58 @@
  * Returns: 0 - no ending status received, no further action taken
  *          1 - interrupt handler was called with ending status
  */
-int s390_process_IRQ( unsigned int irq )
+int
+s390_process_IRQ (unsigned int irq)
 {
-	int                    ccode;      /* cond code from tsch() operation */
-	int                    irb_cc;     /* cond code from irb */
-	int                    sdevstat;   /* struct devstat size to copy */
-	unsigned int           fctl;       /* function control */
-	unsigned int           stctl;      /* status   control */
-	unsigned int           actl;       /* activity control */
-
-	int               issense         = 0;
-	int               ending_status   = 0;
-	int               allow4handler   = 1;
-	int               chnchk          = 0;
-	devstat_t        *dp;
-	devstat_t        *udp;
+	int ccode;		/* cond code from tsch() operation */
+	int irb_cc;		/* cond code from irb */
+	int sdevstat;		/* struct devstat size to copy */
+	unsigned int fctl;	/* function control */
+	unsigned int stctl;	/* status   control */
+	unsigned int actl;	/* activity control */
+
+	int issense = 0;
+	int ending_status = 0;
+	int allow4handler = 1;
+	int chnchk = 0;
+	devstat_t *dp;
+	devstat_t *udp;
 
 	char dbf_txt[15];
-	char buffer[80];
-
+	char buffer[256];
 
 	if (cio_count_irqs) {
-		int cpu = smp_processor_id();
+		int cpu = smp_processor_id ();
 		s390_irq_count[cpu]++;
 	}
-	
-	
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "procIRQ%x", irq);
-		debug_text_event(cio_debug_trace_id, 3, dbf_txt);
-	}
 
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
+	CIO_TRACE_EVENT (3, "procIRQ");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (3, dbf_txt);
+
+	if (ioinfo[irq] == INVALID_STORAGE_AREA) {
 		/* we can't properly process the interrupt ... */
-		tsch( irq, p_init_irb );
-		return( 1 );
+#ifdef CONFIG_DEBUG_IO
+		printk (KERN_CRIT "s390_process_IRQ(%04X) - got interrupt "
+			"for non-initialized subchannel!\n", irq);
+#endif /* CONFIG_DEBUG_IO */
+		CIO_MSG_EVENT (0,
+			       "s390_process_IRQ(%04X) - got interrupt "
+			       "for non-initialized subchannel!\n",
+			       irq);
+		tsch (irq, p_init_irb);
+		return (1);
+
+	}
 
-	} /* endif */
+	if (ioinfo[irq]->st) {
+		/* can't be */
+		BUG();
+		return 1;
+	}
 
-	dp  = &ioinfo[irq]->devstat;
+	dp = &ioinfo[irq]->devstat;
 	udp = ioinfo[irq]->irq_desc.dev_id;
-	
 
 	/*
 	 * It might be possible that a device was not-oper. at the time
@@ -2466,24 +2602,23 @@
 	 *  available when the device possibly becomes ready again. In
 	 *  this case we perform delayed disable_subchannel() processing.
 	 */
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		if ( !ioinfo[irq]->ui.flags.d_disable )
-		{
+	if (!ioinfo[irq]->ui.flags.ready) {
+		if (!ioinfo[irq]->ui.flags.d_disable) {
 #ifdef CONFIG_DEBUG_IO
-			printk( KERN_CRIT"s390_process_IRQ(%04X) "
-			        "- no interrupt handler registered "
-					  "for device %04X !\n",
-			        irq,
-			        ioinfo[irq]->devstat.devno);
-#endif /* CONFIG_DEBUG_IO */
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 0,
-						    "s390_process_IRQ(%04X) - no interrupt handler registered for device %04X !\n",
-						    irq, ioinfo[irq]->devstat.devno);
-		} /* endif */
-
-	} /* endif */
+			printk (KERN_CRIT "s390_process_IRQ(%04X) "
+				"- no interrupt handler registered "
+				"for device %04X !\n",
+				irq, ioinfo[irq]->devstat.devno);
+#endif				/* CONFIG_DEBUG_IO */
+			CIO_MSG_EVENT(0,
+				      "s390_process_IRQ(%04X) "
+				      "- no interrupt handler "
+				      "registered for device "
+				      "%04X !\n",
+				      irq,
+				      ioinfo[irq]->devstat.devno);
+		}
+	}
 
 	/*
 	 * retrieve the i/o interrupt information (irb),
@@ -2503,204 +2638,194 @@
 	 *         issued for an idle device, the intparm must not
 	 *         be taken from lowcore, but from the devstat area.
 	 */
-	ccode = tsch( irq, &(dp->ii.irb) );
+	ccode = tsch (irq, &(dp->ii.irb));
+
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (3, dbf_txt);
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "ccode:%d", ccode);
-		debug_text_event(cio_debug_trace_id, 3, dbf_txt);
+	if (ccode == 1) {
+#ifdef CONFIG_DEBUG_IO
+		printk (KERN_INFO "s390_process_IRQ(%04X) - no status "
+			 "pending...\n", irq);
+#endif /* CONFIG_DEBUG_IO */
+		CIO_MSG_EVENT(2,
+			      "s390_process_IRQ(%04X) - no status pending\n",
+			      irq);
+	} else if (ccode == 3) {
+#ifdef CONFIG_DEBUG_IO
+		printk (KERN_WARNING "s390_process_IRQ(%04X) - subchannel "
+			"is not operational!\n",
+			irq);
+#endif /* CONFIG_DEBUG_IO */
+		CIO_MSG_EVENT(0,
+			      "s390_process_IRQ(%04X) - subchannel "
+			      "is not operational!\n",
+			      irq);
 	}
 
-	//
-	// We must only accumulate the status if the device is busy already
-	//
-	if ( ioinfo[irq]->ui.flags.busy )
-	{
-		dp->dstat   |= dp->ii.irb.scsw.dstat;
-		dp->cstat   |= dp->ii.irb.scsw.cstat;
-                dp->intparm  = ioinfo[irq]->u_intparm;
+	/*
+	 * We must only accumulate the status if the device is busy already
+	 */
+	if (ioinfo[irq]->ui.flags.busy) {
+		dp->dstat |= dp->ii.irb.scsw.dstat;
+		dp->cstat |= dp->ii.irb.scsw.cstat;
+		dp->intparm = ioinfo[irq]->u_intparm;
 
-	}
-	else
-	{
-		dp->dstat    = dp->ii.irb.scsw.dstat;
-		dp->cstat    = dp->ii.irb.scsw.cstat;
+	} else {
+		dp->dstat = dp->ii.irb.scsw.dstat;
+		dp->cstat = dp->ii.irb.scsw.cstat;
 
-		dp->flag     = 0;   // reset status flags
-		dp->intparm  = 0;
+		dp->flag = 0;	/* reset status flags */
+		dp->intparm = 0;
 
-	} /* endif */
+	}
 
 	dp->lpum = dp->ii.irb.esw.esw1.lpum;
 
 	/*
 	 * reset device-busy bit if no longer set in irb
 	 */
-	if (    (dp->dstat & DEV_STAT_BUSY                   ) 
-	     && ((dp->ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))
-	{
+	if ((dp->dstat & DEV_STAT_BUSY)
+	    && ((dp->ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0)) {
 		dp->dstat &= ~DEV_STAT_BUSY;
 
-	} /* endif */
+	}
 
 	/*
-	 * Save residual count and CCW information in case primary and
-	 *  secondary status are presented with different interrupts.
+	   * Save residual count and CCW information in case primary and
+	   *  secondary status are presented with different interrupts.
 	 */
-	if ( dp->ii.irb.scsw.stctl
-	     & ( SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) ) {
+	if (dp->ii.irb.scsw.stctl
+	    & (SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS)) {
 
 		/*
 		 * If the subchannel status shows status pending
 		 * and we received a check condition, the count
 		 * information is not meaningful.
 		 */
-		
-		 if ( !(    (dp->ii.irb.scsw.stctl & SCSW_STCTL_STATUS_PEND) 
-			 && (   dp->ii.irb.scsw.cstat 
-			      & (   SCHN_STAT_CHN_DATA_CHK
-				  | SCHN_STAT_CHN_CTRL_CHK
-				  | SCHN_STAT_INTF_CTRL_CHK
-				  | SCHN_STAT_PROG_CHECK
-				  | SCHN_STAT_PROT_CHECK
-				  | SCHN_STAT_CHAIN_CHECK )))) {
-
-			 dp->rescnt = dp->ii.irb.scsw.count;
-		 } else {
-			 dp->rescnt = SENSE_MAX_COUNT;
-		 }
 
-		dp->cpa    = dp->ii.irb.scsw.cpa;
+		if (!((dp->ii.irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)
+		      && (dp->ii.irb.scsw.cstat
+			  & (SCHN_STAT_CHN_DATA_CHK
+			     | SCHN_STAT_CHN_CTRL_CHK
+			     | SCHN_STAT_INTF_CTRL_CHK
+			     | SCHN_STAT_PROG_CHECK
+			     | SCHN_STAT_PROT_CHECK
+			     | SCHN_STAT_CHAIN_CHECK)))) {
 
-#ifdef CONFIG_DEBUG_IO
-		if ( irq != cons_dev )
-			printk( KERN_DEBUG "s390_process_IRQ( %04X ) : "
-			        "residual count from irb after tsch() %d\n",
-			        irq, dp->rescnt );
-#endif
-		if (cio_debug_initialized)
-			debug_sprintf_event(cio_debug_msg_id, 6,
-					    "s390_process_IRQ( %04X ) : residual count from irq after tsch() %d\n",
-					    irq, dp->rescnt);
+			dp->rescnt = dp->ii.irb.scsw.count;
+		} else {
+			dp->rescnt = SENSE_MAX_COUNT;
+		}
 
-	} /* endif */
+		dp->cpa = dp->ii.irb.scsw.cpa;
 
+	}
 	irb_cc = dp->ii.irb.scsw.cc;
 
-	//
-	// check for any kind of channel or interface control check but don't
-	//  issue the message for the console device
-	//
-	if (    (dp->ii.irb.scsw.cstat
-	            & (  SCHN_STAT_CHN_DATA_CHK
-	               | SCHN_STAT_CHN_CTRL_CHK
-			 | SCHN_STAT_INTF_CTRL_CHK )))
-	{
+	/*
+	 * check for any kind of channel or interface control check but don't
+	 * issue the message for the console device
+	 */
+	if ((dp->ii.irb.scsw.cstat
+	     & (SCHN_STAT_CHN_DATA_CHK
+		| SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK))) {
 		if (irq != cons_dev)
-			printk( KERN_WARNING "Channel-Check or Interface-Control-Check "
+			printk (KERN_WARNING
+				"Channel-Check or Interface-Control-Check "
 				"received\n"
 				" ... device %04X on subchannel %04X, dev_stat "
 				": %02X sch_stat : %02X\n",
-				ioinfo[irq]->devstat.devno,
-				irq,
-				dp->dstat,
+				ioinfo[irq]->devstat.devno, irq, dp->dstat,
 				dp->cstat);
-		if (cio_debug_initialized) {
-			debug_sprintf_event(cio_debug_msg_id, 0,
-					    "Channel-Check or Interface-Control-Check received\n");
-			debug_sprintf_event(cio_debug_msg_id, 0,
-					    "... device %04X on subchannel %04X, dev_stat: %02X sch_stat: %02X\n",
-					    ioinfo[irq]->devstat.devno, irq, dp->dstat, dp->cstat);
-		}
+		CIO_MSG_EVENT(0,
+			      "Channel-Check or "
+			      "Interface-Control-Check received\n");
+		CIO_MSG_EVENT(0,
+			      "... device %04X on subchannel %04X,"
+			      " dev_stat: %02X sch_stat: %02X\n",
+			      ioinfo[irq]->devstat.devno, irq,
+			      dp->dstat, dp->cstat);
+	
 
 		chnchk = 1;
 
-	} /* endif */
+	}
 
-	if( dp->ii.irb.scsw.ectl==0)
-	{
-		issense=0;
-	}
-	else if (    (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND)
-	          && (dp->ii.irb.scsw.eswf  == 0                     ))
-	{
+	if (dp->ii.irb.scsw.ectl == 0) {
 		issense = 0;
-	}
-	else if (   (dp->ii.irb.scsw.stctl ==
-		      (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) 
-		 && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0)  )
-	{
+	} else if ((dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND)
+		   && (dp->ii.irb.scsw.eswf == 0)) {
 		issense = 0;
-	}
-	else
-	{
+	} else if ((dp->ii.irb.scsw.stctl ==
+		    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS))
+		   && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0)) {
+		issense = 0;
+	} else {
 		issense = dp->ii.irb.esw.esw0.erw.cons;
 
-	} /* endif */
+	}
 
-	if ( issense )
-	{
-		dp->scnt  = dp->ii.irb.esw.esw0.erw.scnt;
+	if (issense) {
+		dp->scnt = dp->ii.irb.esw.esw0.erw.scnt;
 		dp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
-                  	
-		sdevstat = sizeof( devstat_t);
+
+		sdevstat = sizeof (devstat_t);
 
 #ifdef CONFIG_DEBUG_IO
-		if ( irq != cons_dev )
-			printk( KERN_DEBUG "s390_process_IRQ( %04X ) : "
-			        "concurrent sense bytes avail %d\n",
-			        irq, dp->scnt );
-#endif
-		if (cio_debug_initialized)
-			debug_sprintf_event(cio_debug_msg_id, 4,
-					    "s390_process_IRQ( %04X ): concurrent sense bytes avail %d\n",
-					    irq, dp->scnt);
-	}
-	else
-	{
+		if (irq != cons_dev)
+			printk (KERN_DEBUG "s390_process_IRQ( %04X ) : "
+				"concurrent sense bytes avail %d\n",
+				irq, dp->scnt);
+#endif
+		CIO_MSG_EVENT(4,
+			      "s390_process_IRQ( %04X ): "
+			      "concurrent sense bytes avail %d\n",
+			      irq, dp->scnt);
+	} else {
 		/* don't copy the sense data area ! */
-		sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;
+		sdevstat = sizeof (devstat_t) - SENSE_MAX_COUNT;
 
-	} /* endif */
+	}
 
-	switch ( irb_cc ) {
-	case 1:      /* status pending */
+	switch (irb_cc) {
+	case 1:		/* status pending */
 
 		dp->flag |= DEVSTAT_STATUS_PENDING;
 
-	case 0:      /* normal i/o interruption */
+	case 0:		/* normal i/o interruption */
 
-		fctl  = dp->ii.irb.scsw.fctl;
+		fctl = dp->ii.irb.scsw.fctl;
 		stctl = dp->ii.irb.scsw.stctl;
-		actl  = dp->ii.irb.scsw.actl;
+		actl = dp->ii.irb.scsw.actl;
 
-		if ( chnchk )
-		{
-			sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
-			         "device %04X after channel check\n",
-			         irq,
-			         dp->devno );
-
-			s390_displayhex( buffer,
-			                 &(dp->ii.irb) ,
-			                 sizeof(irb_t));
+		if (chnchk) {
+			sprintf (buffer, "s390_process_IRQ(%04X) - irb for "
+				 "device %04X after channel check "
+				 "or interface control check\n",
+				 irq, dp->devno);
+
+			s390_displayhex (buffer, &(dp->ii.irb), sizeof (irb_t));
 			if (cio_debug_initialized) {
-				
-				sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
-			         "device %04X after channel check\n",
-			         irq,
-			         dp->devno );
-
-				s390_displayhex2( buffer,
-						  &(dp->ii.irb) ,
-						  sizeof(irb_t), 0);
+
+				sprintf (buffer,
+					 "s390_process_IRQ(%04X) - irb for "
+					 "device %04X after channel check "
+					 "or interface control check\n",
+					 irq, dp->devno);
+
+				s390_displayhex2 (buffer,
+						  &(dp->ii.irb),
+						  sizeof (irb_t), 0);
 			}
-		} /* endif */
-			
+		}
+
 		ioinfo[irq]->stctl |= stctl;
 
-		ending_status =    ( stctl & SCSW_STCTL_SEC_STATUS )
-			        || ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND) )
-			        || ( stctl == SCSW_STCTL_STATUS_PEND);
+		ending_status = (stctl & SCSW_STCTL_SEC_STATUS)
+		    || (stctl ==
+			(SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))
+		    || (stctl == SCSW_STCTL_STATUS_PEND);
 
 		/*
 		 * Check for unsolicited interrupts - for debug purposes only
@@ -2713,53 +2838,48 @@
 		 *       unsolicited interrupt applies to the console device
 		 *       itself !
 		 */
-		if (    !( stctl & SCSW_STCTL_ALERT_STATUS )
-		     &&  ( ioinfo[irq]->ui.flags.busy == 0 ) )
-		{
+		if (!(stctl & SCSW_STCTL_ALERT_STATUS)
+		    && (ioinfo[irq]->ui.flags.busy == 0)) {
 #ifdef CONFIG_DEBUG_IO
 			if (irq != cons_dev)
-				printk( KERN_INFO "Unsolicited interrupt received for device %04X on subchannel %04X\n"
-					" ... device status : %02X subchannel status : %02X\n",
-					dp->devno,
-					irq,
-					dp->dstat,
-					dp->cstat);
-			
-			sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
-			         "device %04X, ending_status %d\n",
-			         irq,
-			         dp->devno,
-			         ending_status);
-
-			s390_displayhex( buffer,
-			                 &(dp->ii.irb) ,
-			                 sizeof(irb_t));
-#endif
+				printk (KERN_INFO
+					"Unsolicited interrupt received for "
+					"device %04X on subchannel %04X\n"
+					" ... device status : %02X "
+					"subchannel status : %02X\n",
+					dp->devno, irq, dp->dstat, dp->cstat);
+
+			sprintf (buffer, "s390_process_IRQ(%04X) - irb for "
+				 "device %04X, ending_status %d\n",
+				 irq, dp->devno, ending_status);
+
+			s390_displayhex (buffer, &(dp->ii.irb), sizeof (irb_t));
+#endif
+			CIO_MSG_EVENT(2,
+				      "Unsolicited interrupt "
+				      "received for device %04X "
+				      "on subchannel %04X\n"
+				      " ... device status : %02X "
+				      "subchannel status : %02X\n",
+				      dp->devno,
+				      irq, dp->dstat, dp->cstat);
 			if (cio_debug_initialized) {
-				debug_sprintf_event(cio_debug_msg_id, 2, 
-						    "Unsolicited interrupt received for device %04X on subchannel %04X\n"
-						    " ... device status : %02X subchannel status : %02X\n",
-						    dp->devno,
-						    irq,
-						    dp->dstat,
-						    dp->cstat);
-				sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
-					 "device %04X, ending_status %d\n",
-					 irq,
-					 dp->devno,
-					 ending_status);
+				sprintf (buffer,
+					 "s390_process_IRQ(%04X) - irb for "
+					 "device %04X, ending_status %d\n", irq,
+					 dp->devno, ending_status);
 				
-				s390_displayhex2( buffer,
-						 &(dp->ii.irb) ,
-						 sizeof(irb_t), 2);	
+				s390_displayhex2 (buffer,
+						  &(dp->ii.irb),
+						  sizeof (irb_t), 2);
 			}
-		} /* endif */
+		}
 
 		/*
 		 * take fast exit if no handler is available
 		 */
-		if ( !ioinfo[irq]->ui.flags.ready )
-			return( ending_status );     		
+		if (!ioinfo[irq]->ui.flags.ready)
+			return (ending_status);
 
 		/*
 		 * Check whether we must issue a SENSE CCW ourselves if there is no
@@ -2771,38 +2891,38 @@
 		 *       sense facility available/supported when enabling the
 		 *       concurrent sense facility.
 		 */
-		if (    (    (dp->ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK )
-		          && (!issense                                    ) )
-		     || (ioinfo[irq]->ui.flags.delsense && ending_status    ) )
-		{
-			int            ret_io;
-			ccw1_t        *s_ccw  = &ioinfo[irq]->senseccw;
-			unsigned long  s_flag = 0;
+		if (((dp->ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK)
+		     && (!issense))
+		    || (ioinfo[irq]->ui.flags.delsense && ending_status)) {
+			int ret_io;
+			ccw1_t *s_ccw = &ioinfo[irq]->senseccw;
+			unsigned long s_flag = 0;
 
-			if ( ending_status )
-			{
+			if (ending_status) {
 				/*
 				 * We copy the current status information into the device driver
 				 *  status area. Then we can use the local devstat area for device
 				 *  sensing. When finally calling the IRQ handler we must not overlay
 				 *  the original device status but copy the sense data only.
 				 */
-				memcpy( udp, dp, sizeof( devstat_t) );
+				memcpy (udp, dp, sizeof (devstat_t));
 
 				s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
-				s_ccw->cda      = (__u32)virt_to_phys( ioinfo[irq]->sense_data );
-				s_ccw->count    = SENSE_MAX_COUNT;
-				s_ccw->flags    = CCW_FLAG_SLI;
+				s_ccw->cda =
+				    (__u32) virt_to_phys (ioinfo[irq]->
+							  sense_data);
+				s_ccw->count = SENSE_MAX_COUNT;
+				s_ccw->flags = CCW_FLAG_SLI;
 
 				/*
 				 * If free_irq() or a sync do_IO/s390_start_IO() is in
 				 *  process we have to sense synchronously
 				 */
-				if ( ioinfo[irq]->ui.flags.unready || ioinfo[irq]->ui.flags.syncio )
-				{
+				if (ioinfo[irq]->ui.flags.unready
+				    || ioinfo[irq]->ui.flags.syncio) {
 					s_flag = DOIO_WAIT_FOR_INTERRUPT;
 
-				} /* endif */
+				}
 
 				/*
 				 * Reset status info
@@ -2816,27 +2936,23 @@
 				 *
 				 * Note : this may be a delayed sense request !
 				 */
-				allow4handler                  = 0;
+				allow4handler = 0;
 
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-				ioinfo[irq]->ui.flags.w4final  = 0;
+				ioinfo[irq]->ui.flags.fast = 0;
+				ioinfo[irq]->ui.flags.repall = 0;
+				ioinfo[irq]->ui.flags.w4final = 0;
 				ioinfo[irq]->ui.flags.delsense = 0;
 
-				dp->cstat     = 0;
-				dp->dstat     = 0;
-				dp->rescnt    = SENSE_MAX_COUNT;
-
-				ioinfo[irq]->ui.flags.w4sense  = 1;
-			
-				ret_io = s390_start_IO( irq,
-				                        s_ccw,
-				                        0xE2C5D5E2,  // = SENSe
-				                        0,           // n/a
-				                        s_flag);
-			}
-			else
-			{
+				dp->cstat = 0;
+				dp->dstat = 0;
+				dp->rescnt = SENSE_MAX_COUNT;
+
+				ioinfo[irq]->ui.flags.w4sense = 1;
+
+				ret_io = s390_start_IO (irq, s_ccw, 0xE2C5D5E2,	/* = SENSe */
+							0,	/* n/a */
+							s_flag);
+			} else {
 				/*
 				 * we received an Unit Check but we have no final
 				 *  status yet, therefore we must delay the SENSE
@@ -2844,15 +2960,15 @@
 				 *  intermediate status to the device interrupt
 				 *  handler.
 				 */
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
+				ioinfo[irq]->ui.flags.fast = 0;
+				ioinfo[irq]->ui.flags.repall = 0;
 
 				ioinfo[irq]->ui.flags.delsense = 1;
-				allow4handler                  = 0;
+				allow4handler = 0;
 
-			} /* endif */
+			}
 
-		} /* endif */
+		}
 
 		/*
 		 * we allow for the device action handler if .
@@ -2863,15 +2979,15 @@
 		 *  - unsollicited interrupts
 		 *
 		 */
-		if ( allow4handler )
-		{
-			allow4handler =    ending_status
-				|| ( ioinfo[irq]->ui.flags.repall                                      )
-				|| ( stctl & SCSW_STCTL_INTER_STATUS                                   )
-				|| ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) )
-				|| ( ioinfo[irq]->ui.flags.oper == 0                                   );
+		if (allow4handler) {
+			allow4handler = ending_status
+			    || (ioinfo[irq]->ui.flags.repall)
+			    || (stctl & SCSW_STCTL_INTER_STATUS)
+			    || ((ioinfo[irq]->ui.flags.fast)
+				&& (stctl & SCSW_STCTL_PRIM_STATUS))
+			    || (ioinfo[irq]->ui.flags.oper == 0);
 
-		} /* endif */
+		}
 
 		/*
 		 * We used to copy the device status information right before
@@ -2882,52 +2998,48 @@
 		 *  call the device action handler.
 		 *
 		 */
-		if ( allow4handler )
-		{
+		if (allow4handler) {
 			/*
 			 * if we were waiting for sense data we copy the sense
 			 *  bytes only as the original status information was
 			 *  saved prior to sense already.
 			 */
-			if ( ioinfo[irq]->ui.flags.w4sense )
-			{
-				int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt;
+			if (ioinfo[irq]->ui.flags.w4sense) {
+				int sense_count =
+				    SENSE_MAX_COUNT -
+				    ioinfo[irq]->devstat.rescnt;
 
 #ifdef CONFIG_DEBUG_IO
-				if ( irq != cons_dev )
-					printk( KERN_DEBUG "s390_process_IRQ( %04X ) : "
+				if (irq != cons_dev)
+					printk (KERN_DEBUG
+						"s390_process_IRQ( %04X ) : "
 						"BASIC SENSE bytes avail %d\n",
-						irq, sense_count );
+						irq, sense_count);
 #endif
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_msg_id, 4,
-							    "s390_process_IRQ( %04X ): BASIC SENSE bytes avail %d\n",
-							    irq, sense_count);
+				CIO_MSG_EVENT(4,
+					      "s390_process_IRQ( %04X ): "
+					      "BASIC SENSE bytes avail %d\n",
+					      irq, sense_count);
 				ioinfo[irq]->ui.flags.w4sense = 0;
 				udp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
-				udp->scnt  = sense_count;
+				udp->scnt = sense_count;
 
-				if ( sense_count >= 0 )
-				{
-					memcpy( udp->ii.sense.data,
-					        ioinfo[irq]->sense_data,
-					        sense_count);
-				}
-				else
-				{
-					panic( "s390_process_IRQ(%04x) encountered "
-					       "negative sense count\n",
-					       irq);
+				if (sense_count >= 0) {
+					memcpy (udp->ii.sense.data,
+						ioinfo[irq]->sense_data,
+						sense_count);
+				} else {
+					panic
+					    ("s390_process_IRQ(%04x) encountered "
+					     "negative sense count\n", irq);
 
-				} /* endif */
-			}
-			else
-			{
-				memcpy( udp, dp, sdevstat );
+				}
+			} else {
+				memcpy (udp, dp, sdevstat);
 
-			}  /* endif */
+			}
 
-		} /* endif */
+		}
 
 		/*
 		 * for status pending situations other than deferred interrupt
@@ -2935,74 +3047,74 @@
 		 *  call the handler. This will synchronously be reported back
 		 *  to the caller instead, e.g. when detected during do_IO().
 		 */
-		if (    ioinfo[irq]->ui.flags.s_pend
-		     || ioinfo[irq]->ui.flags.unready
-		     || ioinfo[irq]->ui.flags.repnone )
-		{		
-			if ( ending_status )
-			{
+		if (ioinfo[irq]->ui.flags.s_pend
+		    || ioinfo[irq]->ui.flags.unready
+		    || ioinfo[irq]->ui.flags.repnone) {
+			if (ending_status) {
+
+				ioinfo[irq]->ui.flags.busy = 0;
+				ioinfo[irq]->ui.flags.doio = 0;
+				ioinfo[irq]->ui.flags.haltio = 0;
+				ioinfo[irq]->ui.flags.fast = 0;
+				ioinfo[irq]->ui.flags.repall = 0;
+				ioinfo[irq]->ui.flags.w4final = 0;
 
-				ioinfo[irq]->ui.flags.busy     = 0;
-				ioinfo[irq]->ui.flags.doio     = 0;
-				ioinfo[irq]->ui.flags.haltio   = 0;
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-				ioinfo[irq]->ui.flags.w4final  = 0;
-
-				dp->flag  |= DEVSTAT_FINAL_STATUS;
+				dp->flag |= DEVSTAT_FINAL_STATUS;
 				udp->flag |= DEVSTAT_FINAL_STATUS;
 
-			} /* endif */
+			}
 
 			allow4handler = 0;
 
-		} /* endif */
+		}
 
 		/*
 		 * Call device action handler if applicable
 		 */
-		if ( allow4handler )
-		{
+		if (allow4handler) {
 
 			/*
 			 *  We only reset the busy condition when we are sure that no further
 			 *   interrupt is pending for the current I/O request (ending_status).
 			 */
-			if ( ending_status || !ioinfo[irq]->ui.flags.oper )
-			{
-				ioinfo[irq]->ui.flags.oper     = 1;  /* dev IS oper */
+			if (ending_status || !ioinfo[irq]->ui.flags.oper) {
+				ioinfo[irq]->ui.flags.oper = 1;	/* dev IS oper */
 
-				ioinfo[irq]->ui.flags.busy     = 0;
-				ioinfo[irq]->ui.flags.doio     = 0;
-				ioinfo[irq]->ui.flags.haltio   = 0;
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-				ioinfo[irq]->ui.flags.w4final  = 0;
+				ioinfo[irq]->ui.flags.busy = 0;
+				ioinfo[irq]->ui.flags.doio = 0;
+				ioinfo[irq]->ui.flags.haltio = 0;
+				ioinfo[irq]->ui.flags.fast = 0;
+				ioinfo[irq]->ui.flags.repall = 0;
+				ioinfo[irq]->ui.flags.w4final = 0;
 
-				dp->flag  |= DEVSTAT_FINAL_STATUS;
+				dp->flag |= DEVSTAT_FINAL_STATUS;
 				udp->flag |= DEVSTAT_FINAL_STATUS;
 
-				ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
+				ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
 
-				//
-				// reset intparm after final status or we will badly present unsolicited
-				//  interrupts with a intparm value possibly no longer valid.
-				//
-				dp->intparm   = 0;
-
-				//
-				// Was there anything queued ? Start the pending channel program
-				//  if there is one.
-				//
-				if ( ioinfo[irq]->ui.flags.doio_q )
-				{
-					int ret;
+				/*
+				 * reset intparm after final status or we will badly present unsolicited
+				 *  interrupts with a intparm value possibly no longer valid.
+				 */
+				dp->intparm = 0;
 
-					ret = s390_start_IO( irq,
-					                     ioinfo[irq]->qcpa,
-					                     ioinfo[irq]->qintparm,
-						             ioinfo[irq]->qlpm,
-					                     ioinfo[irq]->qflag);
+				/*
+				 * Was there anything queued ? Start the pending channel program
+				 *  if there is one.
+				 */
+				if (ioinfo[irq]->ui.flags.doio_q) {
+					int ret;
+					int do_cancel =
+					    ioinfo[irq]->
+					    qflag & DOIO_CANCEL_ON_TIMEOUT;
+
+					ret = s390_start_IO (irq,
+							     ioinfo[irq]->qcpa,
+							     ioinfo[irq]->
+							     qintparm,
+							     ioinfo[irq]->qlpm,
+							     ioinfo[irq]->
+							     qflag);
 
 					ioinfo[irq]->ui.flags.doio_q = 0;
 
@@ -3012,17 +3124,22 @@
 					 *  s390_start_IO() accordingly already (status pending
 					 *  condition).
 					 */
-					if ( ret )
-					{
-						ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
+					if (ret) {
+						ioinfo[irq]->irq_desc.
+						    handler (irq, udp, NULL);
+
+					}
 
-					} /* endif */
+					/* 
+					 * better cancel the io when we time out...
+					 */
+					if ((ret == -ETIMEDOUT) && do_cancel) {
+						cancel_IO (irq);
+					}
 
-				} /* endif */
+				}
 
-			}
-			else
-			{
+			} else {
 				ioinfo[irq]->ui.flags.w4final = 1;
 
 				/*
@@ -3030,53 +3147,48 @@
 				 *  set the PCI or SUSPENDED flag in the user
 				 *  device status block if appropriate.
 				 */
-				if ( dp->cstat & SCHN_STAT_PCI )
-				{
+				if (dp->cstat & SCHN_STAT_PCI) {
 					udp->flag |= DEVSTAT_PCI;
 					dp->cstat &= ~SCHN_STAT_PCI;
 				}
 
-				if ( actl & SCSW_ACTL_SUSPENDED )
-				{
+				if (actl & SCSW_ACTL_SUSPENDED) {
 					udp->flag |= DEVSTAT_SUSPENDED;
 
-				} /* endif */
+				}
 
-				ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
+				ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
 
-			} /* endif */
+			}
 
-		} /* endif */
+		}
 
 		break;
 
-	case 3:      /* device/path not operational */
+	case 3:		/* device/path not operational */
 
-		ioinfo[irq]->ui.flags.busy    = 0;
-		ioinfo[irq]->ui.flags.doio    = 0;
-		ioinfo[irq]->ui.flags.haltio  = 0;
+		ioinfo[irq]->ui.flags.busy = 0;
+		ioinfo[irq]->ui.flags.doio = 0;
+		ioinfo[irq]->ui.flags.haltio = 0;
 
-		dp->cstat    = 0;
-		dp->dstat    = 0;
+		dp->cstat = 0;
+		dp->dstat = 0;
 
-		if ( ioinfo[irq]->ulpm != ioinfo[irq]->opm )
-		{
+		if (ioinfo[irq]->ulpm != ioinfo[irq]->opm) {
 			/*
 			 * either it was the only path or it was restricted ...
 			 */
-			ioinfo[irq]->opm &= ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum);
-		}
-		else
-		{
+			ioinfo[irq]->opm &=
+			    ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum);
+		} else {
 			ioinfo[irq]->opm = 0;
 
-		} /* endif */
-	
-		if ( ioinfo[irq]->opm == 0 ) 	
-		{
-			ioinfo[irq]->ui.flags.oper  = 0;
+		}
+
+		if (ioinfo[irq]->opm == 0) {
+			ioinfo[irq]->ui.flags.oper = 0;
 
-		} /* endif */
+		}
 
 		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
 		ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
@@ -3092,50 +3204,48 @@
 		 *       interrupts on "not oper" conditions.
 		 */
 
-		if (    ( ioinfo[irq]->ui.flags.fast    )
-		     && ( ioinfo[irq]->ui.flags.w4final ) )
-		{
+		if ((ioinfo[irq]->ui.flags.fast)
+		    && (ioinfo[irq]->ui.flags.w4final)) {
 			/*
 			 * If a new request was queued already, we have
 			 *  to simulate the "not oper" status for the
 			 *  queued request by switching the "intparm" value
 			 *  and notify the interrupt handler.
 			 */
-			if ( ioinfo[irq]->ui.flags.doio_q )
-			{
-				ioinfo[irq]->devstat.intparm = ioinfo[irq]->qintparm;
+			if (ioinfo[irq]->ui.flags.doio_q) {
+				ioinfo[irq]->devstat.intparm =
+				    ioinfo[irq]->qintparm;
 
-			} /* endif */
-
-		} /* endif */
+			}
+		}
 
-		ioinfo[irq]->ui.flags.fast    = 0;
-		ioinfo[irq]->ui.flags.repall  = 0;
+		ioinfo[irq]->ui.flags.fast = 0;
+		ioinfo[irq]->ui.flags.repall = 0;
 		ioinfo[irq]->ui.flags.w4final = 0;
 
 		/*
 		 * take fast exit if no handler is available
 		 */
-		if ( !ioinfo[irq]->ui.flags.ready )
-			return( ending_status );     		
+		if (!ioinfo[irq]->ui.flags.ready)
+			return (ending_status);
 
-		memcpy( udp, &(ioinfo[irq]->devstat), sdevstat );
+		memcpy (udp, &(ioinfo[irq]->devstat), sdevstat);
 
-		ioinfo[irq]->devstat.intparm  = 0;
+		ioinfo[irq]->devstat.intparm = 0;
 
-		if ( !ioinfo[irq]->ui.flags.s_pend )
-		{
-			ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
+		if (!ioinfo[irq]->ui.flags.s_pend
+		    && !ioinfo[irq]->ui.flags.repnone) {
+			ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
 
-		} /* endif */
+		}
 
-		ending_status    = 1;
+		ending_status = 1;
 
 		break;
 
-	} /* endswitch */
+	}
 
-	return( ending_status );
+	return (ending_status);
 }
 
 /*
@@ -3155,456 +3265,409 @@
  *  encountered, wait_cons_dev(9 calls do_IRQ() to have
  *  the console device driver processing the interrupt.
  */
-int set_cons_dev( int irq )
+int
+set_cons_dev (int irq)
 {
-	int           ccode;
-	unsigned long cr6 __attribute__ ((aligned (8)));
-	int           rc = 0;
+	int ccode;
+	int rc = 0;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( cons_dev != -1  )
-	{
-		rc = -EBUSY;
-	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "scons%x", irq);
-			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-		}
-		
-		/*
-		 * modify the indicated console device to operate
-		 *  on special console interrupt sublass 7
-		 */
-		ccode = stsch( irq, &(ioinfo[irq]->schib) );
+	if (cons_dev != -1)
+		return -EBUSY;
 
-		if (ccode)
-		{
-			rc                         = -ENODEV;
-			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-		}
-		else
-		{
-			ioinfo[irq]->schib.pmcw.isc = 7;
+	sprintf (dbf_txt, "scd%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-			ccode = msch( irq, &(ioinfo[irq]->schib) );
+	/*
+	 * modify the indicated console device to operate
+	 *  on special console interrupt sublass 7
+	 */
+	ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-			if (ccode)
-			{
-				rc = -EIO;
-			}
-			else
-			{
-				cons_dev = irq;
+	if (ccode) {
+		rc = -ENODEV;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+	} else {
+		ioinfo[irq]->schib.pmcw.isc = 7;
 
-				/*
-				 * enable console I/O-interrupt sublass 7
-				 */
-				__ctl_store( cr6, 6, 6);
-				cr6 |= 0x01000000;
-				__ctl_load( cr6, 6, 6);
+		ccode = msch (irq, &(ioinfo[irq]->schib));
 
-			} /* endif */
+		if (ccode) {
+			rc = -EIO;
+		} else {
+			cons_dev = irq;
 
-		} /* endif */
+			/*
+			 * enable console I/O-interrupt sublass 7
+			 */
+			ctl_set_bit (6, 24);
 
-	} /* endif */
+		}
+	}
 
-	return( rc);
+	return (rc);
 }
 
-int reset_cons_dev( int irq)
+int
+reset_cons_dev (int irq)
 {
-	int     rc = 0;
-	int     ccode;
-	long    cr6 __attribute__ ((aligned (8)));
+	int rc = 0;
+	int ccode;
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( cons_dev != -1  )
-	{
-		rc = -EBUSY;
-	}
-	else
-	{
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "rcons%x", irq);
-			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-		}
-
-		/*
-		 * reset the indicated console device to operate
-		 *  on default console interrupt sublass 3
-		 */
-		ccode = stsch( irq, &(ioinfo[irq]->schib) );
+	if (cons_dev != -1)
+		return -EBUSY;
 
-		if (ccode)
-		{
-			rc                         = -ENODEV;
-			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-		}
-		else
-		{
+	sprintf (dbf_txt, "rscd%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-			ioinfo[irq]->schib.pmcw.isc = 3;
+	/*
+	 * reset the indicated console device to operate
+	 *  on default console interrupt sublass 3
+	 */
+	ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-			ccode = msch( irq, &(ioinfo[irq]->schib) );
+	if (ccode) {
+		rc = -ENODEV;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+	} else {
 
-			if (ccode)
-			{
-				rc = -EIO;
-			}
-			else
-			{
-				cons_dev = -1;
+		ioinfo[irq]->schib.pmcw.isc = 3;
 
-				/*
-				 * disable special console I/O-interrupt sublass 7
-				 */
-				__ctl_store( cr6, 6, 6);
-				cr6 &= 0xFEFFFFFF;
-				__ctl_load( cr6, 6, 6);
+		ccode = msch (irq, &(ioinfo[irq]->schib));
 
-			} /* endif */
+		if (ccode) {
+			rc = -EIO;
+		} else {
+			cons_dev = -1;
 
-		} /* endif */
+			/*
+			 * disable special console I/O-interrupt sublass 7
+			 */
+			ctl_clear_bit(6, 24);
 
-	} /* endif */
+		}
+	}
 
-	return( rc);
+	return (rc);
 }
 
-int wait_cons_dev( int irq )
+int
+wait_cons_dev (int irq)
 {
-	int              rc = 0;
-	long             save_cr6;
+	int rc = 0;
+	long save_cr6;
 	char dbf_txt[15];
 
-	if ( irq == cons_dev )
-	{
+	if (irq != cons_dev)
+		return -EINVAL;
 
-		if (cio_debug_initialized) {
-			sprintf(dbf_txt, "wcons%x", irq);
-			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-		}
+	sprintf (dbf_txt, "wcd%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * before entering the spinlock we may already have
+	 *  processed the interrupt on a different CPU ...
+	 */
+	if (ioinfo[irq]->ui.flags.busy == 1) {
+		long cr6 __attribute__ ((aligned (8)));
 
 		/*
-		 * before entering the spinlock we may already have
-		 *  processed the interrupt on a different CPU ...
+		 * disable all, but isc 7 (console device)
 		 */
-		if ( ioinfo[irq]->ui.flags.busy == 1 )
-		{
-			long cr6 __attribute__ ((aligned (8)));
+		__ctl_store (cr6, 6, 6);
+		save_cr6 = cr6;
+		cr6 &= 0x01FFFFFF;
+		__ctl_load (cr6, 6, 6);
 
-			/*
-			 * disable all, but isc 7 (console device)
-			 */
-			__ctl_store( cr6, 6, 6);
-			save_cr6  = cr6;
-			cr6      &= 0x01FFFFFF;
-			__ctl_load( cr6, 6, 6);
-
-			do {
-				tpi_info_t tpi_info = {0,};
-				if (tpi(&tpi_info) == 1) {
-					s390_process_IRQ( tpi_info.irq );
-				} else {
-					s390irq_spin_unlock(irq);
-					udelay(100);
-					s390irq_spin_lock(irq);
-				}
-				eieio();
-			} while (ioinfo[irq]->ui.flags.busy == 1);
-
-			/*
-			 * restore previous isc value
-			 */
-			cr6 = save_cr6;
-			__ctl_load( cr6, 6, 6);
+		do {
+			tpi_info_t tpi_info = { 0, };
+			if (tpi (&tpi_info) == 1) {
+				s390_process_IRQ (tpi_info.irq);
+			} else {
+				s390irq_spin_unlock (irq);
+				udelay (100);
+				s390irq_spin_lock (irq);
+			}
+			eieio ();
+		} while (ioinfo[irq]->ui.flags.busy == 1);
 
-		} /* endif */
+		/*
+		 * restore previous isc value
+		 */
+		cr6 = save_cr6;
+		__ctl_load (cr6, 6, 6);
 
 	}
-	else
-	{
-		rc = EINVAL;
-
-	} /* endif */
 
-
-	return(rc);
+	return (rc);
 }
 
-
-int enable_cpu_sync_isc( int irq )
+int
+enable_cpu_sync_isc (int irq)
 {
-	int             ccode;
-	long            cr6 __attribute__ ((aligned (8)));
+	int ccode;
+	long cr6 __attribute__ ((aligned (8)));
 
-	int             retry = 3;
-	int             rc    = 0;
+	int retry = 3;
+	int rc = 0;
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "enisc%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "eisc%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/* This one spins until it can get the sync_isc lock for irq# irq */
 
-	if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
-		if ( atomic_read( &sync_isc ) != irq )
-			atomic_compare_and_swap_spin( -1, irq, &sync_isc );
+	if ((irq <= highest_subchannel) && 
+	    (ioinfo[irq] != INVALID_STORAGE_AREA) &&
+	    (!ioinfo[irq]->st)) {
+		if (atomic_read (&sync_isc) != irq)
+			atomic_compare_and_swap_spin (-1, irq, &sync_isc);
 
 		sync_isc_cnt++;
-		
-		if ( sync_isc_cnt > 255 ) /* fixme : magic number */
-		{
-			panic("Too many recursive calls to enable_sync_isc");
+
+		if (sync_isc_cnt > 255) {	/* fixme : magic number */
+			panic ("Too many recursive calls to enable_sync_isc");
 
 		}
 		/*
 		 * we only run the STSCH/MSCH path for the first enablement
 		 */
-		else if ( sync_isc_cnt == 1 )
-		{
+		else if (sync_isc_cnt == 1) {
 			ioinfo[irq]->ui.flags.syncio = 1;
 
-			ccode = stsch( irq, &(ioinfo[irq]->schib) );
+			ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-			if ( !ccode )
-			{
+			if (!ccode) {
 				ioinfo[irq]->schib.pmcw.isc = 5;
 
-				do
-				{
-					ccode = msch( irq,
-					              &(ioinfo[irq]->schib) );
+				do {
+					ccode = msch (irq,
+						      &(ioinfo[irq]->schib));
 
 					switch (ccode) {
-					case 0: 
+					case 0:
 						/*
 						 * enable special isc
 						 */
-						__ctl_store( cr6, 6, 6);
-						cr6 |= 0x04000000;  // enable sync isc 5
-						cr6 &= 0xEFFFFFFF;  // disable standard isc 3
-						__ctl_load( cr6, 6, 6);
+						__ctl_store (cr6, 6, 6);
+						/* enable sync isc 5 */
+						cr6 |= 0x04000000;
+						/* disable standard isc 3 */
+						cr6 &= 0xEFFFFFFF;
+						/* disable console isc 7,
+						 * if neccessary */
+						if (cons_dev != -1)
+							cr6 &= 0xFEFFFFFF;
+						__ctl_load (cr6, 6, 6);
+						rc = 0;
 						retry = 0;
 						break;
-					
+
 					case 1:
-						//
-						// process pending status
-						//
-						ioinfo[irq]->ui.flags.s_pend = 1;
-						s390_process_IRQ( irq );
-						ioinfo[irq]->ui.flags.s_pend = 0;
-						
-						rc = -EIO;  /* might be overwritten... */
+						/*
+						 * process pending status
+						 */
+						ioinfo[irq]->ui.flags.s_pend =
+						    1;
+						s390_process_IRQ (irq);
+						ioinfo[irq]->ui.flags.s_pend =
+						    0;
+
+						rc = -EIO;	/* might be overwritten... */
 						retry--;
 						break;
 
-					case 2: /* busy */
+					case 2:	/* busy */
 						retry = 0;
-						rc = -EBUSY; 
+						rc = -EBUSY;
 						break;
 
-					case 3: /* not oper*/
+					case 3:	/* not oper */
 						retry = 0;
-						rc = -ENODEV; 
+						rc = -ENODEV;
 						break;
-					
-					}
 
-				} while ( retry );
-
-			}
-			else
-			{
-				rc = -ENODEV;     // device is not-operational
+					}
 
-			} /* endif */
+				} while (retry);
 
-		} /* endif */
+			} else {
+				rc = -ENODEV;	/* device is not-operational */
 
+			}
+		}
 
-		if ( rc )	/* can only happen if stsch/msch fails */
-		{
+		if (rc) {	/* can only happen if stsch/msch fails */
 			sync_isc_cnt = 0;
-			atomic_set( &sync_isc, -1);
+			atomic_set (&sync_isc, -1);
 		}
-	}
-	else
-	{
+	} else {
 #ifdef CONFIG_SYNC_ISC_PARANOIA
-		panic( "enable_sync_isc: called with invalid %x\n", irq );
+		panic ("enable_sync_isc: called with invalid %x\n", irq);
 #endif
 
 		rc = -EINVAL;
 
-	} /* endif */
+	}
 
-	return( rc);
+	return (rc);
 }
 
-int disable_cpu_sync_isc( int irq)
+int
+disable_cpu_sync_isc (int irq)
 {
-	int     rc         = 0;
-	int     retry1     = 5;
-	int     retry2     = 5;
-	int     clear_pend = 0;
+	int rc = 0;
+	int retry1 = 5;
+	int retry2 = 5;
+	int clear_pend = 0;
 
-	int     ccode;
-	long    cr6 __attribute__ ((aligned (8)));
+	int ccode;
+	long cr6 __attribute__ ((aligned (8)));
 
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "disisc%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "disc%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
+	if ((irq <= highest_subchannel) && 
+	    (ioinfo[irq] != INVALID_STORAGE_AREA) && 
+	    (!ioinfo[irq]->st)) {
 		/*
 		 * We disable if we're the top user only, as we may
-		 *  run recursively ...	
+		 *  run recursively ... 
 		 * We must not decrease the count immediately; during
 		 *  msch() processing we may face another pending
 		 *  status we have to process recursively (sync).
 		 */
 
 #ifdef CONFIG_SYNC_ISC_PARANOIA
-		if ( atomic_read( &sync_isc ) != irq )
-			panic( "disable_sync_isc: called for %x while %x locked\n",
-				irq, atomic_read( &sync_isc ) );
+		if (atomic_read (&sync_isc) != irq)
+			panic
+			    ("disable_sync_isc: called for %x while %x locked\n",
+			     irq, atomic_read (&sync_isc));
 #endif
 
-		if ( sync_isc_cnt == 1 )
-		{
-			ccode = stsch( irq, &(ioinfo[irq]->schib) );
+		if (sync_isc_cnt == 1) {
+			ccode = stsch (irq, &(ioinfo[irq]->schib));
 
 			ioinfo[irq]->schib.pmcw.isc = 3;
 
-			do
-			{
-			        retry2 = 5;
-				do
-				{
-					ccode = msch( irq, &(ioinfo[irq]->schib) );
+			do {
+				retry2 = 5;
+				do {
+					ccode =
+					    msch (irq, &(ioinfo[irq]->schib));
 
-					switch ( ccode ) {
+					switch (ccode) {
 					case 0:
 						/*
 						 * disable special interrupt subclass in CPU
 						 */
-						__ctl_store( cr6, 6, 6);
-						cr6 &= 0xFBFFFFFF; // disable sync isc 5
-						cr6 |= 0x10000000; // enable standard isc 3
-						__ctl_load( cr6, 6, 6);
+						__ctl_store (cr6, 6, 6);
+						/* disable sync isc 5 */
+						cr6 &= 0xFBFFFFFF;
+						/* enable standard isc 3 */
+						cr6 |= 0x10000000;
+						/* enable console isc 7,
+						 * if neccessary */
+						if (cons_dev != -1)
+							cr6 |= 0x01000000;
+						__ctl_load (cr6, 6, 6);
 
 						retry2 = 0;
 						break;
 
-					case 1: /* status pending */
-						ioinfo[irq]->ui.flags.s_pend = 1;
-						s390_process_IRQ( irq );
-						ioinfo[irq]->ui.flags.s_pend = 0;
+					case 1:	/* status pending */
+						ioinfo[irq]->ui.flags.s_pend =
+						    1;
+						s390_process_IRQ (irq);
+						ioinfo[irq]->ui.flags.s_pend =
+						    0;
 
 						retry2--;
 						break;
 
-					case 2: /* busy */
-					        retry2--;
-						udelay( 100); // give it time
+					case 2:	/* busy */
+						retry2--;
+						udelay (100);	/* give it time */
 						break;
-						
-					default: /* not oper */
+
+					default:	/* not oper */
 						retry2 = 0;
 						break;
-					} /* endswitch */
+					}
 
-				} while ( retry2 );
+				} while (retry2);
 
 				retry1--;
 
 				/* try stopping it ... */
-				if ( (ccode) && !clear_pend )
-				{
-					clear_IO( irq, 0x00004711, 0 );
+				if ((ccode) && !clear_pend) {
+					clear_IO (irq, 0x00004711, 0);
 					clear_pend = 1;
-               	
-				} /* endif */
 
-				udelay( 100);
+				}
+
+				udelay (100);
 
-			} while ( retry1 && ccode );
+			} while (retry1 && ccode);
 
 			ioinfo[irq]->ui.flags.syncio = 0;
-		
-			sync_isc_cnt = 0;	
-			atomic_set( &sync_isc, -1);
 
-		}
-		else
-		{
+			sync_isc_cnt = 0;
+			atomic_set (&sync_isc, -1);
+
+		} else {
 			sync_isc_cnt--;
 
-		} /* endif */
-	}
-	else
-	{
+		}
+	} else {
 #ifdef CONFIG_SYNC_ISC_PARANOIA
-		if ( atomic_read( &sync_isc ) != -1 )
-			panic( "disable_sync_isc: called with invalid %x while %x locked\n", 
-				irq, atomic_read( &sync_isc ) );
+		if (atomic_read (&sync_isc) != -1)
+			panic
+			    ("disable_sync_isc: called with invalid %x while %x locked\n",
+			     irq, atomic_read (&sync_isc));
 #endif
 
 		rc = -EINVAL;
 
-	} /* endif */
+	}
 
-	return( rc);
+	return (rc);
 }
 
-//
-// Input :
-//   devno - device number
-//   ps    - pointer to sense ID data area
-//
-// Output : none
-//
-void VM_virtual_device_info( __u16      devno,
-                             senseid_t *ps )
+/*
+ * Input :
+ *   devno - device number
+ *   ps    - pointer to sense ID data area
+ * Output : none
+ */
+void
+VM_virtual_device_info (__u16 devno, senseid_t * ps)
 {
-	diag210_t  *p_diag_data;
-	int        ccode;
+	diag210_t *p_diag_data;
+	int ccode;
 
-	int        error = 0;
+	int error = 0;
 
-	if (cio_debug_initialized) 
-		debug_text_event(cio_debug_trace_id, 4, "VMvdinf");
+	CIO_TRACE_EVENT (4, "VMvdinf");
 
-	if ( init_IRQ_complete )
-	{
-		p_diag_data = kmalloc( sizeof( diag210_t), GFP_DMA );
-	}
-	else
-	{
-		p_diag_data = alloc_bootmem_low( sizeof( diag210_t));
+	if (init_IRQ_complete) {
+		p_diag_data = kmalloc (sizeof (diag210_t), GFP_DMA);
+	} else {
+		p_diag_data = alloc_bootmem_low (sizeof (diag210_t));
 
-	} /* endif */
+	}
 
 	p_diag_data->vrdcdvno = devno;
-	p_diag_data->vrdclen  = sizeof( diag210_t);
-	ccode                 = diag210( (diag210_t *)virt_to_phys( p_diag_data ) );
-	ps->reserved          = 0xff;
+	p_diag_data->vrdclen = sizeof (diag210_t);
+	ccode = diag210 ((diag210_t *) virt_to_phys (p_diag_data));
+	ps->reserved = 0xff;
 
 	switch (p_diag_data->vrdcvcla) {
 	case 0x80:
@@ -3612,7 +3675,7 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 00:
 
-			ps->cu_type   = 0x3215;
+			ps->cu_type = 0x3215;
 
 			break;
 
@@ -3622,7 +3685,7 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3631,25 +3694,25 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 0xC0:
 
-			ps->cu_type   = 0x5080;
+			ps->cu_type = 0x5080;
 
 			break;
 
 		case 0x80:
 
-			ps->cu_type   = 0x2250;
+			ps->cu_type = 0x2250;
 
 			break;
 
 		case 0x04:
 
-			ps->cu_type   = 0x3277;
+			ps->cu_type = 0x3277;
 
 			break;
 
 		case 0x01:
 
-			ps->cu_type   = 0x3278;
+			ps->cu_type = 0x3278;
 
 			break;
 
@@ -3659,7 +3722,7 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3668,19 +3731,19 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 0x84:
 
-			ps->cu_type   = 0x3505;
+			ps->cu_type = 0x3505;
 
 			break;
 
 		case 0x82:
 
-			ps->cu_type   = 0x2540;
+			ps->cu_type = 0x2540;
 
 			break;
 
 		case 0x81:
 
-			ps->cu_type   = 0x2501;
+			ps->cu_type = 0x2501;
 
 			break;
 
@@ -3690,7 +3753,7 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3699,13 +3762,13 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 0x84:
 
-			ps->cu_type   = 0x3525;
+			ps->cu_type = 0x3525;
 
 			break;
 
 		case 0x82:
 
-			ps->cu_type   = 0x2540;
+			ps->cu_type = 0x2540;
 
 			break;
 
@@ -3713,7 +3776,7 @@
 		case 0x4E:
 		case 0x48:
 
-			ps->cu_type   = 0x3820;
+			ps->cu_type = 0x3820;
 
 			break;
 
@@ -3721,43 +3784,43 @@
 		case 0x49:
 		case 0x45:
 
-			ps->cu_type   = 0x3800;
+			ps->cu_type = 0x3800;
 
 			break;
 
 		case 0x4B:
 
-			ps->cu_type   = 0x4248;
+			ps->cu_type = 0x4248;
 
 			break;
 
 		case 0x4A:
 
-			ps->cu_type   = 0x4245;
+			ps->cu_type = 0x4245;
 
 			break;
 
 		case 0x47:
 
-			ps->cu_type   = 0x3262;
+			ps->cu_type = 0x3262;
 
 			break;
 
 		case 0x43:
 
-			ps->cu_type   = 0x3203;
+			ps->cu_type = 0x3203;
 
 			break;
 
 		case 0x42:
 
-			ps->cu_type   = 0x3211;
+			ps->cu_type = 0x3211;
 
 			break;
 
 		case 0x41:
 
-			ps->cu_type   = 0x1403;
+			ps->cu_type = 0x1403;
 
 			break;
 
@@ -3767,7 +3830,7 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3776,43 +3839,43 @@
 		switch (p_diag_data->vrdcvtyp) {
 		case 0x82:
 
-			ps->cu_type   = 0x3422;
+			ps->cu_type = 0x3422;
 
 			break;
 
 		case 0x81:
 
-			ps->cu_type   = 0x3490;
+			ps->cu_type = 0x3490;
 
 			break;
 
 		case 0x10:
 
-			ps->cu_type   = 0x3420;
+			ps->cu_type = 0x3420;
 
 			break;
 
 		case 0x02:
 
-			ps->cu_type   = 0x3430;
+			ps->cu_type = 0x3430;
 
 			break;
 
 		case 0x01:
 
-			ps->cu_type   = 0x3480;
+			ps->cu_type = 0x3480;
 
 			break;
 
 		case 0x42:
 
-			ps->cu_type   = 0x3424;
+			ps->cu_type = 0x3424;
 
 			break;
 
 		case 0x44:
 
-			ps->cu_type   = 0x9348;
+			ps->cu_type = 0x9348;
 
 			break;
 
@@ -3822,26 +3885,26 @@
 
 			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
-	case 02: /* special device class ... */
+	case 02:		/* special device class ... */
 
 		switch (p_diag_data->vrdcvtyp) {
-		case 0x20: /* OSA */
+		case 0x20:	/* OSA */
 
-			ps->cu_type   = 0x3088;
-			ps->cu_model  = 0x60;
+			ps->cu_type = 0x3088;
+			ps->cu_model = 0x60;
 
 			break;
 
 		default:
 
 			error = 1;
-      	break;
+			break;
 
-		} /* endswitch */
+		}
 
 		break;
 
@@ -3851,47 +3914,44 @@
 
 		break;
 
-	} /* endswitch */
-
-	if ( init_IRQ_complete )
-	{
-		kfree( p_diag_data );
 	}
-	else
-	{
-		free_bootmem( (unsigned long)p_diag_data, sizeof( diag210_t) );
 
-	} /* endif */
+	if (init_IRQ_complete) {
+		kfree (p_diag_data);
+	} else {
+		free_bootmem ((unsigned long) p_diag_data, sizeof (diag210_t));
+
+	}
 
-	if ( error )
-	{
-		printk( KERN_ERR "DIAG X'210' for "
-		        "device %04X returned "
-		        "(cc = %d): vdev class : %02X, "
-			"vdev type : %04X \n ...  rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
+	if (error) {
+		printk (KERN_ERR "DIAG X'210' for "
+			"device %04X returned "
+			"(cc = %d): vdev class : %02X, "
+			"vdev type : %04X \n"
+			" ...  rdev class : %02X, rdev type : %04X, "
+			"rdev model: %02X\n",
 			devno,
 			ccode,
 			p_diag_data->vrdcvcla,
 			p_diag_data->vrdcvtyp,
 			p_diag_data->vrdcrccl,
-			p_diag_data->vrdccrty,
-			p_diag_data->vrdccrmd );
-		if (cio_debug_initialized)
-			debug_sprintf_event( cio_debug_msg_id, 0,
-					     "DIAG X'210' for "
-					     "device %04X returned "
-					     "(cc = %d): vdev class : %02X, "
-					     "vdev type : %04X \n ...  rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
-					     devno,
-					     ccode,
-					     p_diag_data->vrdcvcla,
-					     p_diag_data->vrdcvtyp,
-					     p_diag_data->vrdcrccl,
-					     p_diag_data->vrdccrty,
-					     p_diag_data->vrdccrmd );
-
-	} /* endif */
-
+			p_diag_data->vrdccrty, p_diag_data->vrdccrmd);
+		CIO_MSG_EVENT(0,
+			      "DIAG X'210' for "
+			      "device %04X returned "
+			      "(cc = %d): vdev class : %02X, "
+			      "vdev type : %04X \n ...  "
+			      "rdev class : %02X, rdev type : %04X, "
+			      "rdev model: %02X\n",
+			      devno,
+			      ccode,
+			      p_diag_data->vrdcvcla,
+			      p_diag_data->vrdcvtyp,
+			      p_diag_data->vrdcrccl,
+			      p_diag_data->vrdccrty,
+			      p_diag_data->vrdccrmd);
+		
+	}
 }
 
 /*
@@ -3917,371 +3977,351 @@
  *         b) without unnecessarily increase system startup by
  *            evaluating devices eventually not used at all.
  */
-int read_dev_chars( int irq, void **buffer, int length )
+int
+read_dev_chars (int irq, void **buffer, int length)
 {
-	unsigned int  flags;
-	ccw1_t       *rdc_ccw;
-	devstat_t     devstat;
-	char         *rdc_buf;
-	int           devflag = 0;
-
-	int           ret      = 0;
-	int           emulated = 0;
-	int           retry    = 5;
+	unsigned int flags;
+	ccw1_t *rdc_ccw;
+	devstat_t devstat;
+	char *rdc_buf;
+	int devflag = 0;
+
+	int ret = 0;
+	int emulated = 0;
+	int retry = 5;
 
 	char dbf_txt[15];
 
-	if ( !buffer || !length )
-	{
-		return( -EINVAL );
+	if (!buffer || !length) {
+		return (-EINVAL);
+
+	}
 
-	} /* endif */
+	SANITY_CHECK (irq);
 
-	SANITY_CHECK(irq);
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
 
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
-
-	} /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "rddevch%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
 	}
 
+ 	if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		/* don't even try it */
+ 		return -EUSERS;
+ 	}
+
+	sprintf (dbf_txt, "rdc%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
 	/*
 	 * Before playing around with irq locks we should assure
 	 *   running disabled on (just) our CPU. Sync. I/O requests
 	 *   also require to run disabled.
 	 *
 	 * Note : as no global lock is required, we must not use
-	 *        cli(), but __cli() instead.  	
+	 *        cli(), but __cli() instead.   
 	 */
-	__save_flags(flags);
-	__cli();
+	__save_flags (flags);
+	__cli ();
 
 	rdc_ccw = &ioinfo[irq]->senseccw;
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		ret = request_irq( irq,
-		                   init_IRQ_handler,
-		                   SA_PROBE, "RDC", &devstat );
+	if (!ioinfo[irq]->ui.flags.ready) {
+		ret = request_irq (irq,
+				   init_IRQ_handler, SA_PROBE, "RDC", &devstat);
 
-		if ( !ret )
-		{
+		if (!ret) {
 			emulated = 1;
 
-		} /* endif */
+		}
 
-	} /* endif */
+	}
 
-	if ( !ret )
-	{
-		if ( ! *buffer )
-		{
-			rdc_buf  = kmalloc( length, GFP_KERNEL);
-		}
-		else
-		{
+	if (!ret) {
+		if (!*buffer) {
+			rdc_buf = kmalloc (length, GFP_KERNEL);
+		} else {
 			rdc_buf = *buffer;
 
-		} /* endif */
+		}
 
-		if ( !rdc_buf )
-		{
+		if (!rdc_buf) {
 			ret = -ENOMEM;
-		}
-		else
-		{
-			do
-			{
+		} else {
+			do {
 				rdc_ccw->cmd_code = CCW_CMD_RDC;
-				rdc_ccw->count    = length;
-				rdc_ccw->flags    = CCW_FLAG_SLI;
-				ret = set_normalized_cda( rdc_ccw, (unsigned long)rdc_buf );
+				rdc_ccw->count = length;
+				rdc_ccw->flags = CCW_FLAG_SLI;
+				ret =
+				    set_normalized_cda (rdc_ccw, (unsigned long)
+							rdc_buf);
 				if (!ret) {
 
-					memset( ioinfo[irq]->irq_desc.dev_id,
-						'\0',
-						sizeof( devstat_t));
-
-					ret = s390_start_IO( irq,
-							     rdc_ccw,
-							     0x00524443, // RDC
-							     0,          // n/a
+					memset (ioinfo[irq]->irq_desc.dev_id,
+						'\0', sizeof (devstat_t));
+
+					ret = s390_start_IO (irq, rdc_ccw, 0x00524443,	/* RDC */
+							     0,	/* n/a */
 							     DOIO_WAIT_FOR_INTERRUPT
-							     | DOIO_DONT_CALL_INTHDLR );
+							     |
+							     DOIO_DONT_CALL_INTHDLR);
 					retry--;
-					devflag = ioinfo[irq]->irq_desc.dev_id->flag;   
-					
-					clear_normalized_cda( rdc_ccw);  
+					devflag =
+					    ioinfo[irq]->irq_desc.dev_id->flag;
+
+					clear_normalized_cda (rdc_ccw);
 				} else {
-					udelay(100);  //wait for recovery
+					udelay (100);	/* wait for recovery */
 					retry--;
 				}
 
-			} while (    ( retry                                     )
-			          && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
+			} while ((retry)
+				 && (ret
+				     || (devflag & DEVSTAT_STATUS_PENDING)));
 
-		} /* endif */
+		}
 
-		if ( !retry )
-		{
-			ret = (ret==-ENOMEM)?-ENOMEM:-EBUSY;
+		if (!retry) {
+			ret = (ret == -ENOMEM) ? -ENOMEM : -EBUSY;
 
-		} /* endif */
+		}
 
-		__restore_flags(flags);
+		__restore_flags (flags);
 
 		/*
 		 * on success we update the user input parms
 		 */
-		if ( !ret )
-		{
+		if (!ret) {
 			*buffer = rdc_buf;
 
-		} /* endif */
+		}
 
-		if ( emulated )
-		{
-			free_irq( irq, &devstat);
+		if (emulated) {
+			free_irq (irq, &devstat);
 
-		} /* endif */
+		}
 
-	} /* endif */
+	} else {
+		__restore_flags (flags);
+	}
 
-	return( ret );
+	return (ret);
 }
 
 /*
  *  Read Configuration data
  */
-int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
+int
+read_conf_data (int irq, void **buffer, int *length, __u8 lpm)
 {
 	unsigned long flags;
-	int           ciw_cnt;
+	int ciw_cnt;
 
-	int           found  = 0; // RCD CIW found
-	int           ret    = 0; // return code
+	int found = 0;		/* RCD CIW found */
+	int ret = 0;		/* return code */
 
 	char dbf_txt[15];
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
+
+	if (!buffer || !length) {
+		return (-EINVAL);
+	} else if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
+	} else if (ioinfo[irq]->ui.flags.esid == 0) {
+		*buffer = NULL;
+		*length = 0;
+		return (-EOPNOTSUPP);
 
-	if ( !buffer || !length )
-	{
-		return( -EINVAL);
-	}
-	else if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
-	}
-	else if ( ioinfo[irq]->ui.flags.esid == 0 )
-	{
-		return( -EOPNOTSUPP );
-
-	} /* endif */
-
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "rdconf%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
 	}
 
+ 	if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		/* don't even try it */
+ 		return -EUSERS;
+ 	}
+
+	sprintf (dbf_txt, "rcd%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
 	/*
 	 * scan for RCD command in extended SenseID data
 	 */
-	
-	for ( ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
-	{
-		if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD )
-		{
+
+	for (ciw_cnt = 0; (found == 0) && (ciw_cnt < MAX_CIWS); ciw_cnt++) {
+		if (ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD) {
 			/*
 			 * paranoia check ...
 			 */
-			if ( ioinfo[irq]->senseid.ciw[ciw_cnt].cmd != 0 )
-			{
+			if (ioinfo[irq]->senseid.ciw[ciw_cnt].cmd != 0
+			    && ioinfo[irq]->senseid.ciw[ciw_cnt].count != 0) {
 				found = 1;
 
-			} /* endif */
+			}
 
 			break;
 
-		} /* endif */
-
-	} /* endfor */
+		}
+	}
 
-	if ( found )
-	{
-		devstat_t  devstat;  /* inline device status area */
+	if (found) {
+		devstat_t devstat;	/* inline device status area */
 		devstat_t *pdevstat;
-		int        ioflags;
+		int ioflags;
 
-		ccw1_t    *rcd_ccw  = &ioinfo[irq]->senseccw;
-		char      *rcd_buf  = NULL;
-		int        emulated = 0; /* no i/O handler installed */
-		int        retry    = 5; /* retry count */
+		ccw1_t *rcd_ccw = &ioinfo[irq]->senseccw;
+		char *rcd_buf = NULL;
+		int emulated = 0;	/* no i/O handler installed */
+		int retry = 5;	/* retry count */
 
-		__save_flags(flags);
-		__cli();
+		__save_flags (flags);
+		__cli ();
 
-		if ( !ioinfo[irq]->ui.flags.ready )
-		{
+		if (!ioinfo[irq]->ui.flags.ready) {
 			pdevstat = &devstat;
-			ret      = request_irq( irq,
-			                        init_IRQ_handler,
-			                        SA_PROBE, "RCD", pdevstat );
+			ret = request_irq (irq,
+					   init_IRQ_handler,
+					   SA_PROBE, "RCD", pdevstat);
 
-			if ( !ret )
-			{
+			if (!ret) {
 				emulated = 1;
 
-			} /* endif */
-		}
-		else
-		{
+			}	/* endif */
+		} else {
 			pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
-		} /* endif */
-
-		if ( !ret )
-		{
-			if ( init_IRQ_complete )
-			{
-				rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count,
-				                   GFP_DMA);
-			}
-			else
-			{
-				rcd_buf = alloc_bootmem_low( ioinfo[irq]->senseid.ciw[ciw_cnt].count);
+		}		/* endif */
 
-   		} /* endif */
+		if (!ret) {
+			if (init_IRQ_complete) {
+				rcd_buf =
+				    kmalloc (ioinfo[irq]->senseid.ciw[ciw_cnt].
+					     count, GFP_DMA);
+			} else {
+				rcd_buf =
+				    alloc_bootmem_low (ioinfo[irq]->senseid.
+						       ciw[ciw_cnt].count);
 
-			if ( rcd_buf == NULL )
-			{
-				ret = -ENOMEM;	
+			}
 
-			} /* endif */
+			if (rcd_buf == NULL) {
+				ret = -ENOMEM;
 
-			if ( !ret )
-			{
-				memset( rcd_buf,
-				        '\0',
-				        ioinfo[irq]->senseid.ciw[ciw_cnt].count);
-       	
-				do
-				{
-					rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd;
-					rcd_ccw->cda      = (__u32)virt_to_phys( rcd_buf );
-					rcd_ccw->count    = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
-					rcd_ccw->flags    = CCW_FLAG_SLI;
+			}
+			if (!ret) {
+				memset (rcd_buf,
+					'\0',
+					ioinfo[irq]->senseid.ciw[ciw_cnt].
+					count);
 
-					memset( pdevstat, '\0', sizeof( devstat_t));
+				do {
+					rcd_ccw->cmd_code =
+					    ioinfo[irq]->senseid.ciw[ciw_cnt].
+					    cmd;
+					rcd_ccw->cda =
+					    (__u32) virt_to_phys (rcd_buf);
+					rcd_ccw->count =
+					    ioinfo[irq]->senseid.ciw[ciw_cnt].
+					    count;
+					rcd_ccw->flags = CCW_FLAG_SLI;
+
+					memset (pdevstat, '\0',
+						sizeof (devstat_t));
+
+					if (lpm) {
+						ioflags =
+						    DOIO_WAIT_FOR_INTERRUPT |
+						    DOIO_VALID_LPM |
+						    DOIO_DONT_CALL_INTHDLR;
+					} else {
+						ioflags =
+						    DOIO_WAIT_FOR_INTERRUPT |
+						    DOIO_DONT_CALL_INTHDLR;
 
-					if ( lpm )
-					{
-						ioflags = DOIO_WAIT_FOR_INTERRUPT
-						          | DOIO_VALID_LPM    					
-						          | DOIO_DONT_CALL_INTHDLR;
 					}
-					else
-					{
-						ioflags =   DOIO_WAIT_FOR_INTERRUPT
-						          | DOIO_DONT_CALL_INTHDLR;
-						             					
-					} /* endif */
-
-					ret = s390_start_IO( irq,
-					                     rcd_ccw,
-					                     0x00524344,  // == RCD
-					                     lpm,
-					                     ioflags );
-					switch ( ret ) {
+
+					ret = s390_start_IO (irq, rcd_ccw, 0x00524344,	/* == RCD */
+							     lpm, ioflags);
+					switch (ret) {
 					case 0:
 					case -EIO:
-						
-						if ( !(pdevstat->flag & (   DEVSTAT_STATUS_PENDING
-									    | DEVSTAT_NOT_OPER
-									    | DEVSTAT_FLAG_SENSE_AVAIL ) ) )
+
+						if (!
+						    (pdevstat->
+						     flag &
+						     (DEVSTAT_STATUS_PENDING |
+						      DEVSTAT_NOT_OPER |
+						      DEVSTAT_FLAG_SENSE_AVAIL)))
 						{
-							retry = 0;  // we got it ...
+							retry = 0;	/* we got it ... */
+						} else {
+							retry--;	/* try again ... */
+
 						}
-						else
-						{
-							retry--;    // try again ...
-								
-						} /* endif */
-						
+
 						break;
 
-					default:   // -EBUSY, -ENODEV, ???
+					default:	/* -EBUSY, -ENODEV, ??? */
 						retry = 0;
-						
-					} /* endswitch */
-					
-				} while ( retry );
 
-			} /* endif */
+					}
 
-			__restore_flags( flags );
+				} while (retry);
+			}
+		}
 
-		} /* endif */
+		__restore_flags (flags);
 
 		/*
 		 * on success we update the user input parms
 		 */
-		if ( ret == 0 )
-		{
+		if (ret == 0) {
 			*length = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
 			*buffer = rcd_buf;
-		}
-		else
-		{
-			if ( rcd_buf != NULL )
-			{
-				if ( init_IRQ_complete )
-				{
-					kfree( rcd_buf );
-				}
-				else
-				{
-					free_bootmem( (unsigned long)rcd_buf,
-					              ioinfo[irq]->senseid.ciw[ciw_cnt].count);
+		} else {
+			if (rcd_buf != NULL) {
+				if (init_IRQ_complete) {
+					kfree (rcd_buf);
+				} else {
+					free_bootmem ((unsigned long) rcd_buf,
+						      ioinfo[irq]->senseid.
+						      ciw[ciw_cnt].count);
 
-   			} /* endif */
+				}
 
-			} /* endif */
+			}
 
 			*buffer = NULL;
 			*length = 0;
-    	
-		} /* endif */
 
-		if ( emulated )
-			free_irq( irq, pdevstat);
-	}
-	else
-	{
+		}
+
+		if (emulated)
+			free_irq (irq, pdevstat);
+	} else {
+		*buffer = NULL;
+		*length = 0;
 		ret = -EOPNOTSUPP;
 
-	} /* endif */
+	}
 
-	return( ret );
+	return (ret);
 
 }
 
-int get_dev_info( int irq, s390_dev_info_t * pdi)
+int
+get_dev_info (int irq, s390_dev_info_t * pdi)
 {
-	return( get_dev_info_by_irq( irq, pdi));
+	return (get_dev_info_by_irq (irq, pdi));
 }
 
-static int __inline__ get_next_available_irq( ioinfo_t *pi)
+static int __inline__
+get_next_available_irq (ioinfo_t * pi)
 {
 	int ret_val = -ENODEV;
 
-	while ( pi!=NULL ) {
-		if ( pi->ui.flags.oper ) {
+	while (pi != NULL) {
+		if ((!pi->st) 
+		    && (pi->ui.flags.oper)
+		    && (!pi->ui.flags.unfriendly)) {
 			ret_val = pi->irq;
 			break;
 		} else {
@@ -4292,214 +4332,200 @@
 	return ret_val;
 }
 
-
-int get_irq_first( void )
+int
+get_irq_first (void)
 {
-   int ret_irq;
+	int ret_irq;
 
-	if ( ioinfo_head )
-	{
-		if ( ioinfo_head->ui.flags.oper )
-		{
+	if (ioinfo_head) {
+		if ((ioinfo_head->ui.flags.oper) && 
+		    (!ioinfo_head->ui.flags.unfriendly) &&
+		    (!ioinfo_head->st)) {
 			ret_irq = ioinfo_head->irq;
-		}
-		else if ( ioinfo_head->next )
-		{
-			ret_irq = get_next_available_irq( ioinfo_head->next );
+		} else if (ioinfo_head->next) {
+			ret_irq = get_next_available_irq (ioinfo_head->next);
 
-		}
-		else
-		{
+		} else {
 			ret_irq = -ENODEV;
-   	
-		} /* endif */
-	}
-	else
-	{
+
+		}
+	} else {
 		ret_irq = -ENODEV;
 
-	} /* endif */
+	}
 
 	return ret_irq;
 }
 
-int get_irq_next( int irq )
+int
+get_irq_next (int irq)
 {
-	int ret_irq;	
+	int ret_irq;
 
-	if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
-		if ( ioinfo[irq]->next )
-		{
-			if ( ioinfo[irq]->next->ui.flags.oper )
-			{
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+		if (ioinfo[irq]->next) {
+			if ((ioinfo[irq]->next->ui.flags.oper) &&
+			    (!ioinfo[irq]->next->ui.flags.unfriendly) &&
+			    (!ioinfo[irq]->next->st)) {
 				ret_irq = ioinfo[irq]->next->irq;
+			} else {
+				ret_irq =
+				    get_next_available_irq (ioinfo[irq]->next);
+
 			}
-			else
-			{
-				ret_irq = get_next_available_irq( ioinfo[irq]->next );
+		} else {
+			ret_irq = -ENODEV;
 
-			} /* endif */
 		}
-		else
-		{
-			ret_irq = -ENODEV;     	
-
-		} /* endif */
-	}
-	else
-	{
+	} else {
 		ret_irq = -EINVAL;
 
-	} /* endif */
+	}
 
 	return ret_irq;
 }
 
-int get_dev_info_by_irq( int irq, s390_dev_info_t *pdi)
+int
+get_dev_info_by_irq (int irq, s390_dev_info_t * pdi)
 {
 
-	SANITY_CHECK(irq);
+	SANITY_CHECK (irq);
 
-	if ( pdi == NULL )
+	if (pdi == NULL)
 		return -EINVAL;
 
 	pdi->devno = ioinfo[irq]->schib.pmcw.dev;
-	pdi->irq   = irq;
-	
-	if (   ioinfo[irq]->ui.flags.oper
-	    && !ioinfo[irq]->ui.flags.unknown ) 
-	{
+	pdi->irq = irq;
+
+	if (ioinfo[irq]->ui.flags.oper && !ioinfo[irq]->ui.flags.unknown) {
 		pdi->status = 0;
-		memcpy( &(pdi->sid_data),
-			&ioinfo[irq]->senseid,
-			sizeof( senseid_t));
-	}
-	else if ( ioinfo[irq]->ui.flags.unknown )
-	{
+		memcpy (&(pdi->sid_data),
+			&ioinfo[irq]->senseid, sizeof (senseid_t));
+ 
+ 	} else if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		pdi->status = DEVSTAT_UNFRIENDLY_DEV;
+ 		memset (&(pdi->sid_data), '\0', sizeof (senseid_t));
+ 		pdi->sid_data.cu_type = 0xFFFF;
+
+	} else if (ioinfo[irq]->ui.flags.unknown) {
 		pdi->status = DEVSTAT_UNKNOWN_DEV;
-		memset( &(pdi->sid_data),
-			'\0',
-			sizeof( senseid_t));
+		memset (&(pdi->sid_data), '\0', sizeof (senseid_t));
 		pdi->sid_data.cu_type = 0xFFFF;
-			
-	}
-	else
-	{
+
+	} else {
 		pdi->status = DEVSTAT_NOT_OPER;
-		memset( &(pdi->sid_data),
-			'\0',
-			sizeof( senseid_t));
+		memset (&(pdi->sid_data), '\0', sizeof (senseid_t));
 		pdi->sid_data.cu_type = 0xFFFF;
-		
-	} /* endif */
-	
-	if ( ioinfo[irq]->ui.flags.ready )
-		pdi->status |= DEVSTAT_DEVICE_OWNED;
 
+	}
+
+	if (ioinfo[irq]->ui.flags.ready)
+		pdi->status |= DEVSTAT_DEVICE_OWNED;
 
 	return 0;
 }
 
-
-int get_dev_info_by_devno( __u16 devno, s390_dev_info_t *pdi)
+int
+get_dev_info_by_devno (__u16 devno, s390_dev_info_t * pdi)
 {
 	int i;
 	int rc = -ENODEV;
 
-	if ( devno > 0x0000ffff )
+	if (devno > 0x0000ffff)
 		return -ENODEV;
-        if ( pdi == NULL )
+	if (pdi == NULL)
 		return -EINVAL;
 
-	for ( i=0; i <= highest_subchannel; i++ ) {
-		
-		if (    ioinfo[i] != INVALID_STORAGE_AREA
-		     && ioinfo[i]->schib.pmcw.dev == devno )
-		{
-			
-			pdi->irq   = i;
+	for (i = 0; i <= highest_subchannel; i++) {
+
+		if ((ioinfo[i] != INVALID_STORAGE_AREA) &&
+		    (!ioinfo[i]->st) &&
+		    (ioinfo[i]->schib.pmcw.dev == devno)) {
+
+			pdi->irq = i;
 			pdi->devno = devno;
-			
-			if (    ioinfo[i]->ui.flags.oper
-			     && !ioinfo[i]->ui.flags.unknown )
-			{
+
+			if (ioinfo[i]->ui.flags.oper
+			    && !ioinfo[i]->ui.flags.unknown) {
 				pdi->status = 0;
-				memcpy( &(pdi->sid_data),
+				memcpy (&(pdi->sid_data),
 					&ioinfo[i]->senseid,
-					sizeof( senseid_t));
-			}
-			else if ( ioinfo[i]->ui.flags.unknown )
-			{
+					sizeof (senseid_t));
+ 
+ 			} else if (ioinfo[i]->ui.flags.unfriendly) {
+ 				pdi->status = DEVSTAT_UNFRIENDLY_DEV;
+ 				memset (&(pdi->sid_data), '\0', 
+ 					sizeof (senseid_t));
+ 				pdi->sid_data.cu_type = 0xFFFF;
+ 
+
+			} else if (ioinfo[i]->ui.flags.unknown) {
 				pdi->status = DEVSTAT_UNKNOWN_DEV;
 
-				memset( &(pdi->sid_data),
-					'\0',
-					sizeof( senseid_t));
+				memset (&(pdi->sid_data),
+					'\0', sizeof (senseid_t));
 
 				pdi->sid_data.cu_type = 0xFFFF;
-			}
-			else
-			{
+			} else {
 				pdi->status = DEVSTAT_NOT_OPER;
-				
-				memset( &(pdi->sid_data),
-					'\0',
-					sizeof( senseid_t));
+
+				memset (&(pdi->sid_data),
+					'\0', sizeof (senseid_t));
 
 				pdi->sid_data.cu_type = 0xFFFF;
 
-			} /* endif */
+			}
 
-			if ( ioinfo[i]->ui.flags.ready )
+			if (ioinfo[i]->ui.flags.ready)
 				pdi->status |= DEVSTAT_DEVICE_OWNED;
 
-			rc = 0; /* found */
+			if (!ioinfo[i]->ui.flags.unfriendly)
+				rc = 0;	/* found */
+			else
+				rc = -EUSERS;
 			break;
 
-		} /* endif */
-
-	} /* endfor */
+		}
+	}
 
-	return( rc);
+	return (rc);
 
 }
 
-int get_irq_by_devno( __u16 devno )
+int
+get_irq_by_devno (__u16 devno)
 {
 	int i;
 	int rc = -1;
 
-	if ( devno <= 0x0000ffff )
-	{
-		for ( i=0; i <= highest_subchannel; i++ )
-		{
-			if (    (ioinfo[i] != INVALID_STORAGE_AREA )
-			     && (ioinfo[i]->schib.pmcw.dev == devno)
-			     && (ioinfo[i]->schib.pmcw.dnv == 1    ) )
-			{
+	if (devno <= 0x0000ffff) {
+		for (i = 0; i <= highest_subchannel; i++) {
+			if ((ioinfo[i] != INVALID_STORAGE_AREA)
+			    && (!ioinfo[i]->st)
+			    && (ioinfo[i]->schib.pmcw.dev == devno)
+			    && (ioinfo[i]->schib.pmcw.dnv == 1)) {
 				rc = i;
 				break;
+			}
+		}
+	}
 
-			} /* endif */
-
-		} /* endfor */
-	
-	} /* endif */
-
-	return( rc);
+	return (rc);
 }
 
-unsigned int get_devno_by_irq( int irq )
+unsigned int
+get_devno_by_irq (int irq)
 {
 
-	if (    ( irq > highest_subchannel            )
-	     || ( irq < 0                             )
-	     || ( ioinfo[irq] == INVALID_STORAGE_AREA ) )
-	{
+	if ((irq > highest_subchannel)
+	    || (irq < 0)
+	    || (ioinfo[irq] == INVALID_STORAGE_AREA)) {
+		return -1;
+
+	}
+
+	if (ioinfo[irq]->st) 
 		return -1;
-	
-	} /* endif */
 
 	/*
 	 * we don't need to check for the device be operational
@@ -4508,8 +4534,8 @@
 	 *  existing or not. However, there could be subchannels
 	 *  defined who's device number isn't valid ...
 	 */
-	if ( ioinfo[irq]->schib.pmcw.dnv )
-		return( ioinfo[irq]->schib.pmcw.dev );
+	if (ioinfo[irq]->schib.pmcw.dnv)
+		return (ioinfo[irq]->schib.pmcw.dev);
 	else
 		return -1;
 }
@@ -4521,102 +4547,138 @@
  *  independant SenseID command to obtain info the device type.
  *
  */
-void s390_device_recognition_irq( int irq )
+void
+s390_device_recognition_irq (int irq)
 {
-	int           ret;
+	int ret;
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "devrec%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "dri%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/*
 	 * We issue the SenseID command on I/O subchannels we think are
 	 *  operational only.
 	 */
-	if (    ( ioinfo[irq] != INVALID_STORAGE_AREA )	
-	     && ( ioinfo[irq]->schib.pmcw.st == 0     )
-	     && ( ioinfo[irq]->ui.flags.oper == 1     ) )
-	{
-		int       irq_ret;
+	if ((ioinfo[irq] != INVALID_STORAGE_AREA)
+	    && (!ioinfo[irq]->st)
+	    && (ioinfo[irq]->schib.pmcw.st == 0)
+	    && (ioinfo[irq]->ui.flags.oper == 1)) {
+		int irq_ret;
 		devstat_t devstat;
 
-		irq_ret = request_irq( irq,
-		                       init_IRQ_handler,
-		                       SA_PROBE,
-		                       "INIT",
-		                       &devstat);
-
-		if ( !irq_ret )
-		{
-			ret = enable_cpu_sync_isc( irq );
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE, "INIT", &devstat);
 
-			if ( !ret ) 
-			{
-				ioinfo[irq]->ui.flags.unknown = 0;
+		if (!irq_ret) {
+			ret = enable_cpu_sync_isc (irq);
 
-				memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t));
+			if (!ret) {
+ 				pgid_t pgid;
+ 				/*
+ 				 * First thing we should do is a sensePGID in
+ 				 * order to find out how we can proceed with
+ 				 * the recognition process. 
+ 				 * An unfriendly (locked by so else) device 
+ 				 * won't take kindly to our attempts at 
+ 				 * SetPGID and SenseID...
+ 				 */
+  
+ 				memcpy(&pgid, global_pgid, sizeof(pgid_t));
+ 				ret = s390_SensePGID(irq, 0xff, &pgid);
+
+				if (ret == -EOPNOTSUPP) 
+					/* 
+					 * Doesn't prevent us from proceeding
+					 */
+					ret = 0;
+ 				
+ 				if (!ret && !ioinfo[irq]->ui.flags.unfriendly) {
+
+					ioinfo[irq]->ui.flags.unknown = 0;
+					
+					memset (&ioinfo[irq]->senseid, '\0',
+						sizeof (senseid_t));
+					
+					if (cio_sid_with_pgid) {
+						
+						ret = s390_DevicePathVerification(irq,0);
+						
+						if (ret == -EOPNOTSUPP) 
+							/* 
+							 * Doesn't prevent us from proceeding
+							 */
+							ret = 0;
+					}
 
-				s390_SenseID( irq, &ioinfo[irq]->senseid, 0xff );
-#if 0	/* FIXME */
+					/*
+					 * we'll fallthrough here if we don't want
+					 * to do SPID before SID
+					 */
+					if (!ret) {
+						s390_SenseID (irq, &ioinfo[irq]->senseid, 0xff);
+#if 0				/* FIXME */
 				/*
 				 * We initially check the configuration data for
 				 *  those devices with more than a single path
 				 */
-				if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-				{
-					char     *prcd;
-					int       lrcd;
+				if (ioinfo[irq]->schib.pmcw.pim != 0x80) {
+					char *prcd;
+					int lrcd;
+
+					ret =
+					    read_conf_data (irq,
+							    (void **) &prcd,
+							    &lrcd, 0);
 
-					ret = read_conf_data( irq, (void **)&prcd, &lrcd, 0 );
-
-					if ( !ret )	// on success only ...
+					if (!ret)	// on success only ...
 					{
 						char buffer[80];
 #ifdef CONFIG_DEBUG_IO
-						sprintf( buffer,
-						         "RCD for device(%04X)/"
-						         "subchannel(%04X) returns :\n",
-						         ioinfo[irq]->schib.pmcw.dev,
-						         irq );
+						sprintf (buffer,
+							 "RCD for device(%04X)/"
+							 "subchannel(%04X) returns :\n",
+							 ioinfo[irq]->schib.
+							 pmcw.dev, irq);
 
-						s390_displayhex( buffer, prcd, lrcd );
-#endif      				
+						s390_displayhex (buffer, prcd,
+								 lrcd);
+#endif
 						if (cio_debug_initialized) {
-							sprintf( buffer,
+							sprintf (buffer,
 								 "RCD for device(%04X)/"
 								 "subchannel(%04X) returns :\n",
-								 ioinfo[irq]->schib.pmcw.dev,
-								 irq );
-							
-							s390_displayhex2( buffer, prcd, lrcd, 2);
-						}
-						if ( init_IRQ_complete )
-						{
-							kfree( prcd );
+								 ioinfo[irq]->
+								 schib.pmcw.dev,
+								 irq);
+
+							s390_displayhex2
+							    (buffer, prcd, lrcd,
+							     2);
 						}
-						else
-						{
-							free_bootmem( (unsigned long)prcd, lrcd );
-
- 			  			} /* endif */
+						if (init_IRQ_complete) {
+							kfree (prcd);
+						} else {
+							free_bootmem ((unsigned
+								       long)
+								      prcd,
+								      lrcd);
 
-					} /* endif */
-					
-				} /* endif */
+						}
+					}
+				}
 #endif
+					}
+				}
+				disable_cpu_sync_isc (irq);
 
-				disable_cpu_sync_isc( irq );
-
-			} /* endif */  	
-
-			free_irq( irq, &devstat );
+			}
 
-		} /* endif */
-		
-	} /* endif */
+			free_irq (irq, &devstat);
 
+		}
+	}
 }
 
 /*
@@ -4625,17 +4687,17 @@
  * Used for system wide device recognition.
  *
  */
-void s390_device_recognition_all( void)
+void
+s390_device_recognition_all (void)
 {
-	int irq = 0; /* let's start with subchannel 0 ... */
+	int irq = 0;		/* let's start with subchannel 0 ... */
 
-	do
-	{
-		s390_device_recognition_irq( irq );
+	do {
+		s390_device_recognition_irq (irq);
 
-		irq ++;
+		irq++;
 
-	} while ( irq <= highest_subchannel );
+	} while (irq <= highest_subchannel);
 
 }
 
@@ -4645,39 +4707,72 @@
  * FIXME: there must be a better way to do this...
  */
 
-void s390_redo_validation(void) 
+void
+s390_redo_validation (void)
 {
 	int irq = 0;
 	int ret;
 
-	if (cio_debug_initialized) {
-		debug_text_event(cio_debug_trace_id, 0, "redoval");
-	}
+	CIO_TRACE_EVENT (0, "redoval");
+
 	do {
 		if (ioinfo[irq] == INVALID_STORAGE_AREA) {
-			ret = s390_validate_subchannel(irq, 0);
+			ret = s390_validate_subchannel (irq, 0);
 			if (!ret) {
-				s390_device_recognition_irq(irq);
+				s390_device_recognition_irq (irq);
 				if (ioinfo[irq]->ui.flags.oper) {
 					devreg_t *pdevreg;
-					
-					pdevreg = s390_search_devreg( ioinfo[irq] );
-					if ( pdevreg != NULL ) {
-						if ( pdevreg->oper_func != NULL )
-							pdevreg->oper_func( irq, pdevreg );
-						
-					} 
+
+					pdevreg =
+					    s390_search_devreg (ioinfo[irq]);
+					if (pdevreg != NULL) {
+						if (pdevreg->oper_func != NULL)
+							pdevreg->oper_func (irq,
+									    pdevreg);
+
+					}
 				}
 #ifdef CONFIG_PROC_FS
-				if (cio_proc_devinfo) 
+				if (cio_proc_devinfo)
 					if (irq < MAX_CIO_PROCFS_ENTRIES) {
-						cio_procfs_device_create(ioinfo[irq]->devno);
-				}
+						cio_procfs_device_create (ioinfo
+									  [irq]->
+									  devno);
+					}
 #endif
 			}
 		}
 		irq++;
-	} while (irq<=highest_subchannel);
+	} while (irq <= highest_subchannel);
+}
+
+
+/*
+ * s390_trigger_resense
+ *
+ * try to re-sense the device on subchannel irq
+ * only to be called without interrupt handler
+ */
+int
+s390_trigger_resense(int irq)
+{
+	char dbf_txt[8];
+
+	SANITY_CHECK(irq);
+
+	CIO_TRACE_EVENT (2, "tsns");
+	sprintf(dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	if (ioinfo[irq]->ui.flags.ready) {
+		printk (KERN_WARNING "s390_trigger_resense(%04X): "
+			"Device is in use!\n", irq);
+		return -EBUSY;
+	}
+
+	s390_device_recognition_irq(irq);
+
+	return 0;
 }
 
 /*
@@ -4686,28 +4781,27 @@
  * Determines all subchannels available to the system.
  *
  */
-void s390_process_subchannels( void)
+void
+s390_process_subchannels (void)
 {
-	int   ret;
-	int   irq = 0;   /* Evaluate all subchannels starting with 0 ... */
+	int ret;
+	int irq = 0;		/* Evaluate all subchannels starting with 0 ... */
 
-	do
-	{
-		ret = s390_validate_subchannel( irq, 0);
+	do {
+		ret = s390_validate_subchannel (irq, 0);
 
-		if ( ret != -ENXIO)
+		if (ret != -ENXIO)
 			irq++;
-	
-  	} while ( (ret != -ENXIO) && (irq < __MAX_SUBCHANNELS) );
+
+	} while ((ret != -ENXIO) && (irq < __MAX_SUBCHANNELS));
 
 	highest_subchannel = (--irq);
 
-	printk( KERN_INFO "Highest subchannel number detected (hex) : %04X\n",
-	        highest_subchannel);
-	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_msg_id, 0, 
-				    "Highest subchannel number detected (hex) : %04X\n",
-				    highest_subchannel);	
+	printk (KERN_INFO "Highest subchannel number detected (hex) : %04X\n",
+		highest_subchannel);
+	CIO_MSG_EVENT(0,
+		      "Highest subchannel number detected "
+		      "(hex) : %04X\n", highest_subchannel);
 }
 
 /*
@@ -4716,362 +4810,357 @@
  * Process the subchannel for the requested irq. Returns 1 for valid
  *  subchannels, otherwise 0.
  */
-int s390_validate_subchannel( int irq, int enable )
+int
+s390_validate_subchannel (int irq, int enable)
 {
 
-	int      retry;     /* retry count for status pending conditions */
-	int      ccode;     /* condition code for stsch() only */
-	int      ccode2;    /* condition code for other I/O routines */
+	int retry;		/* retry count for status pending conditions */
+	int ccode;		/* condition code for stsch() only */
+	int ccode2;		/* condition code for other I/O routines */
 	schib_t *p_schib;
-	int      ret;
-	
+	int ret;
+#ifdef CONFIG_CHSC
+	int      chp = 0;
+	int      mask;
+#endif /* CONFIG_CHSC */
+
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "valsch%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "vals%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
 	/*
 	 * The first subchannel that is not-operational (ccode==3)
 	 *  indicates that there aren't any more devices available.
 	 */
-	if (    ( init_IRQ_complete                   )
-	     && ( ioinfo[irq] != INVALID_STORAGE_AREA ) )
-	{
+	if ((init_IRQ_complete)
+	    && (ioinfo[irq] != INVALID_STORAGE_AREA)) {
 		p_schib = &ioinfo[irq]->schib;
-	}
-	else
-	{
+	} else {
 		p_schib = p_init_schib;
 
-	} /* endif */
+	}
 
 	/*
-	 * If we knew the device before we assume the worst case ... 	
+	 * If we knew the device before we assume the worst case ...    
 	 */
-	if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
 		ioinfo[irq]->ui.flags.oper = 0;
 		ioinfo[irq]->ui.flags.dval = 0;
 
-	} /* endif */
+	}
 
-	ccode = stsch( irq, p_schib);
+	ccode = stsch (irq, p_schib);
 
-	if ( !ccode )
-	{
-		/*
-		 * ... just being curious we check for non I/O subchannels
-		 */
-		if ( p_schib->pmcw.st )
-		{
-			printk( KERN_INFO "Subchannel %04X reports "
-			        "non-I/O subchannel type %04X\n",
-			        irq,
-			        p_schib->pmcw.st);
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 0,
-						    "Subchannel %04X reports non-I/O subchannel type %04X\n",
-						    irq, p_schib->pmcw.st);
+	if (ccode) {
+		return -ENXIO;
+	}
+	/*
+	 * ... just being curious we check for non I/O subchannels
+	 */
+	if (p_schib->pmcw.st) {
+		if (cio_show_msg) {
+			printk (KERN_INFO "Subchannel %04X reports "
+				"non-I/O subchannel type %04X\n",
+				irq, p_schib->pmcw.st);
+		}
+		CIO_MSG_EVENT(0,
+			      "Subchannel %04X reports "
+			      "non-I/O subchannel type %04X\n",
+			      irq, p_schib->pmcw.st);
 
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-				ioinfo[irq]->ui.flags.oper = 0;
+		if (ioinfo[irq] != INVALID_STORAGE_AREA)
+			ioinfo[irq]->ui.flags.oper = 0;
 
-		} /* endif */
+	}
 
-		if ( p_schib->pmcw.dnv )
-		{
-		     if ( is_blacklisted( p_schib->pmcw.dev )) {
-			  /* 
-			   * This device must not be known to Linux. So we simply say that 
-			   * there is no device and return ENODEV.
-			   */
+	if ((!p_schib->pmcw.dnv) && (!p_schib->pmcw.st)) {
+		return -ENODEV;
+	}
+	if (!p_schib->pmcw.st) {
+		if (is_blacklisted (p_schib->pmcw.dev)) {
+			/* 
+			 * This device must not be known to Linux. So we simply say that 
+			 * there is no device and return ENODEV.
+			 */
 #ifdef CONFIG_DEBUG_IO
-			  printk( KERN_DEBUG "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev );
-#endif
-			  if (cio_debug_initialized)
-				  debug_sprintf_event(cio_debug_msg_id, 0,
-						      "Blacklisted device detected at devno %04X\n",
-						      p_schib->pmcw.dev);
-			  ret = -ENODEV;
-		     } else {
-		        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-			{	
-				if ( !init_IRQ_complete )
-				{
-					ioinfo[irq] =
-					   (ioinfo_t *)alloc_bootmem_low( sizeof(ioinfo_t));
-				}
-				else
-				{
-					ioinfo[irq] =
-					   (ioinfo_t *)kmalloc( sizeof(ioinfo_t),
-				                           GFP_DMA );
-
-				} /* endif */
-
-				memset( ioinfo[irq], '\0', sizeof( ioinfo_t));
-				memcpy( &ioinfo[irq]->schib,
-			           p_init_schib,
-			           sizeof( schib_t));
-			
-				/*
-				 * We have to insert the new ioinfo element
-				 *  into the linked list, either at its head,
-				 *  its tail or insert it.
-				 */
-				if ( ioinfo_head == NULL )  /* first element */
-				{
-					ioinfo_head = ioinfo[irq];
-					ioinfo_tail = ioinfo[irq];
-				}
-				else if ( irq < ioinfo_head->irq ) /* new head */
-				{
-					ioinfo[irq]->next = ioinfo_head;
-					ioinfo_head->prev = ioinfo[irq];
-					ioinfo_head       = ioinfo[irq];
-				}
-				else if ( irq > ioinfo_tail->irq ) /* new tail */
-				{
-					ioinfo_tail->next = ioinfo[irq];
-					ioinfo[irq]->prev = ioinfo_tail;
-					ioinfo_tail       = ioinfo[irq];
-				}
-				else /* insert element */
-				{
-					ioinfo_t *pi = ioinfo_head;
+			printk (KERN_DEBUG
+				"Blacklisted device detected at devno %04X\n",
+				p_schib->pmcw.dev);
+#endif
+			CIO_MSG_EVENT(0,
+				      "Blacklisted device detected at devno %04X\n",
+				      p_schib->pmcw.dev);
+			return -ENODEV;
+		}
+	}
+	
+	if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+		if (!init_IRQ_complete) {
+			ioinfo[irq] = (ioinfo_t *)
+			    alloc_bootmem_low (sizeof (ioinfo_t));
+		} else {
+			ioinfo[irq] = (ioinfo_t *)
+			    kmalloc (sizeof (ioinfo_t), GFP_DMA);
 
-					for (pi=ioinfo_head; pi!=NULL; pi=pi->next) {
+		}
 
-						if ( irq < pi->next->irq )
-						{
-							ioinfo[irq]->next = pi->next;
-							ioinfo[irq]->prev = pi;
-							pi->next->prev    = ioinfo[irq];
-							pi->next          = ioinfo[irq];
-							break;
-						
-						} /* endif */
-					}
-				} /* endif */
+		memset (ioinfo[irq], '\0', sizeof (ioinfo_t));
+		memcpy (&ioinfo[irq]->schib, p_init_schib, sizeof (schib_t));
 
-			} /* endif */
+		/*
+		 * We have to insert the new ioinfo element
+		 *  into the linked list, either at its head,
+		 *  its tail or insert it.
+		 */
+		if (ioinfo_head == NULL) {	/* first element */
+			ioinfo_head = ioinfo[irq];
+			ioinfo_tail = ioinfo[irq];
+		} else if (irq < ioinfo_head->irq) {	/* new head */
+			ioinfo[irq]->next = ioinfo_head;
+			ioinfo_head->prev = ioinfo[irq];
+			ioinfo_head = ioinfo[irq];
+		} else if (irq > ioinfo_tail->irq) {	/* new tail */
+			ioinfo_tail->next = ioinfo[irq];
+			ioinfo[irq]->prev = ioinfo_tail;
+			ioinfo_tail = ioinfo[irq];
+		} else {	/* insert element */
 
-			// initialize some values ...	
-			ioinfo[irq]->ui.flags.pgid_supp = 1;
+			ioinfo_t *pi = ioinfo_head;
 
-			ioinfo[irq]->opm =   ioinfo[irq]->schib.pmcw.pim
-			                   & ioinfo[irq]->schib.pmcw.pam
-			                   & ioinfo[irq]->schib.pmcw.pom;
+			for (pi = ioinfo_head; pi != NULL; pi = pi->next) {
 
-			if ( cio_show_msg )
-			{
-				printk( KERN_INFO"Detected device %04X "
-				        "on subchannel %04X"
-				        " - PIM = %02X, PAM = %02X, POM = %02X\n",
-				        ioinfo[irq]->schib.pmcw.dev,
-				        irq,
-			   	     ioinfo[irq]->schib.pmcw.pim,
-			      	  ioinfo[irq]->schib.pmcw.pam,
-			 	       ioinfo[irq]->schib.pmcw.pom);
-
-			} /* endif */
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 0,
-						    "Detected device %04X "
-						    "on subchannel %04X"
-						    " - PIM = %02X, PAM = %02X, POM = %02X\n",
-						    ioinfo[irq]->schib.pmcw.dev,
-						    irq,
-						    ioinfo[irq]->schib.pmcw.pim,
-						    ioinfo[irq]->schib.pmcw.pam,
-						    ioinfo[irq]->schib.pmcw.pom);
+				if (irq < pi->next->irq) {
+					ioinfo[irq]->next = pi->next;
+					ioinfo[irq]->prev = pi;
+					pi->next->prev = ioinfo[irq];
+					pi->next = ioinfo[irq];
+					break;
 
-			/*
-			 * initialize ioinfo structure
-			 */
-			ioinfo[irq]->irq             = irq;
-			if(!ioinfo[irq]->ui.flags.ready)
-			{
-				ioinfo[irq]->nopfunc         = NULL;
-				ioinfo[irq]->ui.flags.busy   = 0;
-				ioinfo[irq]->ui.flags.dval   = 1;
-				ioinfo[irq]->devstat.intparm = 0;
-				
+				}
 			}
-			ioinfo[irq]->devstat.devno   = ioinfo[irq]->schib.pmcw.dev;
-			ioinfo[irq]->devno           = ioinfo[irq]->schib.pmcw.dev;
+		}
+	}
 
-			/*
-			 * We should have at least one CHPID ...
-			 */
-			if ( ioinfo[irq]->opm )
-			{
+	/* initialize some values ... */
+	ioinfo[irq]->irq = irq;
+	ioinfo[irq]->st = ioinfo[irq]->schib.pmcw.st;
+	if (ioinfo[irq]->st)
+		return -ENODEV;
+
+	ioinfo[irq]->ui.flags.pgid_supp = 1;
+
+	ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
+	    & ioinfo[irq]->schib.pmcw.pam & ioinfo[irq]->schib.pmcw.pom;
+
+#ifdef CONFIG_CHSC
+	if (ioinfo[irq]->opm) {
+		for (chp=0;chp<=7;chp++) {
+			mask = 0x80 >> chp;
+			if (ioinfo[irq]->opm & mask) {
+				if (!test_bit
+				    (ioinfo[irq]->schib.pmcw.chpid[chp], 
+				     &chpids_logical)) {
+					/* disable using this path */
+					ioinfo[irq]->opm &= ~mask;
+				}
+			}
+		}
+	}
+#endif /* CONFIG_CHSC */
+
+	if (cio_show_msg) {
+		printk (KERN_INFO
+			"Detected device %04X "
+			"on subchannel %04X"
+			" - PIM = %02X, PAM = %02X, POM = %02X\n",
+			ioinfo[irq]->schib.pmcw.dev,
+			irq,
+			ioinfo[irq]->schib.pmcw.pim,
+			ioinfo[irq]->schib.pmcw.pam,
+			ioinfo[irq]->schib.pmcw.pom);
+
+	}
+	CIO_MSG_EVENT(0,
+		      "Detected device %04X "
+		      "on subchannel %04X"
+		      " - PIM = %02X, "
+		      "PAM = %02X, POM = %02X\n",
+		      ioinfo[irq]->schib.pmcw.dev, 
+		      irq,
+		      ioinfo[irq]->schib.pmcw.pim,
+		      ioinfo[irq]->schib.pmcw.pam, 
+		      ioinfo[irq]->schib.pmcw.pom);
+
+	/*
+	 * initialize ioinfo structure
+	 */
+	if (!ioinfo[irq]->ui.flags.ready) {
+		ioinfo[irq]->nopfunc = NULL;
+		ioinfo[irq]->ui.flags.busy = 0;
+		ioinfo[irq]->ui.flags.dval = 1;
+		ioinfo[irq]->devstat.intparm = 0;
+
+	}
+	ioinfo[irq]->devstat.devno = ioinfo[irq]->schib.pmcw.dev;
+	ioinfo[irq]->devno = ioinfo[irq]->schib.pmcw.dev;
+
+	/*
+	 * We should have at least one CHPID ...
+	 */
+	if (ioinfo[irq]->opm) {
+		/*
+		 * We now have to initially ...
+		 *  ... set "interruption sublass"
+		 *  ... enable "concurrent sense"
+		 *  ... enable "multipath mode" if more than one
+		 *        CHPID is available. This is done regardless
+		 *        whether multiple paths are available for us.
+		 *
+		 * Note : we don't enable the device here, this is temporarily
+		 *        done during device sensing below.
+		 */
+		ioinfo[irq]->schib.pmcw.isc = 3;	/* could be smth. else */
+		ioinfo[irq]->schib.pmcw.csense = 1;	/* concurrent sense */
+		ioinfo[irq]->schib.pmcw.ena = enable;
+		ioinfo[irq]->schib.pmcw.intparm = ioinfo[irq]->schib.pmcw.dev;
+
+		if ((ioinfo[irq]->opm != 0x80)
+		    && (ioinfo[irq]->opm != 0x40)
+		    && (ioinfo[irq]->opm != 0x20)
+		    && (ioinfo[irq]->opm != 0x10)
+		    && (ioinfo[irq]->opm != 0x08)
+		    && (ioinfo[irq]->opm != 0x04)
+		    && (ioinfo[irq]->opm != 0x02)
+		    && (ioinfo[irq]->opm != 0x01)) {
+			ioinfo[irq]->schib.pmcw.mp = 1;	/* multipath mode */
+
+		}
+
+		retry = 5;
+
+		do {
+			ccode2 = msch_err (irq, &ioinfo[irq]->schib);
+
+			switch (ccode2) {
+			case 0:
 				/*
-				 * We now have to initially ...
-				 *  ... set "interruption sublass"
-				 *  ... enable "concurrent sense"
-				 *  ... enable "multipath mode" if more than one
-				 *        CHPID is available. This is done regardless
-				 *        whether multiple paths are available for us.
+				 * successful completion
 				 *
-				 * Note : we don't enable the device here, this is temporarily
-				 *        done during device sensing below.
+				 * concurrent sense facility available
 				 */
-				ioinfo[irq]->schib.pmcw.isc     = 3; /* could be smth. else */
-				ioinfo[irq]->schib.pmcw.csense  = 1; /* concurrent sense */
-				ioinfo[irq]->schib.pmcw.ena     = enable;
-				ioinfo[irq]->schib.pmcw.intparm =
-				                     ioinfo[irq]->schib.pmcw.dev;
-
-				if (    ( ioinfo[irq]->opm != 0x80 )
-				     && ( ioinfo[irq]->opm != 0x40 )
-				     && ( ioinfo[irq]->opm != 0x20 )
-				     && ( ioinfo[irq]->opm != 0x10 )
-				     && ( ioinfo[irq]->opm != 0x08 )
-				     && ( ioinfo[irq]->opm != 0x04 )
-				     && ( ioinfo[irq]->opm != 0x02 )
-				     && ( ioinfo[irq]->opm != 0x01 ) )
-				{
-					ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
-
-				} /* endif */
-
-				retry = 5;
-
-				do
-				{
-					ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
-					switch (ccode2) {
-					case 0:  // successful completion
-						//
-						// concurrent sense facility available ...
-						//
-						ioinfo[irq]->ui.flags.oper   = 1;
-						ioinfo[irq]->ui.flags.consns = 1;
-						ret                          = 0;
-						break;
-      	
-					case 1:  // status pending
-						//
-						// How can we have a pending status as
-						//  device is disabled for interrupts ?
-						//  Anyway, process it ...
-						//
-						ioinfo[irq]->ui.flags.s_pend = 1;
-						s390_process_IRQ( irq);
-						ioinfo[irq]->ui.flags.s_pend = 0;
-						retry--;
-						ret = -EIO;
-						break;
-   	
-					case 2:  // busy
-						/*
-						 * we mark it not-oper as we can't
-						 *  properly operate it !
-						 */
-						ioinfo[irq]->ui.flags.oper = 0;
-						udelay( 100);	/* allow for recovery */
-						retry--;
-						ret = -EBUSY;
-						break;
+				ioinfo[irq]->ui.flags.oper = 1;
+				ioinfo[irq]->ui.flags.consns = 1;
+				ret = 0;
+				break;
 
-					case 3:  // not operational
-						ioinfo[irq]->ui.flags.oper = 0;
-						retry                      = 0;
-						ret = -ENODEV;
-						break;
+			case 1:
+				/*
+				 * status pending
+				 *
+				 * How can we have a pending status 
+				 * as the device is disabled for 
+				 * interrupts ?
+				 * Anyway, process it ...
+				 */
+				ioinfo[irq]->ui.flags.s_pend = 1;
+				s390_process_IRQ (irq);
+				ioinfo[irq]->ui.flags.s_pend = 0;
+				retry--;
+				ret = -EIO;
+				break;
+
+			case 2:
+				/*
+				 * busy
+				 *
+				 * we mark it not-oper as we can't 
+				 * properly operate it !
+				 */
+				ioinfo[irq]->ui.flags.oper = 0;
+				udelay (100);	/* allow for recovery */
+				retry--;
+				ret = -EBUSY;
+				break;
+
+			case 3:	/* not operational */
+				ioinfo[irq]->ui.flags.oper = 0;
+				retry = 0;
+				ret = -ENODEV;
+				break;
 
-					default:
+			default:
 #define PGMCHK_OPERAND_EXC      0x15
 
-						if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC )
-						{
-							/*
-							 * re-issue the modify subchannel without trying to
-							 *  enable the concurrent sense facility
-							 */
-							ioinfo[irq]->schib.pmcw.csense = 0;
-   	
-							ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
-							if ( ccode2 != 0 )
-							{
-								printk( KERN_ERR " ... msch() (2) failed with CC = %X\n",
-								        ccode2 );
-								if (cio_debug_initialized)
-									debug_sprintf_event(cio_debug_msg_id, 0,
-											    "msch() (2) failed with CC=%X\n",
-											    ccode2);
-								ioinfo[irq]->ui.flags.oper = 0;
-								ret                        = -EIO;
-							}
-							else
-							{
-								ioinfo[irq]->ui.flags.oper   = 1;
-								ioinfo[irq]->ui.flags.consns = 0;
-								ret                          = 0;
+				if ((ccode2 & PGMCHK_OPERAND_EXC)
+				    == PGMCHK_OPERAND_EXC) {
+					/*
+					 * re-issue the modify subchannel without trying to
+					 *  enable the concurrent sense facility
+					 */
+					ioinfo[irq]->schib.pmcw.csense = 0;
 
-							} /* endif */
-						}
-						else
-						{
-							printk( KERN_ERR " ... msch() (1) failed with CC = %X\n",
-							        ccode2);
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 0,
-										    "msch() (1) failed with CC = %X\n",
-										    ccode2);
-							ioinfo[irq]->ui.flags.oper = 0;
-							ret                        = -EIO;
-
-						} /* endif */
-   	
-						retry  = 0;
-						break;
+					ccode2 =
+					    msch_err (irq, &ioinfo[irq]->schib);
+
+					if (ccode2 != 0) {
+						printk (KERN_ERR
+							" ... msch() (2) failed"
+							" with CC = %X\n",
+							ccode2);
+						CIO_MSG_EVENT(0,
+							      "msch() (2) failed"
+							      " with CC=%X\n",
+							      ccode2);
+						ioinfo[irq]->ui.flags.oper = 0;
+						ret = -EIO;
+					} else {
+						ioinfo[irq]->ui.flags.oper = 1;
+						ioinfo[irq]->ui.
+						    flags.consns = 0;
+						ret = 0;
+
+					}
 
-					} /* endswitch */
+				} else {
+					printk (KERN_ERR
+						" ... msch() (1) failed with "
+						"CC = %X\n", ccode2);
+					CIO_MSG_EVENT(0,
+						      "msch() (1) failed with "
+						      "CC = %X\n", ccode2);
+					ioinfo[irq]->ui.flags.oper = 0;
+					ret = -EIO;
 
-				} while ( ccode2 && retry );
+				}
 
-				if ( (ccode2 != 0) && (ccode2 != 3) && (!retry) )
-				{
-					printk( KERN_ERR " ... msch() retry count for "
-					        "subchannel %04X exceeded, CC = %d\n",
-					        irq,
-					        ccode2);
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 0,
-								    " ... msch() retry count for "
-								    "subchannel %04X exceeded, CC = %d\n",
-								    irq, ccode2);		    
+				retry = 0;
+				break;
 
-				} /* endif */
 			}
-			else
-			{
-				/* no path available ... */
-				ioinfo[irq]->ui.flags.oper = 0;
-				ret                        = -ENODEV;    	
 
-			} /* endif */
-		     }
+		} while (ccode2 && retry);
+
+		if ((ccode2 != 0) && (ccode2 != 3)
+		    && (!retry)) {
+			printk (KERN_ERR
+				" ... msch() retry count for "
+				"subchannel %04X exceeded, CC = %d\n",
+				irq, ccode2);
+			CIO_MSG_EVENT(0,
+				      " ... msch() retry count for "
+				      "subchannel %04X exceeded, CC = %d\n",
+				      irq, ccode2);
+
 		}
-		else
-		{
-			ret = -ENODEV;
+	} else {
+		/* no path available ... */
+		ioinfo[irq]->ui.flags.oper = 0;
+		ret = -ENODEV;
 
-		} /* endif */
 	}
-	else
-	{
-		ret = -ENXIO;
 
-	} /* endif */
-
-	return( ret );
+	return (ret);
 }
 
 /*
@@ -5087,43 +5176,46 @@
  *  s390_SenseID() related device interrupts - interruption
  *  parameter used is 0x00E2C9C4 ( SID ).
  */
-int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
+int
+s390_SenseID (int irq, senseid_t * sid, __u8 lpm)
 {
-	ccw1_t    *sense_ccw;     /* ccw area for SenseID command */
-	senseid_t  isid;          /* internal sid */				
-	devstat_t  devstat;       /* required by request_irq() */
-	__u8       pathmask;      /* calulate path mask */
-	__u8       domask;        /* path mask to use */
-	int        inlreq;        /* inline request_irq() */
-	int        irq_ret;       /* return code */
-	devstat_t *pdevstat;      /* ptr to devstat in use */
-	int        retry;         /* retry count */
-	int        io_retry;      /* retry indicator */
+	ccw1_t *sense_ccw;	/* ccw area for SenseID command */
+	senseid_t isid;		/* internal sid */
+	devstat_t devstat;	/* required by request_irq() */
+	__u8 pathmask;		/* calulate path mask */
+	__u8 domask;		/* path mask to use */
+	int inlreq;		/* inline request_irq() */
+	int irq_ret;		/* return code */
+	devstat_t *pdevstat;	/* ptr to devstat in use */
+	int retry;		/* retry count */
+	int io_retry;		/* retry indicator */
 
-	senseid_t *psid     = sid;/* start with the external buffer */	
-	int        sbuffer  = 0;  /* switch SID data buffer */
+	senseid_t *psid = sid;	/* start with the external buffer */
+	int sbuffer = 0;	/* switch SID data buffer */
 
 	char dbf_txt[15];
+	int i;
+	int failure = 0;	/* nothing went wrong yet */
 
-	int failure = 0;          /* nothing went wrong yet */
+	SANITY_CHECK (irq);
 
-	SANITY_CHECK(irq);
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
 
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
+	}
 
-	} /* endif */
+ 	if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		/* don't even try it */
+ 		return -EUSERS;
+ 	}
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "snsID%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	CIO_TRACE_EVENT (4, "senseID");
+	sprintf (dbf_txt, "%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	inlreq = 0; /* to make the compiler quiet... */
+	inlreq = 0;		/* to make the compiler quiet... */
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
+	if (!ioinfo[irq]->ui.flags.ready) {
 
 		pdevstat = &devstat;
 
@@ -5133,471 +5225,421 @@
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
 		 */
-		irq_ret = request_irq( irq, init_IRQ_handler, SA_PROBE, "SID", &devstat);
+		irq_ret =
+		    request_irq (irq, init_IRQ_handler, SA_PROBE, "SID",
+				 &devstat);
 
-		if ( irq_ret == 0 )
+		if (irq_ret == 0)
 			inlreq = 1;
-	}
-	else
-	{
-		inlreq   = 0;
-		irq_ret  = 0;
+	} else {
+		inlreq = 0;
+		irq_ret = 0;
 		pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
-  	} /* endif */
+	}
 
-	if ( irq_ret == 0 )
-	{
-		int i;
+	if (irq_ret) {
+		return irq_ret;
+	}
 
-		s390irq_spin_lock( irq);
+	s390irq_spin_lock (irq);
 
-		if ( init_IRQ_complete )
-		{
-			sense_ccw = kmalloc( 2*sizeof( ccw1_t), GFP_DMA);
-		}
-		else	
-		{
-			sense_ccw = alloc_bootmem_low( 2*sizeof( ccw1_t));
-
-		} /* endif */
-
-		// more than one path installed ?
-		if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-		{
-			sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
-			sense_ccw[0].cda      = 0;
-			sense_ccw[0].count    = 0;
-			sense_ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
-
-			sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID;
-			sense_ccw[1].cda      = (__u32)virt_to_phys( sid );
-			sense_ccw[1].count    = sizeof( senseid_t);
-			sense_ccw[1].flags    = CCW_FLAG_SLI;
-		}
-		else
-		{
-			sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID;
-			sense_ccw[0].cda      = (__u32)virt_to_phys( sid );
-			sense_ccw[0].count    = sizeof( senseid_t);
-			sense_ccw[0].flags    = CCW_FLAG_SLI;
+	if (init_IRQ_complete) {
+		sense_ccw = kmalloc (2 * sizeof (ccw1_t), GFP_DMA);
+	} else {
+		sense_ccw = alloc_bootmem_low (2 * sizeof (ccw1_t));
 
-		} /* endif */
+	}
 
-		for ( i = 0 ; (i < 8) ; i++ )
-		{
-			pathmask = 0x80 >> i;						
+	/* more than one path installed ? */
+	if (ioinfo[irq]->schib.pmcw.pim != 0x80) {
+		sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
+		sense_ccw[0].cda = 0;
+		sense_ccw[0].count = 0;
+		sense_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
 
-			domask = ioinfo[irq]->opm & pathmask;
+		sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID;
+		sense_ccw[1].cda = (__u32) virt_to_phys (sid);
+		sense_ccw[1].count = sizeof (senseid_t);
+		sense_ccw[1].flags = CCW_FLAG_SLI;
+	} else {
+		sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID;
+		sense_ccw[0].cda = (__u32) virt_to_phys (sid);
+		sense_ccw[0].count = sizeof (senseid_t);
+		sense_ccw[0].flags = CCW_FLAG_SLI;
 
-			if ( lpm )
-				domask &= lpm;
+	}
 
-			if ( domask )
-			{
-				failure = 0;
-				
-				psid->reserved   = 0;
-				psid->cu_type    = 0xFFFF;  /* initialize fields ... */
-				psid->cu_model   = 0;
-				psid->dev_type   = 0;
-				psid->dev_model  = 0;
+	for (i = 0; (i < 8); i++) {
+		pathmask = 0x80 >> i;
 
-				retry            = 5;  /* retry count    */
-				io_retry         = 1;  /* enable retries */
+		domask = ioinfo[irq]->opm & pathmask;
 
-				/*
-				 * We now issue a SenseID request. In case of BUSY,
-				 *  STATUS PENDING or non-CMD_REJECT error conditions
-				 *  we run simple retries.
-				 */
-				do
-				{
-					memset( pdevstat, '\0', sizeof( devstat_t) );
-
-					irq_ret = s390_start_IO( irq,
-					                         sense_ccw,
-					                         0x00E2C9C4,  // == SID
-								 domask,
-					                         DOIO_WAIT_FOR_INTERRUPT
-					                          | DOIO_TIMEOUT
-					                          | DOIO_VALID_LPM
-					                          | DOIO_DONT_CALL_INTHDLR );
+		if (lpm)
+			domask &= lpm;
 
+		if (!domask)
+			continue;
 
-					if ( psid->cu_type  == 0xFFFF )
-					{
+		failure = 0;
 
-						failure = 1;
+		memset(psid, 0, sizeof(senseid_t));
+		psid->cu_type = 0xFFFF;	/* initialize fields ... */
 
-						if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-						{
+		retry = 5;	/* retry count    */
+		io_retry = 1;	/* enable retries */
+
+		/*
+		 * We now issue a SenseID request. In case of BUSY,
+		 *  STATUS PENDING or non-CMD_REJECT error conditions
+		 *  we run simple retries.
+		 */
+		do {
+			memset (pdevstat, '\0', sizeof (devstat_t));
+
+			irq_ret = s390_start_IO (irq, sense_ccw, 0x00E2C9C4,	/* == SID */
+						 domask,
+						 DOIO_WAIT_FOR_INTERRUPT
+						 | DOIO_TIMEOUT
+						 | DOIO_VALID_LPM
+						 | DOIO_DONT_CALL_INTHDLR);
+
+			if ((psid->cu_type != 0xFFFF)
+			    && (psid->reserved == 0xFF)) {
+				if (!sbuffer) {	/* switch buffers */
+					/*
+					 * we report back the
+					 *  first hit only
+					 */
+					psid = &isid;
+
+					if (ioinfo[irq]->schib.pmcw.pim != 0x80) {
+						sense_ccw[1].cda = (__u32)
+						    virt_to_phys (psid);
+					} else {
+						sense_ccw[0].cda = (__u32)
+						    virt_to_phys (psid);
+
+					}
+
+					/*
+					 * if just the very first
+					 *  was requested to be
+					 *  sensed disable further
+					 *  scans.
+					 */
+					if (!lpm)
+						lpm = domask;
+
+					sbuffer = 1;
+
+				}
+
+				if (pdevstat->rescnt < (sizeof (senseid_t) - 8)) {
+					ioinfo[irq]->ui.flags.esid = 1;
+
+				}
+
+				io_retry = 0;
+
+				break;
+			}
+
+			failure = 1;
+
+			if (pdevstat->flag & DEVSTAT_STATUS_PENDING) {
 #ifdef CONFIG_DEBUG_IO
-							printk( KERN_DEBUG "SenseID : device %04X on "
-							        "Subchannel %04X "
-							        "reports pending status, "
-							        "retry : %d\n",
-							        ioinfo[irq]->schib.pmcw.dev,
-								irq,
-							        retry);
-#endif
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 2,
-										    "SenseID : device %04X on "
-										    "Subchannel %04X "
-										    "reports pending status, "
-										    "retry : %d\n",
-										    ioinfo[irq]->schib.pmcw.dev,
-										    irq,
-										    retry);		    
-						} /* endif */
+				printk (KERN_DEBUG
+					"SenseID : device %04X on "
+					"Subchannel %04X "
+					"reports pending status, "
+					"retry : %d\n",
+					ioinfo[irq]->schib.pmcw.dev, irq,
+					retry);
+#endif
+				CIO_MSG_EVENT(2,
+					      "SenseID : device %04X on "
+					      "Subchannel %04X "
+					      "reports pending status, "
+					      "retry : %d\n",
+					      ioinfo
+					      [irq]->schib.pmcw.dev, irq, retry);
+			}
 
-						else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
-						{
-							/*
-							 * if the device doesn't support the SenseID
-							 *  command further retries wouldn't help ...
-							 */
-							if (  pdevstat->ii.sense.data[0]
-							    & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ) )
-							{
+			else if (pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+				/*
+				 * if the device doesn't support the SenseID
+				 *  command further retries wouldn't help ...
+				 */
+				if (pdevstat->ii.sense.data[0]
+				    & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)) {
 #ifdef CONFIG_DEBUG_IO
-								printk( KERN_ERR "SenseID : device %04X on "
-								        "Subchannel %04X "
-								        "reports cmd reject or "
-								        "intervention required\n",
-								        ioinfo[irq]->schib.pmcw.dev,
-								        irq);
-#endif
-								if (cio_debug_initialized)
-									debug_sprintf_event(cio_debug_msg_id, 2,
-											    "SenseID : device %04X on "
-											    "Subchannel %04X "
-											    "reports cmd reject or "
-											    "intervention required\n",
-											    ioinfo[irq]->schib.pmcw.dev,
-											    irq);		    
-								io_retry = 0;
-							}
+					printk (KERN_ERR
+						"SenseID : device %04X on "
+						"Subchannel %04X "
+						"reports cmd reject or "
+						"intervention required\n",
+						ioinfo[irq]->schib.pmcw.dev,
+						irq);
+#endif
+					CIO_MSG_EVENT(2,
+						      "SenseID : device %04X on "
+						      "Subchannel %04X "
+						      "reports cmd reject or "
+						      "intervention required\n",
+						      ioinfo[irq]->schib.pmcw.dev, 
+						      irq);
+					io_retry = 0;
+				} else {
+#ifdef CONFIG_DEBUG_IO
+					printk
+					    (KERN_WARNING
+					     "SenseID : UC on "
+					     "dev %04X, "
+					     "retry %d, "
+					     "lpum %02X, "
+					     "cnt %02d, "
+					     "sns :"
+					     " %02X%02X%02X%02X "
+					     "%02X%02X%02X%02X ...\n",
+					     ioinfo[irq]->schib.pmcw.dev,
+					     retry,
+					     pdevstat->lpum,
+					     pdevstat->scnt,
+					     pdevstat->ii.sense.data[0],
+					     pdevstat->ii.sense.data[1],
+					     pdevstat->ii.sense.data[2],
+					     pdevstat->ii.sense.data[3],
+					     pdevstat->ii.sense.data[4],
+					     pdevstat->ii.sense.data[5],
+					     pdevstat->ii.sense.data[6],
+					     pdevstat->ii.sense.data[7]);
+#endif
+					CIO_MSG_EVENT(2,
+						      "SenseID : UC on "
+						      "dev %04X, "
+						      "retry %d, "
+						      "lpum %02X, "
+						      "cnt %02d, "
+						      "sns :"
+						      " %02X%02X%02X%02X "
+						      "%02X%02X%02X%02X ...\n",
+						      ioinfo[irq]->
+						      schib.pmcw.dev,
+						      retry,
+						      pdevstat->lpum,
+						      pdevstat->scnt,
+						      pdevstat->
+						      ii.sense.data[0],
+						      pdevstat->
+						      ii.sense.data[1],
+						      pdevstat->
+						      ii.sense.data[2],
+						      pdevstat->
+						      ii.sense.data[3],
+						      pdevstat->
+						      ii.sense.data[4],
+						      pdevstat->
+						      ii.sense.data[5],
+						      pdevstat->
+						      ii.sense.data[6],
+						      pdevstat->
+						      ii.sense.data[7]);
 
-							else
-							{
-#ifdef CONFIG_DEBUG_IO							
-								printk( KERN_WARNING "SenseID : UC on "
-								        "dev %04X, "
-								        "retry %d, "
-								        "lpum %02X, "
-								        "cnt %02d, "
-								        "sns :"
-								        " %02X%02X%02X%02X "
-								        "%02X%02X%02X%02X ...\n",
-								        ioinfo[irq]->schib.pmcw.dev,
-								        retry,
-								        pdevstat->lpum,
-								        pdevstat->scnt,
-								        pdevstat->ii.sense.data[0],
-								        pdevstat->ii.sense.data[1],
-								        pdevstat->ii.sense.data[2],
-								        pdevstat->ii.sense.data[3],
-								        pdevstat->ii.sense.data[4],
-								        pdevstat->ii.sense.data[5],
-								        pdevstat->ii.sense.data[6],
-								        pdevstat->ii.sense.data[7]);
-#endif
-								if (cio_debug_initialized) {
-									debug_sprintf_event(cio_debug_msg_id, 2,
-											    "SenseID : UC on "
-											    "dev %04X, "
-											    "retry %d, "
-											    "lpum %02X, "
-											    "cnt %02d, "
-											    "sns :"
-											    " %02X%02X%02X%02X "
-											    "%02X%02X%02X%02X ...\n",
-											    ioinfo[irq]->schib.pmcw.dev,
-											    retry,
-											    pdevstat->lpum,
-											    pdevstat->scnt,
-											    pdevstat->ii.sense.data[0],
-											    pdevstat->ii.sense.data[1],
-											    pdevstat->ii.sense.data[2],
-											    pdevstat->ii.sense.data[3],
-											    pdevstat->ii.sense.data[4],
-											    pdevstat->ii.sense.data[5],
-											    pdevstat->ii.sense.data[6],
-											    pdevstat->ii.sense.data[7]);	    
-									if (psid->reserved != 0xFF) 
-										debug_sprintf_event(cio_debug_msg_id, 2,
-												    "SenseID was not properly "
-												    "executed!\n");
-								}
-							} /* endif */
+				}
 
-						}
-						else if (    ( pdevstat->flag & DEVSTAT_NOT_OPER )
-							  || ( irq_ret        == -ENODEV         ) )
-						{
+			} else if ((pdevstat->flag & DEVSTAT_NOT_OPER)
+				   || (irq_ret == -ENODEV)) {
 #ifdef CONFIG_DEBUG_IO
-							printk( KERN_ERR "SenseID : path %02X for "
-							        "device %04X on "
-							        "subchannel %04X "
-							        "is 'not operational'\n",
-							        domask,
-							        ioinfo[irq]->schib.pmcw.dev,
-							        irq);
-#endif
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 2, 
-										    "SenseID : path %02X for "
-										    "device %04X on "
-										    "subchannel %04X "
-										    "is 'not operational'\n",
-										    domask,
-										    ioinfo[irq]->schib.pmcw.dev,
-										    irq);		    
-
-							io_retry          = 0;
-							ioinfo[irq]->opm &= ~domask;
-      	
-						}
+				printk (KERN_ERR
+					"SenseID : path %02X for "
+					"device %04X on "
+					"subchannel %04X "
+					"is 'not operational'\n",
+					domask,
+					ioinfo[irq]->schib.pmcw.dev, irq);
+#endif
+				CIO_MSG_EVENT(2,
+					      "SenseID : path %02X for "
+					      "device %04X on "
+					      "subchannel %04X "
+					      "is 'not operational'\n",
+					      domask,
+					      ioinfo[irq]->schib.pmcw.dev, irq);
+				
+				io_retry = 0;
+				ioinfo[irq]->opm &= ~domask;
 
-						else if (     ( pdevstat->flag !=
-							       (   DEVSTAT_START_FUNCTION
-								 | DEVSTAT_FINAL_STATUS    ) )
-							   && !( pdevstat->flag &
-								DEVSTAT_STATUS_PENDING       ) )
-						{
+			} else {
 #ifdef CONFIG_DEBUG_IO
-							printk( KERN_INFO "SenseID : start_IO() for "
-							        "device %04X on "
-							        "subchannel %04X "
-							        "returns %d, retry %d, "
-							        "status %04X\n",
-							        ioinfo[irq]->schib.pmcw.dev,
-							        irq,
-							        irq_ret,
-							        retry,
-							        pdevstat->flag);
-#endif
-							if (cio_debug_initialized)
-								debug_sprintf_event(cio_debug_msg_id, 2,
-										    "SenseID : start_IO() for "
-										    "device %04X on "
-										    "subchannel %04X "
-										    "returns %d, retry %d, "
-										    "status %04X\n",
-										    ioinfo[irq]->schib.pmcw.dev,
-										    irq,
-										    irq_ret,
-										    retry,
-										    pdevstat->flag);		    
+				printk (KERN_INFO
+					"SenseID : start_IO() for "
+					"device %04X on "
+					"subchannel %04X "
+					"returns %d, retry %d, "
+					"status %04X\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					irq, irq_ret, retry, pdevstat->flag);
+#endif
+				CIO_MSG_EVENT(2,
+					     "SenseID : start_IO() for "
+					     "device %04X on "
+					     "subchannel %04X "
+					     "returns %d, retry %d, "
+					     "status %04X\n",
+					     ioinfo[irq]->schib.pmcw.dev, irq,
+					     irq_ret, retry, pdevstat->flag);
 
-						} /* endif */
+				if (irq_ret == -ETIMEDOUT) {
+					int xret;
 
-					}
-					else   // we got it ...
-					{
-						if (psid->reserved != 0xFF) {
-							/* No, we failed after all... */
-							failure = 1;
-							retry--;
-
-						} else {
-					       
-							if ( !sbuffer )	// switch buffers
-							{
-								/*
-								 * we report back the
-								 *  first hit only
-								 */
-								psid = &isid;
-								
-								if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-								{
-									sense_ccw[1].cda = (__u32)virt_to_phys( psid );
-								}
-								else
-								{
-									sense_ccw[0].cda = (__u32)virt_to_phys( psid );
-
-								} /* endif */
-
-								/*
-								 * if just the very first
-								 *  was requested to be
-								 *  sensed disable further
-								 *  scans.
-								 */	
-								if ( !lpm )
-									lpm = domask;
-								
-								sbuffer = 1;
-								
-							} /* endif */
-
-							if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) )
-							{
-								ioinfo[irq]->ui.flags.esid = 1;
-       							
-							} /* endif */
+					/*
+					 * Seems we need to cancel the first ssch sometimes...
+					 * On the next try, the ssch will usually be fine.
+					 */
 
-							io_retry = 0;
-						
-						}
+					xret = cancel_IO (irq);
 
-					} /* endif */
+					if (!xret)
+						CIO_MSG_EVENT(2,
+							      "SenseID: sch canceled "
+							      "successfully for irq %x\n",
+							      irq);
+				}
 
-					if ( io_retry )
-					{
-						retry--;
+			}
 
-						if ( retry == 0 )
-						{
-							io_retry = 0;
+			if (io_retry) {
+				retry--;
 
-						} /* endif */
-      	
-					} /* endif */
+				if (retry == 0) {
+					io_retry = 0;
 
-					if ((failure) && (io_retry)) {
-						/* reset fields... */
+				}
+			}
 
-						failure = 0;
-						
-						psid->reserved   = 0;
-						psid->cu_type    = 0xFFFF;  
-						psid->cu_model   = 0;
-						psid->dev_type   = 0;
-						psid->dev_model  = 0;
-					}
-						
-				} while ( (io_retry) );
+			if ((failure) && (io_retry)) {
+				/* reset fields... */
 
- 			} /* endif - domask */
+				failure = 0;
 
-		} /* endfor */
+				memset(psid, 0, sizeof(senseid_t));
+				psid->cu_type = 0xFFFF;
+			}
 
-		if ( init_IRQ_complete )
-		{
-			kfree( sense_ccw );
-		}
-		else	
-		{
-			free_bootmem( (unsigned long)sense_ccw, 2*sizeof(ccw1_t) );
+		} while ((io_retry));
 
-		} /* endif */
+	}
 
-		s390irq_spin_unlock( irq);
+	if (init_IRQ_complete) {
+		kfree (sense_ccw);
+	} else {
+		free_bootmem ((unsigned long) sense_ccw, 2 * sizeof (ccw1_t));
 
-		/*
-		 * If we installed the irq action handler we have to
-		 *  release it too.
-		 */
-		if ( inlreq )
-			free_irq( irq, pdevstat);
+	}
 
-		/*
-		 * if running under VM check there ... perhaps we should do
-		 *  only if we suffered a command reject, but it doesn't harm
-		 */
-		if (    ( sid->cu_type == 0xFFFF    )
-		     && ( MACHINE_IS_VM             ) )
-		{
-			VM_virtual_device_info( ioinfo[irq]->schib.pmcw.dev,
-			                        sid );
-		} /* endif */
+	s390irq_spin_unlock (irq);
 
-		if ( sid->cu_type == 0xFFFF )
-		{
-			/*
-			 * SenseID CU-type of 0xffff indicates that no device
-			 *  information could be retrieved (pre-init value).
-			 *
-			 * If we can't couldn't identify the device type we
-			 *  consider the device "not operational".
-			 */
-#ifdef CONFIG_DEBUG_IO
-			printk( KERN_WARNING "SenseID : unknown device %04X on subchannel %04X\n",
-			        ioinfo[irq]->schib.pmcw.dev,
-			        irq);
-#endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_msg_id, 2,
-						    "SenseID : unknown device %04X on subchannel %04X\n",
-						    ioinfo[irq]->schib.pmcw.dev,
-						    irq);		    
-			ioinfo[irq]->ui.flags.unknown = 1;
+	/*
+	 * If we installed the irq action handler we have to
+	 *  release it too.
+	 */
+	if (inlreq)
+		free_irq (irq, pdevstat);
 
-		} /* endif */
+	/*
+	 * if running under VM check there ... perhaps we should do
+	 *  only if we suffered a command reject, but it doesn't harm
+	 */
+	if ((sid->cu_type == 0xFFFF)
+	    && (MACHINE_IS_VM)) {
+		VM_virtual_device_info (ioinfo[irq]->schib.pmcw.dev, sid);
+	}
 
-	
+	if (sid->cu_type == 0xFFFF) {
 		/*
-		 * Issue device info message if unit was operational .
+		 * SenseID CU-type of 0xffff indicates that no device
+		 *  information could be retrieved (pre-init value).
+		 *
+		 * If we can't couldn't identify the device type we
+		 *  consider the device "not operational".
 		 */
-		if ( !ioinfo[irq]->ui.flags.unknown ) {
-			if ( sid->dev_type != 0 ) {
-				if ( cio_show_msg ) 
-					printk( KERN_INFO"SenseID : device %04X reports: "
-						"CU  Type/Mod = %04X/%02X,"
-						" Dev Type/Mod = %04X/%02X\n",
-						ioinfo[irq]->schib.pmcw.dev,
-						sid->cu_type,
-						sid->cu_model,
-						sid->dev_type,
-						sid->dev_model);
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_msg_id, 2,
-							    "SenseID : device %04X reports: "
-							    "CU  Type/Mod = %04X/%02X,"
-							    " Dev Type/Mod = %04X/%02X\n",
-							    ioinfo[irq]->schib.pmcw.dev,
-							    sid->cu_type,
-							    sid->cu_model,
-							    sid->dev_type,
-							    sid->dev_model);
-			} else {
-				if ( cio_show_msg ) 
-					printk( KERN_INFO"SenseID : device %04X reports:"
-						" Dev Type/Mod = %04X/%02X\n",
-						ioinfo[irq]->schib.pmcw.dev,
-						sid->cu_type,
-						sid->cu_model);
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_msg_id, 2,
-							    "SenseID : device %04X reports:"
-							    " Dev Type/Mod = %04X/%02X\n",
-							    ioinfo[irq]->schib.pmcw.dev,
-							    sid->cu_type,
-							    sid->cu_model);		    
-			} /* endif */
+#ifdef CONFIG_DEBUG_IO
+		printk (KERN_WARNING
+			"SenseID : unknown device %04X on subchannel %04X\n",
+			ioinfo[irq]->schib.pmcw.dev, irq);
+#endif
+		CIO_MSG_EVENT(2,
+			      "SenseID : unknown device %04X on subchannel %04X\n",
+			      ioinfo[irq]->schib.pmcw.dev, irq);
+		ioinfo[irq]->ui.flags.unknown = 1;
 
-		} /* endif */
+	}
 
-		if ( !ioinfo[irq]->ui.flags.unknown )
-			irq_ret = 0;
-		else
-			irq_ret = -ENODEV;
+	/*
+	 * Issue device info message if unit was operational .
+	 */
+	if (!ioinfo[irq]->ui.flags.unknown) {
+		if (sid->dev_type != 0) {
+			if (cio_show_msg)
+				printk (KERN_INFO
+					"SenseID : device %04X reports: "
+					"CU  Type/Mod = %04X/%02X,"
+					" Dev Type/Mod = %04X/%02X\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					sid->cu_type, sid->cu_model,
+					sid->dev_type, sid->dev_model);
+			CIO_MSG_EVENT(2,
+				      "SenseID : device %04X reports: "
+				      "CU  Type/Mod = %04X/%02X,"
+				      " Dev Type/Mod = %04X/%02X\n",
+				      ioinfo[irq]->schib.
+				      pmcw.dev,
+				      sid->cu_type,
+				      sid->cu_model,
+				      sid->dev_type,
+				      sid->dev_model);
+		} else {
+			if (cio_show_msg)
+				printk (KERN_INFO
+					"SenseID : device %04X reports:"
+					" Dev Type/Mod = %04X/%02X\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					sid->cu_type, sid->cu_model);
+			CIO_MSG_EVENT(2,
+				      "SenseID : device %04X reports:"
+				      " Dev Type/Mod = %04X/%02X\n",
+				      ioinfo[irq]->schib.
+				      pmcw.dev,
+				      sid->cu_type,
+				      sid->cu_model);
+		}
 
-	} /* endif */
+	}
+
+	if (!ioinfo[irq]->ui.flags.unknown)
+		irq_ret = 0;
+	else
+		irq_ret = -ENODEV;
 
-   return( irq_ret );
+	return (irq_ret);
 }
 
-static int __inline__ s390_SetMultiPath( int irq )
+static int __inline__
+s390_SetMultiPath (int irq)
 {
 	int cc;
 
-	cc = stsch( irq, &ioinfo[irq]->schib );
+	cc = stsch (irq, &ioinfo[irq]->schib);
 
-	if ( !cc )
-	{
-		ioinfo[irq]->schib.pmcw.mp = 1;     /* multipath mode */
+	if (!cc) {
+		ioinfo[irq]->schib.pmcw.mp = 1;	/* multipath mode */
 
-		cc = msch( irq, &ioinfo[irq]->schib );
+		cc = msch (irq, &ioinfo[irq]->schib);
 
-	} /* endif */
+	}
 
-	return( cc);
+	return (cc);
 }
 
 /*
@@ -5610,182 +5652,308 @@
  * Note : This function must not be called during normal device recognition,
  *         but during device driver initiated request_irq() processing only.
  */
-int s390_DevicePathVerification( int irq, __u8 usermask )
+int
+s390_DevicePathVerification (int irq, __u8 usermask)
 {
-	int  ccode;
+	int ccode;
 	__u8 pathmask;
 	__u8 domask;
+#ifdef CONFIG_CHSC
+	int chp;
+	int mask;
+	int old_opm = 0;
+#endif /* CONFIG_CHSC */
 
 	int ret = 0;
+	int i;
+	pgid_t pgid;
+	__u8 dev_path;
+	int first = 1;
 
 	char dbf_txt[15];
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt, "dpver%x", irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
-
-	if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
-	{
-		return( 0);	// just exit ...
+	sprintf (dbf_txt, "dpvf%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	} /* endif */
+	if (ioinfo[irq]->st) 
+		return -ENODEV;
 
-	ccode = stsch( irq, &(ioinfo[irq]->schib) );
+#ifdef CONFIG_CHSC
+	old_opm = ioinfo[irq]->opm;
+#endif /* CONFIG_CHSC */
+	ccode = stsch (irq, &(ioinfo[irq]->schib));
 
-	if ( ccode )
-	{
-		ret = -ENODEV;
+	if (ccode) {
+		return -ENODEV;
 	}
-	else if ( ioinfo[irq]->schib.pmcw.pim == 0x80 )
-	{
+	if (ioinfo[irq]->schib.pmcw.pim == 0x80) {
 		/*
 		 * no error, just not required for single path only devices
-		 */	
+		 */
 		ioinfo[irq]->ui.flags.pgid_supp = 0;
 		ret = 0;
+
+#ifdef CONFIG_CHSC
+		/*
+		 * disable if chpid is logically offline
+		 */
+		if (!test_bit(ioinfo[irq]->schib.pmcw.chpid[0], 
+			      &chpids_logical)) {
+			not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+			int was_oper = ioinfo[irq]->ui.flags.oper;
+
+			ioinfo[irq]->opm = 0;
+			ioinfo[irq]->ui.flags.oper = 0;
+			printk(KERN_WARNING 
+			       "No logical path for sch %d...\n",
+			       irq);
+			if (old_opm && 
+			    was_oper && 
+			    ioinfo[irq]->ui.flags.ready) {
+#ifdef CONFIG_PROC_FS
+				if (cio_proc_devinfo)
+					cio_procfs_device_remove
+						(ioinfo[irq]->devno);
+#endif /* CONFIG_PROC_FS */
+				free_irq( irq, ioinfo[irq]->irq_desc.dev_id);
+				if (nopfunc)
+					nopfunc( irq, DEVSTAT_DEVICE_GONE);
+			}
+			ret = -ENODEV;
+		} else if (!old_opm) {
+
+			/*
+			 * check for opm...
+			 */
+			ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
+				& ioinfo[irq]->schib.pmcw.pam
+				& ioinfo[irq]->schib.pmcw.pom;
+				
+			if (ioinfo[irq]->opm) {
+				devreg_t *pdevreg;
+
+				ioinfo[irq]->ui.flags.oper = 1;
+				pdevreg = s390_search_devreg( ioinfo[irq] );
+
+				if (pdevreg) 
+					if (pdevreg->oper_func)
+						pdevreg->oper_func
+							( irq, pdevreg);
+#ifdef CONFIG_PROC_FS
+				if (cio_proc_devinfo) 
+					if (highest_subchannel 
+					    < MAX_CIO_PROCFS_ENTRIES) {
+						cio_procfs_device_create
+							(ioinfo[irq]->devno);
+					}
+#endif /* CONFIG_PROC_FS */
+			}
+			ret = 0;
+		} else {
+			ret = 0;
+		}
+#endif /* CONFIG_CHSC */
+		return ret;
 	}
-	else
-	{
-		int    i;
-		pgid_t pgid;
-		__u8   dev_path;
-		int    first  = 1;
-
-		ioinfo[irq]->opm =   ioinfo[irq]->schib.pmcw.pim
-		                   & ioinfo[irq]->schib.pmcw.pam
-		                   & ioinfo[irq]->schib.pmcw.pom;
-
-		if ( usermask )
-		{
-			dev_path = usermask;
+
+	ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
+	    & ioinfo[irq]->schib.pmcw.pam & ioinfo[irq]->schib.pmcw.pom;
+
+#ifdef CONFIG_CHSC
+	if (ioinfo[irq]->opm) {
+		for (chp=0;chp<=7;chp++) {
+			mask = 0x80 >> chp;
+			if (ioinfo[irq]->opm & mask) {
+				if (!test_bit
+				    (ioinfo[irq]->schib.pmcw.chpid[chp], 
+				     &chpids_logical)) {
+					/* disable using this path */
+					ioinfo[irq]->opm &= ~mask;
+				}
+			}
 		}
-		else
-		{
-			dev_path = ioinfo[irq]->opm;
+	}
+	
+	if ((ioinfo[irq]->opm == 0) && (old_opm)) {
+		not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+		int was_oper = ioinfo[irq]->ui.flags.ready;
 
-		} /* endif */
+		ioinfo[irq]->ui.flags.oper = 0;
+		printk(KERN_WARNING "No logical path for sch %d...\n",irq);
+		if (was_oper && ioinfo[irq]->ui.flags.oper) {
+#ifdef CONFIG_PROC_FS
+			if (cio_proc_devinfo)
+				cio_procfs_device_remove(ioinfo[irq]->devno);
+#endif /* CONFIG_PROC_FS */
+				free_irq( irq, ioinfo[irq]->irq_desc.dev_id);
+				if (nopfunc)
+					nopfunc( irq, DEVSTAT_DEVICE_GONE);
+		}
+		return -ENODEV;
+	}
 
-		/*
-		 * let's build a path group ID if we don't have one yet
-		 */
-		if ( ioinfo[irq]->ui.flags.pgid == 0)
-		{
-			ioinfo[irq]->pgid.cpu_addr  = *(__u16 *)__LC_CPUADDR;
-			ioinfo[irq]->pgid.cpu_id    = ((cpuid_t *)__LC_CPUID)->ident;
-			ioinfo[irq]->pgid.cpu_model = ((cpuid_t *)__LC_CPUID)->machine;
-			ioinfo[irq]->pgid.tod_high  = *(__u32 *)&irq_IPL_TOD;
+	if (!old_opm) {
+		/* Hey, we have a new logical path... */
+		devreg_t *pdevreg;
+		
+		ioinfo[irq]->ui.flags.oper = 1;
+		pdevreg = s390_search_devreg( ioinfo[irq] );
+		
+		if (pdevreg) 
+			if (pdevreg->oper_func)
+				pdevreg->oper_func( irq, pdevreg);
+#ifdef CONFIG_PROC_FS		
+		if (cio_proc_devinfo) 
+			if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
+				cio_procfs_device_create(ioinfo[irq]->devno);
+			}
+#endif /* CONFIG_PROC_FS */
+	}
+#endif /* CONFIG_CHSC */
 
-			ioinfo[irq]->ui.flags.pgid  = 1;
+	if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
+		return( 0);	/* just exit ... */
 
-		} /* endif */     		
+	if (usermask) {
+		dev_path = usermask;
+	} else {
+		dev_path = ioinfo[irq]->opm;
 
-		memcpy( &pgid, &ioinfo[irq]->pgid, sizeof(pgid_t));
+	}
 
-		for ( i = 0; i < 8 && !ret ; i++)
-		{
-			pathmask = 0x80 >> i;						
+	if (ioinfo[irq]->ui.flags.pgid == 0) {
+		memcpy (&ioinfo[irq]->pgid, global_pgid, sizeof (pgid_t));
+		ioinfo[irq]->ui.flags.pgid = 1;
+	}
 
-			domask = dev_path & pathmask;
+	for (i = 0; i < 8 && !ret; i++) {
+		pathmask = 0x80 >> i;
 
-			if ( domask )
-			{
-				ret = s390_SetPGID( irq, domask, &pgid );
+		domask = dev_path & pathmask;
 
-				/*
-				 * For the *first* path we are prepared
-				 *  for recovery
-				 *
-				 *  - If we fail setting the PGID we assume its
-				 *     using  a different PGID already (VM) we
-				 *     try to sense.
-				 */
-				if ( ret == -EOPNOTSUPP && first )
-				{
-					*(int *)&pgid = 0;
-					
-					ret   = s390_SensePGID( irq, domask, &pgid);
-					first = 0;
+		if (domask) {
+			ret = s390_SetPGID (irq, domask);
 
-					if ( ret == 0 )
-					{
-						/*
-						 * Check whether we retrieved
-						 *  a reasonable PGID ...
-						 */	
-						if ( pgid.inf.ps.state1 == SNID_STATE1_GROUPED )
-						{
-							memcpy( &(ioinfo[irq]->pgid),
-							        &pgid,
-							        sizeof(pgid_t) );
-						}
-						else // ungrouped or garbage ...
-						{
-							ret = -EOPNOTSUPP;
+			/*
+			 * For the *first* path we are prepared
+			 *  for recovery
+			 *
+			 *  - If we fail setting the PGID we assume its
+			 *     using  a different PGID already (VM) we
+			 *     try to sense.
+			 */
+			if (ret == -EOPNOTSUPP && first) {
+				*(int *) &pgid = 0;
+
+				ret = s390_SensePGID (irq, domask, &pgid);
+				first = 0;
+
+				if (ret == 0) {
+					/*
+					 * Check whether we retrieved
+					 *  a reasonable PGID ...
+					 */
+					if (pgid.inf.ps.state1 ==
+					    SNID_STATE1_GROUPED) {
+						memcpy (&ioinfo[irq]->pgid,
+							&pgid, sizeof (pgid_t));
+					} else {	/* ungrouped or garbage ... */
+						ret = -EOPNOTSUPP;
 
-						} /* endif */
 					}
-					else
-					{
-						ioinfo[irq]->ui.flags.pgid_supp = 0;
+				} else {
+					ioinfo[irq]->ui.flags.pgid_supp = 0;
 
 #ifdef CONFIG_DEBUG_IO
-						printk( KERN_WARNING "PathVerification(%04X) "
-						        "- Device %04X doesn't "
-						        " support path grouping\n",
-						        irq,
-						        ioinfo[irq]->schib.pmcw.dev);
-#endif
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "PathVerification(%04X) "
-									    "- Device %04X doesn't "
-									    " support path grouping\n",
-									    irq,
-									    ioinfo[irq]->schib.pmcw.dev);		    
-
-					} /* endif */
+					printk (KERN_WARNING
+						"PathVerification(%04X) "
+						"- Device %04X doesn't "
+						" support path grouping\n",
+						irq,
+						ioinfo[irq]->schib.pmcw.dev);
+#endif
+					CIO_MSG_EVENT(2,
+						      "PathVerification(%04X) "
+						      "- Device %04X doesn't "
+						      " support path grouping\n",
+						      irq,
+						      ioinfo[irq]->schib.
+						      pmcw.dev);
+					
 				}
-				else if ( ret == -EIO ) 
-				{
+			} else if (ret == -EIO) {
 #ifdef CONFIG_DEBUG_IO
-					printk( KERN_ERR "PathVerification(%04X) - I/O error "
-					       "on device %04X\n", irq,
-					       ioinfo[irq]->schib.pmcw.dev);
+				printk (KERN_ERR
+					"PathVerification(%04X) - I/O error "
+					"on device %04X\n", irq,
+					ioinfo[irq]->schib.pmcw.dev);
 #endif
 
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 2,
-								    "PathVerification(%04X) - I/O error "
-								    "on device %04X\n", irq,
-								    ioinfo[irq]->schib.pmcw.dev);
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) - I/O error "
+					      "on device %04X\n", irq,
+					      ioinfo[irq]->schib.pmcw.dev);
+				
+				ioinfo[irq]->ui.flags.pgid_supp = 0;
 
-					ioinfo[irq]->ui.flags.pgid_supp = 0;
-		    
-				} else {
+			} else if (ret == -ETIMEDOUT) {
 #ifdef CONFIG_DEBUG_IO
-					printk( KERN_ERR "PathVerification(%04X) "
-						"- Unexpected error on device %04X\n",
-						irq,
-						ioinfo[irq]->schib.pmcw.dev);
+				printk (KERN_ERR
+					"PathVerification(%04X) - I/O timed "
+					"out on device %04X\n", 
+					irq,
+					ioinfo[irq]->schib.pmcw.dev);
 #endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 2,
-								    "PathVerification(%04X) - "
-								    "Unexpected error on device %04X\n",
-								    irq,
-								    ioinfo[irq]->schib.pmcw.dev);		    
-					
-					ioinfo[irq]->ui.flags.pgid_supp = 0;
-					
-				} /* endif */
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) - I/O timed "
+					      "out on device %04X\n", irq,
+					      ioinfo[irq]->schib.pmcw.dev);
+				
+				ioinfo[irq]->ui.flags.pgid_supp = 0;
 
-			} /* endif */
-			
-		} /* endfor */
+			} else if (ret == -EAGAIN) {
 
-	} /* endif */
+				ret = 0;
 
+			} else if (ret == -EUSERS) {
+				
+#ifdef CONFIG_DEBUG_IO
+				printk (KERN_ERR 
+					"PathVerification(%04X) "
+					"- Device is locked by someone else!\n",
+					irq);
+#endif
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) "
+					      "- Device is locked by someone else!\n",
+					      irq);
+			} else if (ret == -ENODEV) {
+#ifdef CONFIG_DEBUG_IO
+				printk (KERN_ERR 
+					"PathVerification(%04X) "
+					"- Device %04X is no longer there?!?\n",
+					irq, ioinfo[irq]->schib.pmcw.dev);
+#endif
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) "
+					      "- Device %04X is no longer there?!?\n",
+					      irq, ioinfo[irq]->schib.pmcw.dev);
+			} else if (ret) {
+#ifdef CONFIG_DEBUG_IO
+				printk (KERN_ERR
+					"PathVerification(%04X) "
+					"- Unexpected error %d on device %04X\n",
+					irq, ret, ioinfo[irq]->schib.pmcw.dev);
+#endif
+				CIO_MSG_EVENT(2,
+					      "PathVerification(%04X) - "
+					      "Unexpected error %d on device %04X\n",
+					      irq, ret, ioinfo[irq]->schib.pmcw.dev);
+				
+				ioinfo[irq]->ui.flags.pgid_supp = 0;
+			}
+		}
+	}
 	return ret;
 
 }
@@ -5796,275 +5964,285 @@
  * Set Path Group ID
  *
  */
-int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
+int
+s390_SetPGID (int irq, __u8 lpm)
 {
-	ccw1_t    *spid_ccw;    /* ccw area for SPID command */
-	devstat_t  devstat;     /* required by request_irq() */
+	ccw1_t *spid_ccw;	/* ccw area for SPID command */
+	devstat_t devstat;	/* required by request_irq() */
 	devstat_t *pdevstat = &devstat;
-        unsigned long flags;
+	unsigned long flags;
 	char dbf_txt[15];
 
+	int irq_ret = 0;	/* return code */
+	int retry = 5;		/* retry count */
+	int inlreq = 0;		/* inline request_irq() */
+	int mpath = 1;		/* try multi-path first */
 
-	int        irq_ret = 0; /* return code */
-	int        retry   = 5; /* retry count */
-	int        inlreq  = 0; /* inline request_irq() */
-	int        mpath   = 1; /* try multi-path first */
+	SANITY_CHECK (irq);
 
-	SANITY_CHECK(irq);
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
 
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
+	}
 
-	} /* endif */
+ 	if (ioinfo[irq]->ui.flags.unfriendly) {
+ 		/* don't even try it */
+ 		return -EUSERS;
+ 	}
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"SPID%x",irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
-	}
+	sprintf (dbf_txt, "SPID%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
+	if (!ioinfo[irq]->ui.flags.ready) {
 		/*
 		 * Perform SetPGID command processing. We have to request device
 		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
 		 */
-		irq_ret = request_irq( irq,
-		                       init_IRQ_handler,
-		                       SA_PROBE,
-		                       "SPID",
-		                       pdevstat);
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE, "SPID", pdevstat);
 
-		if ( irq_ret == 0 )
+		if (irq_ret == 0)
 			inlreq = 1;
-	}
-	else
-	{
+	} else {
 		pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
-	} /* endif */
-
-	if ( irq_ret == 0 )
-	{
-		s390irq_spin_lock_irqsave( irq, flags);
+	}
 
-		if ( init_IRQ_complete )
-		{
-			spid_ccw = kmalloc( 2*sizeof( ccw1_t), GFP_DMA);
-		}
-		else	
-		{
-			spid_ccw = alloc_bootmem_low( 2*sizeof( ccw1_t));
+	if (irq_ret) {
+		return irq_ret;
+	}
 
-		} /* endif */
+	s390irq_spin_lock_irqsave (irq, flags);
 
-		spid_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;	
-		spid_ccw[0].cda      = 0;
-		spid_ccw[0].count    = 0;
-		spid_ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
+	if (init_IRQ_complete) {
+		spid_ccw = kmalloc (2 * sizeof (ccw1_t), GFP_DMA);
+	} else {
+		spid_ccw = alloc_bootmem_low (2 * sizeof (ccw1_t));
 
-		spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
-		spid_ccw[1].cda      = (__u32)virt_to_phys( pgid );
-		spid_ccw[1].count    = sizeof( pgid_t);
-		spid_ccw[1].flags    = CCW_FLAG_SLI;
+	}
 
-		pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
+	spid_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
+	spid_ccw[0].cda = 0;
+	spid_ccw[0].count = 0;
+	spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
 
-		/*
-		 * We now issue a SetPGID request. In case of BUSY
-		 *  or STATUS PENDING conditions we retry 5 times.
-		 */
-		do
-		{
-			memset( pdevstat, '\0', sizeof( devstat_t) );
+	spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
+	spid_ccw[1].cda = (__u32) virt_to_phys (&ioinfo[irq]->pgid);
+	spid_ccw[1].count = sizeof (pgid_t);
+	spid_ccw[1].flags = CCW_FLAG_SLI;
 
-			irq_ret = s390_start_IO( irq,
-			                         spid_ccw,
-			                         0xE2D7C9C4,  // == SPID
-			                         lpm,         // n/a
-			                         DOIO_WAIT_FOR_INTERRUPT
-			                          | DOIO_VALID_LPM
-			                          | DOIO_DONT_CALL_INTHDLR );
+	ioinfo[irq]->pgid.inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
 
-			if ( !irq_ret )
-			{
-				if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-				{
-#ifdef CONFIG_DEBUG_IO
-					printk( KERN_DEBUG "SPID - Device %04X "
-					        "on Subchannel %04X "
-					        "reports pending status, "
-					        "retry : %d\n",
-					        ioinfo[irq]->schib.pmcw.dev,
-					        irq,
-					        retry);
-#endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 2,
-								    "SPID - Device %04X "
-								    "on Subchannel %04X "
-								    "reports pending status, "
-								    "retry : %d\n",
-								    ioinfo[irq]->schib.pmcw.dev,
-								    irq,
-								    retry);	    
-					retry--;
-					irq_ret = -EIO;
-				} /* endif */
+	/*
+	 * We now issue a SetPGID request. In case of BUSY
+	 *  or STATUS PENDING conditions we retry 5 times.
+	 */
+	do {
+		memset (pdevstat, '\0', sizeof (devstat_t));
 
-				if ( pdevstat->flag == (   DEVSTAT_START_FUNCTION
-				                         | DEVSTAT_FINAL_STATUS   ) )
-				{
-					retry = 0;	// successfully set ...
-					irq_ret = 0;
-				}
-				else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
-				{
-					/*
-					 * If the device doesn't support the
-					 *  Sense Path Group ID command
-					 *  further retries wouldn't help ...
-					 */
-					if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
-					{
-						if ( mpath )
-						{
-							/*
-							 * We now try single path mode.
-							 * Note we must not issue the suspend
-							 * multipath reconnect, or we will get
-							 * a command reject by tapes.
-							 */
-							
-							spid_ccw[0].cmd_code = CCW_CMD_SET_PGID;
-							spid_ccw[0].cda      = (__u32)virt_to_phys( pgid );
-							spid_ccw[0].count    = sizeof( pgid_t);
-							spid_ccw[0].flags    = CCW_FLAG_SLI;
-
-							pgid->inf.fc =   SPID_FUNC_SINGLE_PATH
-							               | SPID_FUNC_ESTABLISH;
-							mpath        = 0;
-							retry--;
-							irq_ret = -EIO;
-						}
-						else
-						{
-							irq_ret = -EOPNOTSUPP;
-							retry   = 0;			
+		irq_ret = s390_start_IO (irq, spid_ccw, 0xE2D7C9C4,	/* == SPID */
+					 lpm,	/* n/a */
+					 DOIO_WAIT_FOR_INTERRUPT
+					 | DOIO_VALID_LPM
+					 | DOIO_DONT_CALL_INTHDLR
+					 | DOIO_TIMEOUT);
 
-						} /* endif */
-					}
-					else
-					{
+		if (!irq_ret) {
+			if (pdevstat->flag & DEVSTAT_STATUS_PENDING) {
 #ifdef CONFIG_DEBUG_IO
-						printk( KERN_WARNING "SPID - device %04X,"
-						        " unit check,"
-						        " retry %d, cnt %02d,"
-						        " sns :"
-						        " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-						        ioinfo[irq]->schib.pmcw.dev,
-						        retry,
-						        pdevstat->scnt,
-						        pdevstat->ii.sense.data[0],
-						        pdevstat->ii.sense.data[1],
-						        pdevstat->ii.sense.data[2],
-						        pdevstat->ii.sense.data[3],
-						        pdevstat->ii.sense.data[4],
-						        pdevstat->ii.sense.data[5],
-						        pdevstat->ii.sense.data[6],
-						        pdevstat->ii.sense.data[7]);
-#endif
-
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "SPID - device %04X,"
-									    " unit check,"
-									    " retry %d, cnt %02d,"
-									    " sns :"
-									    " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-									    ioinfo[irq]->schib.pmcw.dev,
-									    retry,
-									    pdevstat->scnt,
-									    pdevstat->ii.sense.data[0],
-									    pdevstat->ii.sense.data[1],
-									    pdevstat->ii.sense.data[2],
-									    pdevstat->ii.sense.data[3],
-									    pdevstat->ii.sense.data[4],
-									    pdevstat->ii.sense.data[5],
-									    pdevstat->ii.sense.data[6],
-									    pdevstat->ii.sense.data[7]);
+				printk (KERN_DEBUG "SPID - Device %04X "
+					"on Subchannel %04X "
+					"reports pending status, "
+					"retry : %d\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					irq, retry);
+#endif
+				CIO_MSG_EVENT(2,
+					      "SPID - Device %04X "
+					      "on Subchannel %04X "
+					      "reports pending status, "
+					      "retry : %d\n",
+					      ioinfo[irq]->schib.pmcw.
+					      dev, irq, retry);
+				retry--;
+				irq_ret = -EIO;
+			}
+
+			if (pdevstat->flag == (DEVSTAT_START_FUNCTION
+					       | DEVSTAT_FINAL_STATUS)) {
+				retry = 0;	/* successfully set ... */
+				irq_ret = 0;
+			} else if (pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+				/*
+				 * If the device doesn't support the
+				 *  Sense Path Group ID command
+				 *  further retries wouldn't help ...
+				 */
+				if (pdevstat->ii.sense.
+				    data[0] & SNS0_CMD_REJECT) {
+					if (mpath) {
+						/*
+						 * We now try single path mode.
+						 * Note we must not issue the suspend
+						 * multipath reconnect, or we will get
+						 * a command reject by tapes.
+						 */
 
+						spid_ccw[0].cmd_code =
+						    CCW_CMD_SET_PGID;
+						spid_ccw[0].cda = (__u32)
+						    virt_to_phys (&ioinfo[irq]->pgid);
+						spid_ccw[0].count =
+						    sizeof (pgid_t);
+						spid_ccw[0].flags =
+						    CCW_FLAG_SLI;
+
+						ioinfo[irq]->pgid.inf.fc =
+						    SPID_FUNC_SINGLE_PATH
+						    | SPID_FUNC_ESTABLISH;
+						mpath = 0;
 						retry--;
 						irq_ret = -EIO;
-		    
-					} /* endif */
+					} else {
+						irq_ret = -EOPNOTSUPP;
+						retry = 0;
 
-				}
-				else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
-				{
-					/* don't issue warnings during startup unless requested*/
-					if (init_IRQ_complete || cio_notoper_msg) {   
-						
-						printk( KERN_WARNING "SPID - Device %04X "
-							"on Subchannel %04X "
-							"became 'not operational'\n",
-							ioinfo[irq]->schib.pmcw.dev,
-							irq);
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "SPID - Device %04X "
-									    "on Subchannel %04X "
-									    "became 'not operational'\n",
-									    ioinfo[irq]->schib.pmcw.dev,
-									    irq);		    
 					}
+				} else {
+#ifdef CONFIG_DEBUG_IO
+					printk (KERN_WARNING
+						"SPID - device %04X,"
+						" unit check,"
+						" retry %d, cnt %02d,"
+						" sns :"
+						" %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+						ioinfo[irq]->schib.pmcw.
+						dev, retry,
+						pdevstat->scnt,
+						pdevstat->ii.sense.
+						data[0],
+						pdevstat->ii.sense.
+						data[1],
+						pdevstat->ii.sense.
+						data[2],
+						pdevstat->ii.sense.
+						data[3],
+						pdevstat->ii.sense.
+						data[4],
+						pdevstat->ii.sense.
+						data[5],
+						pdevstat->ii.sense.
+						data[6],
+						pdevstat->ii.sense.data[7]);
+#endif
+
+					CIO_MSG_EVENT(2,
+						     "SPID - device %04X,"
+						     " unit check,"
+						     " retry %d, cnt %02d,"
+						     " sns :"
+						     " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+						     ioinfo[irq]->schib.
+						     pmcw.dev, retry,
+						     pdevstat->scnt,
+						     pdevstat->ii.sense.
+						     data[0],
+						     pdevstat->ii.sense.
+						     data[1],
+						     pdevstat->ii.sense.
+						     data[2],
+						     pdevstat->ii.sense.
+						     data[3],
+						     pdevstat->ii.sense.
+						     data[4],
+						     pdevstat->ii.sense.
+						     data[5],
+						     pdevstat->ii.sense.
+						     data[6],
+						     pdevstat->ii.sense.
+						     data[7]);
 
-					retry = 0;
+					retry--;
 					irq_ret = -EIO;
 
-				} /* endif */
+				}
+
+			} else if (pdevstat->flag & DEVSTAT_NOT_OPER) {
+				/* don't issue warnings during startup unless requested */
+				if (init_IRQ_complete || cio_notoper_msg) {
+
+					printk (KERN_WARNING
+						"SPID - Device %04X "
+						"on Subchannel %04X, "
+						"lpm %02X, "
+						"became 'not operational'\n",
+						ioinfo[irq]->schib.pmcw.
+						dev, irq,
+						lpm);
+					CIO_MSG_EVENT(2,
+						     "SPID - Device %04X "
+						     "on Subchannel %04X, "
+						      "lpm %02X, "
+						     "became 'not operational'\n",
+						     ioinfo[irq]->schib.
+						     pmcw.dev, irq,
+						     lpm);
+				}
+
+				retry = 0;
+				ioinfo[irq]->opm &= ~lpm;
+				irq_ret = -EAGAIN;
+
 			}
-			else if ( irq_ret != -ENODEV )
-			{
-				retry--;
-				irq_ret = -EIO;
-			}
-			else
-			{
-				retry = 0;
-				irq_ret = -ENODEV;
 
-			} /* endif */
+		} else if (irq_ret == -ETIMEDOUT) {
+			/* 
+			 * SetPGID timed out, so we cancel it before
+			 * we retry
+			 */
+			int xret;
 
-		} while ( retry > 0 );
+			xret = cancel_IO(irq);
 
+			if (!xret) 
+				CIO_MSG_EVENT(2,
+					      "SetPGID: sch canceled "
+					      "successfully for irq %x\n",
+					      irq);
+			retry--;
+
+		} else if (irq_ret != -ENODEV) {
+			retry--;
+			irq_ret = -EIO;
+		} else {
+			retry = 0;
+			irq_ret = -ENODEV;
 
-		if ( init_IRQ_complete )
-		{
-			kfree( spid_ccw );
 		}
-		else	
-		{
-			free_bootmem( (unsigned long)spid_ccw, 2*sizeof(ccw1_t) );
 
-		} /* endif */
+	} while (retry > 0);
 
-		s390irq_spin_unlock_irqrestore( irq, flags);
+	if (init_IRQ_complete) {
+		kfree (spid_ccw);
+	} else {
+		free_bootmem ((unsigned long) spid_ccw, 2 * sizeof (ccw1_t));
 
-		/*
-		 * If we installed the irq action handler we have to
-		 *  release it too.
-		 */
-		if ( inlreq )
-			free_irq( irq, pdevstat);
+	}
 
-	} /* endif */
+	s390irq_spin_unlock_irqrestore (irq, flags);
 
-   return( irq_ret );
-}
+	/*
+	 * If we installed the irq action handler we have to
+	 *  release it too.
+	 */
+	if (inlreq)
+		free_irq (irq, pdevstat);
 
+	return (irq_ret);
+}
 
 /*
  * s390_SensePGID
@@ -6072,253 +6250,1360 @@
  * Sense Path Group ID
  *
  */
-int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
+int
+s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid)
 {
-	ccw1_t    *snid_ccw;    /* ccw area for SNID command */
-	devstat_t  devstat;     /* required by request_irq() */
+	ccw1_t *snid_ccw;	/* ccw area for SNID command */
+	devstat_t devstat;	/* required by request_irq() */
 	devstat_t *pdevstat = &devstat;
 	char dbf_txt[15];
+	pgid_t * tmp_pgid;
 
-	int        irq_ret = 0; /* return code */
-	int        retry   = 5; /* retry count */
-	int        inlreq  = 0; /* inline request_irq() */
+	int irq_ret = 0;	/* return code */
+	int retry = 5;		/* retry count */
+	int inlreq = 0;		/* inline request_irq() */
 	unsigned long flags;
 
-	SANITY_CHECK(irq);
-
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
+	SANITY_CHECK (irq);
 
-	} /* endif */
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
 
-	if (cio_debug_initialized) {
-		sprintf(dbf_txt,"SNID%x",irq);
-		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
 	}
 
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
+	sprintf (dbf_txt, "SNID%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	if (!ioinfo[irq]->ui.flags.ready) {
 		/*
 		 * Perform SENSE PGID command processing. We have to request device
 		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
 		 */
-		irq_ret = request_irq( irq,
-		                       init_IRQ_handler,
-		                       SA_PROBE,
-		                       "SNID",
-		                       pdevstat);
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE, "SNID", pdevstat);
 
-		if ( irq_ret == 0 )
+		if (irq_ret == 0)
 			inlreq = 1;
 
-   }
-	else
-	{
+	} else {
 		pdevstat = ioinfo[irq]->irq_desc.dev_id;
 
-	} /* endif */
+	}
+
+	if (irq_ret) {
+		return irq_ret;
+	}
+
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	ioinfo[irq]->ui.flags.unfriendly = 0; /* assume it's friendly... */
+
+	if (init_IRQ_complete) {
+		snid_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA);
+		tmp_pgid = kmalloc (sizeof (pgid_t), GFP_DMA);
+	} else {
+		snid_ccw = alloc_bootmem_low (sizeof (ccw1_t));
+		tmp_pgid = alloc_bootmem_low (sizeof (pgid_t));
+	}
+
+	snid_ccw->cmd_code = CCW_CMD_SENSE_PGID;
+	snid_ccw->cda = (__u32) virt_to_phys (tmp_pgid);
+	snid_ccw->count = sizeof (pgid_t);
+	snid_ccw->flags = CCW_FLAG_SLI;
+
+	/*
+	 * We now issue a SensePGID request. In case of BUSY
+	 *  or STATUS PENDING conditions we retry 5 times.
+	 */
+	do {
+		memset (pdevstat, '\0', sizeof (devstat_t));
+
+		irq_ret = s390_start_IO (irq, snid_ccw, 0xE2D5C9C4,	/* == SNID */
+					 lpm,	/* n/a */
+					 DOIO_WAIT_FOR_INTERRUPT
+ 					 | DOIO_TIMEOUT
+					 | DOIO_VALID_LPM
+					 | DOIO_DONT_CALL_INTHDLR);
+
+		if (irq_ret == 0) {
+			if (pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+				/*
+				 * If the device doesn't support the
+				 *  Sense Path Group ID command
+				 *  further retries wouldn't help ...
+				 */
+				if (pdevstat->ii.sense.data[0] & 
+				    (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)) {
+					retry = 0;
+					irq_ret = -EOPNOTSUPP;
+				} else {
+#ifdef CONFIG_DEBUG_IO
+					printk (KERN_WARNING
+						"SNID - device %04X,"
+						" unit check,"
+						" flag %04X, "
+						" retry %d, cnt %02d,"
+						" sns :"
+						" %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+						ioinfo[irq]->schib.pmcw.
+						dev, pdevstat->flag,
+						retry, pdevstat->scnt,
+						pdevstat->ii.sense.
+						data[0],
+						pdevstat->ii.sense.
+						data[1],
+						pdevstat->ii.sense.
+						data[2],
+						pdevstat->ii.sense.
+						data[3],
+						pdevstat->ii.sense.
+						data[4],
+						pdevstat->ii.sense.
+						data[5],
+						pdevstat->ii.sense.
+						data[6],
+						pdevstat->ii.sense.data[7]);
+
+#endif
+					CIO_MSG_EVENT(2,
+						     "SNID - device %04X,"
+						     " unit check,"
+						     " flag %04X, "
+						     " retry %d, cnt %02d,"
+						     " sns :"
+						     " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+						     ioinfo[irq]->schib.
+						     pmcw.dev,
+						     pdevstat->flag,
+						     retry,
+						     pdevstat->scnt,
+						     pdevstat->ii.sense.
+						     data[0],
+						     pdevstat->ii.sense.
+						     data[1],
+						     pdevstat->ii.sense.
+						     data[2],
+						     pdevstat->ii.sense.
+						     data[3],
+						     pdevstat->ii.sense.
+						     data[4],
+						     pdevstat->ii.sense.
+						     data[5],
+						     pdevstat->ii.sense.
+						     data[6],
+						     pdevstat->ii.sense.
+						     data[7]);
+					retry--;
+					irq_ret = -EIO;
+
+				}
+			} else if (pdevstat->flag & DEVSTAT_NOT_OPER) {
+				/* don't issue warnings during startup unless requested */
+				if (init_IRQ_complete || cio_notoper_msg) {
+					printk (KERN_WARNING
+						"SNID - Device %04X "
+						"on Subchannel %04X, "
+						"lpm %02X, "
+						"became 'not operational'\n",
+						ioinfo[irq]->schib.pmcw.
+						dev, irq,
+						lpm);
+					CIO_MSG_EVENT(2,
+						     "SNID - Device %04X "
+						     "on Subchannel %04X, "
+						     "lpm %02X, "
+						     "became 'not operational'\n",
+						     ioinfo[irq]->schib.
+						     pmcw.dev, irq,
+						     lpm);
+				}
+
+				retry = 0;
+				irq_ret = -EIO;
+
+			} else {
+				retry = 0;	/* success ... */
+				irq_ret = 0;
+ 				/*
+ 				 * Check if device is locked by someone else
+ 				 * -- we'll fail other commands if that is
+ 				 * the case
+ 				 */
+ 				if (pgid->inf.ps.state2 ==
+ 				    SNID_STATE2_RESVD_ELSE) {
+ 					printk (KERN_WARNING 
+ 						"SNID - Device %04X "
+ 						"on Subchannel %04X "
+ 						"is reserved by "
+ 						"someone else\n",
+ 						ioinfo[irq]->schib.pmcw.dev,
+ 						irq);
+ 					CIO_MSG_EVENT(2,
+ 						      "SNID - Device %04X "
+ 						      "on Subchannel %04X "
+ 						      "is reserved by "
+ 						      "someone else\n",
+ 						      ioinfo[irq]->schib.
+ 						      pmcw.dev,
+ 						      irq);
+ 				
+ 					ioinfo[irq]->ui.flags.unfriendly = 1;
+ 				} else {
+ 					/*
+ 					 * device is friendly to us :)
+ 					 */
+ 					ioinfo[irq]->ui.flags.unfriendly = 0;
+ 				}
+				memcpy(pgid, tmp_pgid, sizeof(pgid_t));
+			}
+
+ 		} else if (irq_ret == -ETIMEDOUT) {
+#ifdef CONFIG_DEBUG_IO
+ 			printk(KERN_INFO "SNID - Operation timed out "
+ 			       "on Device %04X, Subchannel %04X... "
+ 			       "cancelling IO\n",
+ 			       ioinfo[irq]->schib.pmcw.dev,
+ 			       irq);
+#endif /* CONFIG_DEBUG_IO */
+ 			CIO_MSG_EVENT(2,
+ 				      "SNID - Operation timed out "
+ 				      "on Device %04X, Subchannel %04X... "
+ 				      "cancelling IO\n",
+ 				      ioinfo[irq]->schib.pmcw.dev,
+ 				      irq);
+ 			cancel_IO(irq);
+ 			retry--;
+
+		} else if (irq_ret != -ENODEV) {	/* -EIO, or -EBUSY */
+
+			if (pdevstat->flag & DEVSTAT_STATUS_PENDING) {
+#ifdef CONFIG_DEBUG_IO
+				printk (KERN_INFO "SNID - Device %04X "
+					"on Subchannel %04X "
+					"reports pending status, "
+					"retry : %d\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					irq, retry);
+#endif
+				CIO_MSG_EVENT(2,
+					     "SNID - Device %04X "
+					     "on Subchannel %04X "
+					     "reports pending status, "
+					     "retry : %d\n",
+					     ioinfo[irq]->schib.pmcw.
+					     dev, irq, retry);
+			}
+
+			printk (KERN_WARNING "SNID - device %04X,"
+				" start_io() reports rc : %d, retrying ...\n",
+				ioinfo[irq]->schib.pmcw.dev, irq_ret);
+			CIO_MSG_EVENT(2,
+				      "SNID - device %04X,"
+				      " start_io() reports rc : %d,"
+				      " retrying ...\n",
+				      ioinfo[irq]->schib.pmcw.dev, irq_ret);
+			retry--;
+			irq_ret = -EIO;
+		} else {	/* -ENODEV ... */
+
+			retry = 0;
+			irq_ret = -ENODEV;
+
+		}
+
+	} while (retry > 0);
+
+	if (init_IRQ_complete) {
+		kfree (snid_ccw);
+		kfree (tmp_pgid);
+	} else {
+		free_bootmem ((unsigned long) snid_ccw, sizeof (ccw1_t));
+		free_bootmem ((unsigned long) tmp_pgid, sizeof (pgid_t));
+
+	}
+
+	s390irq_spin_unlock_irqrestore (irq, flags);
+
+	/*
+	 * If we installed the irq action handler we have to
+	 *  release it too.
+	 */
+	if (inlreq)
+		free_irq (irq, pdevstat);
+
+	return (irq_ret);
+}
+
+void
+s390_process_subchannel_source (int irq)
+{
+	int dev_oper = 0;
+	int dev_no = -1;
+	int lock = 0;
+	int is_owned = 0;
+
+	/*
+	 * If the device isn't known yet
+	 *   we can't lock it ...
+	 */
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+		s390irq_spin_lock (irq);
+		lock = 1;
+
+		if (!ioinfo[irq]->st) {
+			dev_oper = ioinfo[irq]->ui.flags.oper;
+			
+			if (ioinfo[irq]->ui.flags.dval)
+				dev_no = ioinfo[irq]->devno;
+			
+			is_owned = ioinfo[irq]->ui.flags.ready;
+		}
+
+	}
+#ifdef CONFIG_DEBUG_CRW
+	printk (KERN_DEBUG
+		"do_crw_pending : subchannel validation - start ...\n");
+#endif
+	CIO_CRW_EVENT(4, "subchannel validation - start\n");
+	s390_validate_subchannel (irq, is_owned);
+
+	if (irq > highest_subchannel)
+		highest_subchannel = irq;
+
+#ifdef CONFIG_DEBUG_CRW
+	printk (KERN_DEBUG "do_crw_pending : subchannel validation - done\n");
+#endif
+	CIO_CRW_EVENT(4, "subchannel validation - done\n");
+	/*
+	 * After the validate processing
+	 *   the ioinfo control block
+	 *   should be allocated ...
+	 */
+	if (lock) {
+		s390irq_spin_unlock (irq);
+	}
+
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+#ifdef CONFIG_DEBUG_CRW
+		printk (KERN_DEBUG "do_crw_pending : ioinfo at "
+#ifdef CONFIG_ARCH_S390X
+			"%08lX\n", (unsigned long) ioinfo[irq]
+#else				/* CONFIG_ARCH_S390X */
+			"%08X\n", (unsigned) ioinfo[irq]
+#endif				/* CONFIG_ARCH_S390X */
+			);
+#endif
+#ifdef CONFIG_ARCH_S390X
+		CIO_CRW_EVENT(4, "ioinfo at %08lX\n", 
+			      (unsigned long)ioinfo[irq]);
+#else				/* CONFIG_ARCH_S390X */
+		CIO_CRW_EVENT(4, "ioinfo at %08X\n", 
+			      (unsigned)ioinfo[irq]);
+#endif				/* CONFIG_ARCH_S390X */
+
+		if (ioinfo[irq]->st)
+			return;
+
+		if (ioinfo[irq]->ui.flags.oper == 0) {
+			not_oper_handler_func_t nopfunc = ioinfo[irq]->nopfunc;
+#ifdef CONFIG_PROC_FS
+			/* remove procfs entry */
+			if (cio_proc_devinfo)
+				cio_procfs_device_remove (dev_no);
+#endif
+			/*
+			 * If the device has gone
+			 *  call not oper handler               
+			 */
+			if ((dev_oper == 1)
+			    && (nopfunc != NULL)) {
+
+				free_irq (irq, ioinfo[irq]->irq_desc.dev_id);
+				nopfunc (irq, DEVSTAT_DEVICE_GONE);
+
+			}
+		} else {
+#ifdef CONFIG_DEBUG_CRW
+			printk (KERN_DEBUG
+				"do_crw_pending : device "
+				"recognition - start ...\n");
+#endif
+			CIO_CRW_EVENT( 4,
+				       "device recognition - start\n");
+			s390_device_recognition_irq (irq);
+
+#ifdef CONFIG_DEBUG_CRW
+			printk (KERN_DEBUG
+				"do_crw_pending : device "
+				"recognition - done\n");
+#endif
+			CIO_CRW_EVENT( 4,
+				       "device recognition - done\n");
+			/*
+			 * the device became operational
+			 */
+			if (dev_oper == 0) {
+				devreg_t *pdevreg;
+
+				pdevreg = s390_search_devreg (ioinfo[irq]);
+
+				if (pdevreg != NULL) {
+					if (pdevreg->oper_func != NULL)
+						pdevreg->
+						    oper_func (irq, pdevreg);
+
+				}
+#ifdef CONFIG_PROC_FS
+				/* add new procfs entry */
+				if (cio_proc_devinfo)
+					if (highest_subchannel <
+					    MAX_CIO_PROCFS_ENTRIES) {
+						cio_procfs_device_create
+						    (ioinfo[irq]->devno);
+					}
+#endif
+			}
+			/*
+			 * ... it is and was operational, but
+			 *      the devno may have changed
+			 */
+			else if ((ioinfo[irq]->devno != dev_no)
+				 && (ioinfo[irq]->nopfunc != NULL)) {
+#ifdef CONFIG_PROC_FS
+				int devno_old = ioinfo[irq]->devno;
+#endif
+				ioinfo[irq]->nopfunc (irq, DEVSTAT_REVALIDATE);
+#ifdef CONFIG_PROC_FS
+				/* remove old entry, add new */
+				if (cio_proc_devinfo) {
+					cio_procfs_device_remove (devno_old);
+					cio_procfs_device_create
+					    (ioinfo[irq]->devno);
+				}
+#endif
+			}
+		}
+#ifdef CONFIG_PROC_FS
+		/* get rid of dead procfs entries */
+		if (cio_proc_devinfo)
+			cio_procfs_device_purge ();
+#endif
+	}
+}
+
+#ifdef CONFIG_CHSC
+static int 
+chsc_get_sch_desc_irq(int irq)
+{
+	int j = 0;
+	int ccode;
+
+	spin_lock(&chsc_lock_ssd);
+		
+	if (!chsc_area_ssd)
+		chsc_area_ssd = kmalloc(sizeof(chsc_area_t),GFP_KERNEL);
+	
+	if (!chsc_area_ssd) {
+		printk( KERN_CRIT "No memory to determine sch descriptions...\n");
+		spin_unlock(&chsc_lock_ssd);
+		return -ENOMEM;
+	}
+	
+	memset(chsc_area_ssd, 0, sizeof(chsc_area_t));
+	
+	chsc_area_ssd->request_block.command_code1=0x0010;
+	chsc_area_ssd->request_block.command_code2=0x0004;
+	chsc_area_ssd->request_block.request_block_data.ssd_req.f_sch=irq;
+	chsc_area_ssd->request_block.request_block_data.ssd_req.l_sch=irq;
+	
+	ccode = chsc(chsc_area_ssd);
+#ifdef CONFIG_DEBUG_CHSC
+	if (ccode)
+		printk( KERN_DEBUG "chsc returned with ccode = %d\n",ccode);
+#endif /* CONFIG_DEBUG_CHSC */
+	if (!ccode) {
+		if (chsc_area_ssd->response_block.response_code == 0x0003) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING "Error in chsc request block!\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2, "Error in chsc request block!\n");
+			spin_unlock(&chsc_lock_ssd);
+			return -EINVAL;
+			
+		} else if (chsc_area_ssd->response_block.response_code == 0x0004) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING "Model does not provide ssd\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2, "Model does not provide ssd\n");
+			spin_unlock(&chsc_lock_ssd);
+			return -EOPNOTSUPP;
+
+		} else if (chsc_area_ssd->response_block.response_code == 0x0002) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING "chsc: Invalid command!\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2,
+				       "chsc: Invalid command!\n");
+			return -EINVAL;
+
+		} else if (chsc_area_ssd->response_block.response_code == 0x0001) {
+			/* everything ok */
+					
+			switch (chsc_area_ssd->response_block.response_block_data.ssd_res.st) {
+				
+			case 0:  /* I/O subchannel */
+				
+				/* 
+				 * All fields have meaning
+				 */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg) 
+					printk( KERN_DEBUG 
+						"ssd: sch %x is I/O subchannel\n",
+						irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 6,
+					       "ssd: sch %x is I/O subchannel\n",
+					       irq);
+
+				if (ioinfo[irq] == INVALID_STORAGE_AREA)
+					/* FIXME: we should do device rec. here... */
+					break;
+
+				ioinfo[irq]->ssd_info.valid = 1;
+				ioinfo[irq]->ssd_info.type = 0;
+				for (j=0;j<8;j++) {
+					if ((0x80 >> j) & 
+					    chsc_area_ssd->response_block.
+					    response_block_data.ssd_res.path_mask & 
+					    chsc_area_ssd->response_block.
+					    response_block_data.ssd_res.fla_valid_mask) {
+
+						if (chsc_area_ssd->response_block.
+						    response_block_data.ssd_res.chpid[j]) 
+
+							if (!test_and_set_bit
+							    (chsc_area_ssd->response_block.
+							     response_block_data.
+							     ssd_res.chpid[j],
+							     &chpids_known)) 
+
+								if (test_bit
+								    (chsc_area_ssd->response_block.
+								     response_block_data.
+								     ssd_res.chpid[j],
+								     &chpids_logical))
+
+									set_bit(chsc_area_ssd->response_block.
+										response_block_data.
+										ssd_res.chpid[j],
+										&chpids);
+
+						ioinfo[irq]->ssd_info.chpid[j] = 
+							chsc_area_ssd->response_block.
+							response_block_data.ssd_res.chpid[j];
+						ioinfo[irq]->ssd_info.fla[j] = 
+							chsc_area_ssd->response_block.
+							response_block_data.ssd_res.fla[j];
+					}
+				}
+				break;
+				
+			case 1:  /* CHSC subchannel */
+				
+				/*
+				 * Only sch_val, st and sch have meaning
+				 */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg)
+					printk( KERN_DEBUG 
+						"ssd: sch %x is chsc subchannel\n",
+						irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 6,
+					       "ssd: sch %x is chsc subchannel\n",
+					       irq);
+
+				if (ioinfo[irq] == INVALID_STORAGE_AREA)
+					/* FIXME: we should do device rec. here... */
+					break;
+
+				ioinfo[irq]->ssd_info.valid = 1;
+				ioinfo[irq]->ssd_info.type = 1;
+				break;
+				
+			case 2: /* Message subchannel */
+				
+				/*
+				 * All fields except unit_addr have meaning
+				 */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg)
+					printk( KERN_DEBUG 
+						"ssd: sch %x is message subchannel\n",
+						irq);
+#endif
+				CIO_CRW_EVENT( 6,
+					       "ssd: sch %x is message subchannel\n",
+					       irq);
+
+				if (ioinfo[irq] == INVALID_STORAGE_AREA)
+					/* FIXME: we should do device rec. here... */
+					break;
+
+				ioinfo[irq]->ssd_info.valid = 1;
+				ioinfo[irq]->ssd_info.type = 2;
+				for (j=0;j<8;j++) {
+					if ((0x80 >> j) & 
+					    chsc_area_ssd->response_block.
+					    response_block_data.ssd_res.path_mask & 
+					    chsc_area_ssd->response_block.
+					    response_block_data.ssd_res.fla_valid_mask) {
+						if (chsc_area_ssd->response_block.
+						    response_block_data.ssd_res.chpid[j])
+
+							if (!test_and_set_bit
+							    (chsc_area_ssd->response_block.
+							     response_block_data.
+							     ssd_res.chpid[j],
+							     &chpids_known)) 
+
+								if (test_bit
+								    (chsc_area_ssd->response_block.
+								     response_block_data.
+								     ssd_res.chpid[j],
+								     &chpids_logical))
+
+									set_bit(chsc_area_ssd->response_block.
+										response_block_data.
+										ssd_res.chpid[j],
+										&chpids);
+
+						ioinfo[irq]->ssd_info.chpid[j] = 
+							chsc_area_ssd->response_block.
+							response_block_data.ssd_res.chpid[j];
+						ioinfo[irq]->ssd_info.fla[j] = 
+							chsc_area_ssd->response_block.
+							response_block_data.ssd_res.fla[j];
+					}
+				}
+				break;
+				
+			case 3: /* ADM subchannel */
+				
+				/*
+				 * Only sch_val, st and sch have meaning
+				 */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg) 
+					printk( KERN_DEBUG 
+						"ssd: sch %x is ADM subchannel\n",
+						irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 6,
+					       "ssd: sch %x is ADM subchannel\n",
+					       irq);
+
+				if (ioinfo[irq] == INVALID_STORAGE_AREA)
+					/* FIXME: we should do device rec. here... */
+					break;
+
+				ioinfo[irq]->ssd_info.valid = 1;
+				ioinfo[irq]->ssd_info.type = 3;
+				break;
+				
+			default: /* uhm, that looks strange... */
+#ifdef CONFIG_DEBUG_CHSC
+				if (cio_show_msg) 
+					printk( KERN_DEBUG 
+						"Strange subchannel type %d for sch %x\n", 
+						chsc_area_ssd->response_block.
+						response_block_data.ssd_res.st,
+						irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 0, 
+					       "Strange subchannel type %d for "
+					       "sch %x\n", 
+					       chsc_area_ssd->response_block.
+					       response_block_data.ssd_res.st,
+					       irq);
+			}
+			spin_unlock(&chsc_lock_ssd);
+			return 0;
+		}
+	} else {
+		spin_unlock(&chsc_lock_ssd);
+		if (ccode == 3)
+			return -ENODEV;
+		return -EBUSY;
+	}
+	return -EIO;
+}
 
-	if ( irq_ret == 0 )
-	{
-		s390irq_spin_lock_irqsave( irq, flags);
 
-		if ( init_IRQ_complete )
-		{
-			snid_ccw = kmalloc( sizeof( ccw1_t), GFP_DMA);
+static int 
+chsc_get_sch_descriptions( void )
+{
+
+	int irq = 0;
+	int err = 0;
+
+	CIO_TRACE_EVENT( 4, "gsdesc");
+
+	/*
+	 * get information about chpids and link addresses 
+	 * by executing the chsc command 'store subchannel description'
+	 */
+
+	if (init_IRQ_complete) {
+		
+		for (irq=0; irq<=highest_subchannel; irq++) {
+
+			/*
+			 * retrieve information for each sch
+			 */
+			err = chsc_get_sch_desc_irq(irq);
+			if (err) {
+				if (!cio_chsc_err_msg) {
+					printk( KERN_ERR
+						"chsc_get_sch_descriptions:"
+						" Error %d while doing chsc; "
+						"processing "
+						"some machine checks may "
+						"not work\n", 
+						err);
+					cio_chsc_err_msg=1;
+				}
+				return err;
+			}
 		}
-		else	
-		{
-			snid_ccw = alloc_bootmem_low( sizeof( ccw1_t));
+		cio_chsc_desc_avail = 1;
+		return 0;
+	} else {
+		/* Paranoia... */
+		
+		printk( KERN_ERR 
+			"Error: chsc_get_sch_descriptions called before "
+		       "initialization complete\n");
+		return -EINVAL;
+	}
+	
+}
+
+__initcall(chsc_get_sch_descriptions);
+
+void 
+s390_do_chpid_processing( __u8 chpid)
+{
+
+	int irq;
+	int j;
+	int mask;
+	char dbf_txt[15];
+	int ccode;
+	int was_oper;
+	int chp = 0;
+	int mask2;
+	int ret = 0;
 
-		} /* endif */
+	sprintf(dbf_txt, "chpr%x", chpid);
+	CIO_TRACE_EVENT( 2, dbf_txt);
 
-		snid_ccw->cmd_code = CCW_CMD_SENSE_PGID;
-		snid_ccw->cda      = (__u32)virt_to_phys( pgid );
-		snid_ccw->count    = sizeof( pgid_t);
-		snid_ccw->flags    = CCW_FLAG_SLI;
+	/* 
+	 * TODO: the chpid may be not the chpid with the link incident,
+	 * but the chpid the report came in through. How to handle???
+	 */
+	clear_bit(chpid, &chpids);
+	if (!test_and_clear_bit(chpid, &chpids_known))
+		return;  /* we didn't know the chpid anyway */
+
+	for (irq=0;irq<=highest_subchannel;irq++) {
+		if (ioinfo[irq] == INVALID_STORAGE_AREA) 
+			continue;  /* we don't know the device anyway */
+		if (ioinfo[irq]->st)
+			continue; /* non-io subchannel */
+		for (j=0; j<8;j++) {
+			if (ioinfo[irq]->schib.pmcw.chpid[j] == chpid) {
+				
+				/*
+				 * Send nops down each path to find out
+				 * which path is gone (ssch will yield cc=3 
+				 * and the path will be switched off in the opm)
+				 */
+				
+				/* 
+				 * Note: irq spinlock is grabbed several times
+				 * in here
+				 */
+				for (chp=0;chp<=7;chp++) {
+					mask2 = 0x80 >> chp;
+					if (mask2 & ioinfo[irq]->opm)
+						ret = s390_send_nop (irq, mask2);
+				}
+				
+				s390irq_spin_lock(irq);
 
+				/*
+				 * FIXME: is this neccessary?
+				 */
+				ccode = stsch(irq, &ioinfo[irq]->schib);
+				if (ccode) {
+#ifdef CONFIG_DEBUG_CRW
+					printk( KERN_WARNING 
+						"do_crw_pending: device on "
+						"sch %x is not operational\n",
+						irq);
+#endif /* CONFIG_DEBUG_CRW */
+					CIO_CRW_EVENT( 2,
+						       "device on sch %x is "
+						       "not operational\n",
+						       irq);
+					ioinfo[irq]->ui.flags.oper = 0;
+					break;
+				}
+
+				ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim &
+					ioinfo[irq]->schib.pmcw.pam &
+					ioinfo[irq]->schib.pmcw.pom;
+
+				if (ioinfo[irq]->opm) {
+					for (chp=0;chp<=7;chp++) {
+						mask2 = 0x80 >> chp;
+						if (ioinfo[irq]->opm & mask2) {
+							if (!test_bit
+							    (ioinfo[irq]->
+							     schib.pmcw.chpid[chp], 
+							     &chpids_logical)) {
+								/* disable using this path */
+								ioinfo[irq]->opm 
+									&= ~mask2;
+							}
+						}
+					}
+				}
+
+				if (!ioinfo[irq]->opm) {
+					/*
+					 * sh*t, our last path has gone...
+					 * Set the device status to not operational
+					 * and eventually notify the device driver
+					 */
+#ifdef CONFIG_DEBUG_CRW
+					printk( KERN_WARNING 
+						"do_crw_pending: Last path gone for "
+						"device %x, sch %x\n",
+						ioinfo[irq]->devno, irq);
+#endif /* CONFIG_DEBUG_CRW */
+					CIO_CRW_EVENT( 2,
+						       "Last path gone for "
+						       "device %x, sch %x\n",
+						       ioinfo[irq]->devno,
+						       irq);
+					
+					was_oper = ioinfo[irq]->ui.flags.oper;
+					
+					ioinfo[irq]->ui.flags.oper = 0;
+					
+					if (was_oper && ioinfo[irq]->ui.flags.ready) {
+						
+						not_oper_handler_func_t nopfunc = 
+							ioinfo[irq]->nopfunc;
+#ifdef CONFIG_PROC_FS						
+						if (cio_proc_devinfo)
+							cio_procfs_device_remove
+								(ioinfo[irq]->devno);
+#endif /* CONFIG_PROC_FS */
+						free_irq(irq, 
+							 ioinfo[irq]->irq_desc.dev_id);
+						if (nopfunc)
+							nopfunc(irq, 
+								DEVSTAT_DEVICE_GONE);
+					}
+					
+				} else if (ioinfo[irq]->ui.flags.ready) {
+					/* 
+					 * Re-do path verification for the chpid in question
+					 * FIXME: is this neccessary?
+					 */
+					mask = 0x80 >> j;
+
+					if (!s390_DevicePathVerification(irq,mask)) {
+#ifdef CONFIG_DEBUG_CRW
+						printk( KERN_DEBUG 
+							"DevicePathVerification "
+							"successful for"
+							" Subchannel %x, "
+							"chpid %x\n",
+							irq, chpid);
+#endif /* CONFIG_DEBUG_CRW */
+						CIO_CRW_EVENT( 2,
+							       "DevicePathVerification "
+							       "successful for"
+							       " Subchannel %x, "
+							       "chpid %x\n",
+							       irq, chpid);
+					}
+				}
+					
+				j=8;
+				s390irq_spin_unlock(irq);
+			}
+			
+		}
+	}	
+}
+
+
+void 
+s390_do_res_acc_processing( __u8 chpid, __u16 fla, int info)
+{
+
+	char dbf_txt[15];
+	int irq = 0;
+	int ccode;
+	__u32 fla_mask = 0xffff;
+	int chp;
+	int mask, mask2;
+	int ret;
+
+	sprintf(dbf_txt, "accp%x", chpid);
+	CIO_TRACE_EVENT( 2, dbf_txt);
+	if (info != CHSC_SEI_ACC_CHPID) {
+		sprintf(dbf_txt, "fla%x", fla);
+		CIO_TRACE_EVENT( 2, dbf_txt);
+	}
+	sprintf(dbf_txt, "info:%d", info);
+	CIO_TRACE_EVENT( 2, dbf_txt);
+	
+	/*
+	 * I/O resources may have become accessible.
+	 * Scan through all subchannels that may be concerned and
+	 * do a validation on those.
+	 * The more information we have (info), the less scanning
+	 * will we have to do.
+	 */
+
+	if (!cio_chsc_desc_avail) 
+		chsc_get_sch_descriptions();
+
+	if (!cio_chsc_desc_avail) {
 		/*
-		 * We now issue a SensePGID request. In case of BUSY
-		 *  or STATUS PENDING conditions we retry 5 times.
+		 * Something went wrong...
 		 */
-		do
-		{
-			memset( pdevstat, '\0', sizeof( devstat_t) );
+#ifdef CONFIG_DEBUG_CRW
+		printk( KERN_WARNING 
+			"Error: Could not retrieve subchannel descriptions, "
+		       "will not process css machine check...\n");
+#endif /* CONFIG_DEBUG_CRW */
+		CIO_CRW_EVENT( 0,
+			       "Error: Could not retrieve subchannel descriptions, "
+			       "will not process css machine check...\n");
+		return;
+	} 
+
+	if (!test_bit(chpid, &chpids_logical))
+		return; /* no need to do the rest */
+
+	switch (info) {
+	case CHSC_SEI_ACC_CHPID: /*
+				  * worst case, we only know about the chpid
+				  * the devices are attached to
+				  */
+#ifdef CONFIG_DEBUG_CHSC
+		printk( KERN_DEBUG "Looking at chpid %x...\n", chpid);
+#endif /* CONFIG_DEBUG_CHSC */
+		
+		for (irq=0; irq<=__MAX_SUBCHANNELS; irq++) {
+			
+			if((ioinfo[irq] != INVALID_STORAGE_AREA) 
+			   && (!ioinfo[irq]->st)) {
+				
+				/*
+				 * Send nops down each path to find out
+				 * which path is there 
+				 */
+				
+				for (chp=0;chp<=7;chp++) {
+					mask = 0x80 >> chp;
 
-			irq_ret = s390_start_IO( irq,
-			                         snid_ccw,
-			                         0xE2D5C9C4,  // == SNID
-			                         lpm,         // n/a
-			                         DOIO_WAIT_FOR_INTERRUPT
-			                          | DOIO_VALID_LPM
-			                          | DOIO_DONT_CALL_INTHDLR );
+					/*
+					 * check if chpid is in information
+					 * updated by ssd
+					 */
+					if ((ioinfo[irq]->ssd_info.valid) &&
+					    (ioinfo[irq]->ssd_info.chpid[chp]
+					     == chpid))
+						ret = s390_send_nop (irq, mask);
+				}
+
+				ccode = stsch(irq, &ioinfo[irq]->schib);
+				if (!ccode) {
+
+					ioinfo[irq]->opm = 
+						ioinfo[irq]->schib.pmcw.pim &
+						ioinfo[irq]->schib.pmcw.pam &
+						ioinfo[irq]->schib.pmcw.pom;
+
+					if (ioinfo[irq]->opm) {
+						for (chp=0;chp<=7;chp++) {
+							mask = 0x80 >> chp;
+							if (ioinfo[irq]->opm 
+							    & mask) {
+								if (!test_bit
+								    (ioinfo[irq]->
+								     schib.pmcw.chpid[chp], 
+								     &chpids_logical)) {
+									/* disable using this path */
+									ioinfo[irq]->opm 
+										&= ~mask;
+								}
+							}
+						}
+					}
+
+					if ((ioinfo[irq]->ui.flags.ready) 
+					    && (chpid & ioinfo[irq]->opm))
+						s390_DevicePathVerification(irq, chpid);
+
+				} else {
+					ioinfo[irq]->ui.flags.oper = 0;
+				}
+			} else if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+				/*
+				 * We don't know the device yet, but since a path
+				 * may be available now to the device we'll have
+				 * to do recognition again.
+				 * Since we don't have any idea about which chpid
+				 * that beast may be on we'll have to do a stsch
+				 * on all devices, grr...
+				 */
+				int valret = 0;
+				
+				valret = s390_validate_subchannel(irq,0);
+				if (valret == -ENXIO) {
+					/* We're through */
+					return;
+				}
+				if (irq > highest_subchannel)
+					highest_subchannel = irq;
+				if (valret == 0)
+					s390_device_recognition_irq(irq);
+			}
+		}
 
-			if ( irq_ret == 0 )
-			{
-				if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
-				{
-					/*
-					 * If the device doesn't support the
-					 *  Sense Path Group ID command
-					 *  further retries wouldn't help ...
+		break;
+		
+	case CHSC_SEI_ACC_LINKADDR: /*
+				     * better, we know the link determined by
+				     * the link address and the chpid
+				     */
+		fla_mask = 0xff00;
+		/* fallthrough */
+
+	case CHSC_SEI_ACC_FULLLINKADDR: /*
+					 * best case, we know the CU image
+					 * by chpid and full link address
 					 */
-					if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
-					{
-						retry   = 0;
-						irq_ret = -EOPNOTSUPP;
-					}
-					else
-					{
-#ifdef CONFIG_DEBUG_IO
-						printk( KERN_WARNING "SNID - device %04X,"
-						        " unit check,"
-						        " flag %04X, "
-						        " retry %d, cnt %02d,"
-						        " sns :"
-						        " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-						        ioinfo[irq]->schib.pmcw.dev,
-						        pdevstat->flag,
-						        retry,
-						        pdevstat->scnt,
-						        pdevstat->ii.sense.data[0],
-						        pdevstat->ii.sense.data[1],
-						        pdevstat->ii.sense.data[2],
-						        pdevstat->ii.sense.data[3],
-						        pdevstat->ii.sense.data[4],
-						        pdevstat->ii.sense.data[5],
-						        pdevstat->ii.sense.data[6],
-						        pdevstat->ii.sense.data[7]);
-
-#endif
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "SNID - device %04X,"
-									    " unit check,"
-									    " flag %04X, "
-									    " retry %d, cnt %02d,"
-									    " sns :"
-									    " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
-									    ioinfo[irq]->schib.pmcw.dev,
-									    pdevstat->flag,
-									    retry,
-									    pdevstat->scnt,
-									    pdevstat->ii.sense.data[0],
-									    pdevstat->ii.sense.data[1],
-									    pdevstat->ii.sense.data[2],
-									    pdevstat->ii.sense.data[3],
-									    pdevstat->ii.sense.data[4],
-									    pdevstat->ii.sense.data[5],
-									    pdevstat->ii.sense.data[6],
-									    pdevstat->ii.sense.data[7]);		    
-						retry--;
-						irq_ret = -EIO;
 
-					} /* endif */
-				}
-				else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
-				{
-					/* don't issue warnings during startup unless requested*/
-					if (init_IRQ_complete || cio_notoper_msg) {  
-						printk( KERN_WARNING "SNID - Device %04X "
-							"on Subchannel %04X "
-							"became 'not operational'\n",
-							ioinfo[irq]->schib.pmcw.dev,
-							irq);
-						if (cio_debug_initialized)
-							debug_sprintf_event(cio_debug_msg_id, 2,
-									    "SNID - Device %04X "
-									    "on Subchannel %04X "
-									    "became 'not operational'\n",
-									    ioinfo[irq]->schib.pmcw.dev,
-									    irq);		    
-					}
+#ifdef CONFIG_DEBUG_CHSC
+		printk( KERN_DEBUG "Looking at chpid %x, link addr %x...\n", 
+			chpid, fla);
+#endif /* CONFIG_DEBUG_CHSC */
+		
+		for (irq=0; irq<=__MAX_SUBCHANNELS; irq++) {
+			
+			/*
+			 * Walk through all subchannels and
+			 * look if our chpid and our (masked) link 
+			 * address are in somewhere
+			 * Do a stsch for the found subchannels and
+			 * perform path grouping  
+			 */
+			if ((ioinfo[irq] != INVALID_STORAGE_AREA) 
+			    && (!ioinfo[irq]->st)) {
+				int j;
+				
+				/* Update our ssd_info */
+				if (chsc_get_sch_desc_irq(irq)) 
+					break;
+				
+				for (j=0;j<8;j++) {
+					if ((ioinfo[irq]->ssd_info.chpid[j] == chpid) &&
+					    ((ioinfo[irq]->ssd_info.fla[j]&fla_mask) == fla)) {
 
-					retry = 0;
-					irq_ret = -EIO;
+						mask2 = 0x80 >> j;
+						ret = s390_send_nop (irq, mask2);
+						
+						ccode = stsch(irq,&ioinfo[irq]->schib);
+						if (!ccode) {
+							ioinfo[irq]->opm = 
+								ioinfo[irq]->schib.pmcw.pim &
+								ioinfo[irq]->schib.pmcw.pam &
+								ioinfo[irq]->schib.pmcw.pom;
+
+							if (ioinfo[irq]->opm) {
+								for (chp=0;chp<=7;chp++) {
+									mask = 0x80 >> chp;
+									if (ioinfo[irq]->opm 
+									    & mask) {
+										if (!test_bit
+										    (ioinfo[irq]->
+										     schib.pmcw.chpid[chp], 
+										     &chpids_logical)) {
+											/* disable using this path */
+											ioinfo[irq]->opm 
+												&= ~mask;
+										}
+									}
+								}
+							}
 
+							if (ioinfo[irq]->ui.flags.ready)
+								s390_DevicePathVerification(irq, chpid);
+						}
+						break;
+					}
 				}
-				else
-				{
-					retry = 0; // success ...
-					irq_ret = 0;
-
-				} /* endif */
+			} else if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+				/* The full program again (see above), grr... */
+				int valret = 0;
+				
+				valret = s390_validate_subchannel(irq,0);
+				if (valret == -ENXIO) {
+					/* We're done */
+					return;
+				}
+				if (irq > highest_subchannel)
+					highest_subchannel = irq;
+				if (valret == 0)
+					s390_device_recognition_irq(irq);
+				
 			}
-			else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
-			{
+		}
+		
+		break;
 
-				if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-				{
-#ifdef CONFIG_DEBUG_IO
-					printk( KERN_INFO "SNID - Device %04X "
-					        "on Subchannel %04X "
-					        "reports pending status, "
-					        "retry : %d\n",
-					        ioinfo[irq]->schib.pmcw.dev,
-					        irq,
-					        retry);
-#endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_msg_id, 2,
-								    "SNID - Device %04X "
-								    "on Subchannel %04X "
-								    "reports pending status, "
-								    "retry : %d\n",
-								    ioinfo[irq]->schib.pmcw.dev,
-								    irq,
-								    retry);		    
-				} /* endif */
-
-
-				printk( KERN_WARNING "SNID - device %04X,"
-				        " start_io() reports rc : %d, retrying ...\n",
-				        ioinfo[irq]->schib.pmcw.dev,
-				        irq_ret);
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_msg_id, 2, 
-							    "SNID - device %04X,"
-							    " start_io() reports rc : %d, retrying ...\n",
-							    ioinfo[irq]->schib.pmcw.dev,
-							    irq_ret);
-				retry--;
-				irq_ret = -EIO;
-			}
-			else	// -ENODEV ...
-			{
-				retry = 0;
-				irq_ret = -ENODEV;
+	default: BUG();
+	}
+}
 
-			} /* endif */
+void 
+s390_process_css( void ) 
+{
 
-		} while ( retry > 0 );
+	int ccode;
 
+	CIO_TRACE_EVENT( 2, "prcss");
 
-		if ( init_IRQ_complete )
-		{
-			kfree( snid_ccw );
-		}
-		else	
-		{
-			free_bootmem( (unsigned long)snid_ccw, sizeof(ccw1_t) );
+	spin_lock(&chsc_lock_sei);
+
+	if (!chsc_area_sei) {
+		if (init_IRQ_complete) 
+			chsc_area_sei = kmalloc(sizeof(chsc_area_t),GFP_KERNEL);
+		else
+			chsc_area_sei = alloc_bootmem(sizeof(chsc_area_t));
+	}
+	
+	if (!chsc_area_sei) {
+		printk( KERN_CRIT 
+			"No memory to store event information...\n");
+		spin_unlock(&chsc_lock_sei);
+		return;
+	}
+
+	/* 
+	 * build the chsc request block for store event information 
+	 * and do the call 
+	 */
+	memset(chsc_area_sei,0,sizeof(chsc_area_t));
+	chsc_area_sei->request_block.command_code1=0x0010;
+	chsc_area_sei->request_block.command_code2=0x000E;
+
+	ccode = chsc(chsc_area_sei);
+
+
+	if (!ccode) {
+		/* for debug purposes, check for problems */
+		if (chsc_area_sei->response_block.response_code == 0x0003) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING 
+				"s390_process_css: error in chsc request block!\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2, 
+				       "s390_process_css: "
+				       "error in chsc request block!\n");
+
+		} else if (chsc_area_sei->response_block.response_code == 0x0005) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING 
+				"s390_process_css: no event information stored\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2, 
+				       "s390_process_css: "
+				       "no event information stored\n");
+
+		} else if (chsc_area_sei->response_block.response_code == 0x0002) {
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_WARNING
+				"s390_process_css: invalid command!\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 2,
+				       "s390_process_css: "
+				       "invalid command!\n");
+
+		} else if (chsc_area_sei->response_block.response_code == 0x0001) {
+			/* everything ok */
+#ifdef CONFIG_DEBUG_CHSC
+			printk( KERN_DEBUG 
+				"s390_process_css: "
+				"event information successfully stored\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			CIO_CRW_EVENT( 4, 
+				       "s390_process_css: "
+				       "event information successfully stored\n");
+
+			if (chsc_area_sei->response_block.
+			    response_block_data.sei_res.rs != 4) {
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_ERR
+					"s390_process_css: "
+					"reporting source (%04X) isn't a chpid!"
+					"Aborting processing of machine check...\n",
+					chsc_area_sei->response_block.
+					response_block_data.sei_res.rsid);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 2,
+					       "s390_process_css: "
+					       "reporting source (%04X) isn't a chpid!"
+					       "Aborting processing of machine check...\n",
+					       chsc_area_sei->response_block.
+					       response_block_data.sei_res.rsid);
+				return;
+			}
+			
+			/* which kind of information was stored? */
+			switch (chsc_area_sei->response_block.
+				response_block_data.sei_res.cc) {
+			case 1: /* link incident*/
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG 
+					"s390_process_css: "
+					"channel subsystem reports link incident,"
+					" source is chpid %x\n", 
+					chsc_area_sei->response_block.
+					response_block_data.sei_res.rsid);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 4,
+					       "s390_process_css: "
+					       "channel subsystem reports "
+					       "link incident, "
+					       "source is chpid %x\n", 
+					       chsc_area_sei->response_block.
+					       response_block_data.sei_res.rsid);
+
+				s390_do_chpid_processing(chsc_area_sei->response_block.
+							 response_block_data.sei_res.rsid);
+							    
+				break;
 
-		} /* endif */
+			case 2: /* i/o resource accessibiliy */
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG 
+					"s390_process_css: channel subsystem "
+					"reports some I/O devices "
+					"may have become accessable\n");
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 4,
+					       "s390_process_css: "
+					       "channel subsystem reports "
+					       "some I/O devices "
+					       "may have become accessable\n");
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG 
+					"Data received after sei: \n");
+				printk( KERN_DEBUG 
+					"Validity flags: %x\n", 
+				       chsc_area_sei->response_block.
+					response_block_data.sei_res.vf);
+#endif /* CONFIG_DEBUG_CHSC */
+				if ((chsc_area_sei->response_block.
+				    response_block_data.sei_res.vf&0x80)
+				    == 0) {
+#ifdef CONFIG_DEBUG_CHSC
+					printk( KERN_DEBUG "chpid: %x\n",
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.rsid);
+#endif /* CONFIG_DEBUG_CHSC */
+					s390_do_res_acc_processing
+						(chsc_area_sei->response_block.
+						 response_block_data.sei_res.rsid,
+						 0,
+						 CHSC_SEI_ACC_CHPID);
+				} else if ((chsc_area_sei->response_block.
+					   response_block_data.sei_res.vf&0xc0)
+					   == 0x80) {
+#ifdef CONFIG_DEBUG_CHSC
+					printk( KERN_DEBUG 
+						"chpid: %x  link addr: %x\n",
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.rsid,
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.fla);
+#endif /* CONFIG_DEBUG_CHSC */
+					s390_do_res_acc_processing
+						(chsc_area_sei->response_block.
+						 response_block_data.sei_res.rsid, 
+						 chsc_area_sei->response_block.
+						 response_block_data.sei_res.fla,
+						 CHSC_SEI_ACC_LINKADDR);
+				} else if ((chsc_area_sei->response_block.
+					    response_block_data.sei_res.vf & 0xc0)
+					   == 0xc0) {
+#ifdef CONFIG_DEBUG_CHSC
+					printk( KERN_DEBUG 
+						"chpid: %x  "
+						"full link addr: %x\n",
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.rsid,
+						chsc_area_sei->response_block.
+						response_block_data.sei_res.fla);
+#endif /* CONFIG_DEBUG_CHSC */
+					s390_do_res_acc_processing
+						(chsc_area_sei->response_block.
+						 response_block_data.sei_res.rsid, 
+						 chsc_area_sei->response_block.
+						 response_block_data.sei_res.fla,
+						 CHSC_SEI_ACC_FULLLINKADDR);
+				}
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG "\n");
+#endif /* CONFIG_DEBUG_CHSC */
 
-		s390irq_spin_unlock_irqrestore( irq, flags);
+				break;
 
-		/*
-		 * If we installed the irq action handler we have to
-		 *  release it too.
-		 */
-		if ( inlreq )
-			free_irq( irq, pdevstat);
+			default: /* other stuff */
+#ifdef CONFIG_DEBUG_CHSC
+				printk( KERN_DEBUG 
+					"s390_process_css: event %d\n",
+					chsc_area_sei->response_block.
+					response_block_data.sei_res.cc);
+#endif /* CONFIG_DEBUG_CHSC */
+				CIO_CRW_EVENT( 4, 
+					       "s390_process_css: event %d\n",
+					       chsc_area_sei->response_block.
+					       response_block_data.sei_res.cc);
 
-	} /* endif */
+				break;
 
-   return( irq_ret );
+			}
+		}
+	}
+	spin_unlock(&chsc_lock_sei);
 }
+#endif
 
 /*
  * s390_do_crw_pending
@@ -6328,298 +7613,116 @@
  *
  * Note : we currently process CRWs for subchannel source only
  */
-void s390_do_crw_pending( crwe_t *pcrwe )
+void
+s390_do_crw_pending (crwe_t * pcrwe)
 {
 	int irq;
 	int chpid;
-	int dev_oper = 0;
-	int dev_no   = -1;	
-	int lock     = 0;
-
+	
 #ifdef CONFIG_DEBUG_CRW
-	printk( KERN_DEBUG "do_crw_pending : starting ...\n");
+	printk (KERN_DEBUG "do_crw_pending : starting ...\n");
 #endif
-	if (cio_debug_initialized) 
-		debug_sprintf_event(cio_debug_crw_id, 2, 
-				    "do_crw_pending: starting\n");
-	while ( pcrwe != NULL )
-	{
-		int is_owned = 0;
-
-		switch ( pcrwe->crw.rsc ) {	
-		case CRW_RSC_SCH :
+	CIO_CRW_EVENT( 2, "do_crw_pending: starting\n");
+	while (pcrwe != NULL) {
 
+		switch (pcrwe->crw.rsc) {
+		case CRW_RSC_SCH:
+			
 			irq = pcrwe->crw.rsid;
-
-#ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE"do_crw_pending : source is "
-			        "subchannel %04X\n", irq);
-#endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is subchannel %04X\n", irq);
-			/*
-			 * If the device isn't known yet
-			 *   we can't lock it ...
-			 */
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-			{
-				s390irq_spin_lock( irq );
-				lock = 1;
-
-				dev_oper = ioinfo[irq]->ui.flags.oper;
-
-				if ( ioinfo[irq]->ui.flags.dval )
-					dev_no = ioinfo[irq]->devno;
-
-				is_owned = ioinfo[irq]->ui.flags.ready;
-
-			} /* endif */
-
-#ifdef CONFIG_DEBUG_CRW
-			printk( KERN_DEBUG "do_crw_pending : subchannel validation - start ...\n");
-#endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 4,
-						    "subchannel validation - start\n");
-			s390_validate_subchannel( irq, is_owned );
-
-			if ( irq > highest_subchannel )
-				highest_subchannel = irq;
-
-#ifdef CONFIG_DEBUG_CRW
-			printk( KERN_DEBUG "do_crw_pending : subchannel validation - done\n");
-#endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 4,
-						    "subchannel validation - done\n");
-			/*
-			 * After the validate processing
-			 *   the ioinfo control block
-			 *   should be allocated ...
-			 */
-			if ( lock )
-			{
-				s390irq_spin_unlock( irq );
-
-			} /* endif */
-
-
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-			{
-#ifdef CONFIG_DEBUG_CRW
-				printk( KERN_DEBUG "do_crw_pending : ioinfo at "
-#ifdef CONFIG_ARCH_S390X
-					"%08lX\n",
-					(unsigned long)ioinfo[irq]);
-#else /* CONFIG_ARCH_S390X */
-					"%08X\n",
-				        (unsigned)ioinfo[irq]);
-#endif /* CONFIG_ARCH_S390X */
-#endif
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_crw_id, 4,
-							    "ioinfo at "
-#ifdef CONFIG_ARCH_S390X
-							    "%08lX\n",
-							    (unsigned long)ioinfo[irq]);
-#else /* CONFIG_ARCH_S390X */
-				                            "%08X\n",
-							    (unsigned)ioinfo[irq]);
-#endif /* CONFIG_ARCH_S390X */
-			} /* endif */
-
-
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-			{
-				if ( ioinfo[irq]->ui.flags.oper == 0 )
-				{
-					 not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
-#ifdef CONFIG_PROC_FS					 
-					 /* remove procfs entry */
-					 if (cio_proc_devinfo)
-						 cio_procfs_device_remove(dev_no);
-#endif
-					/*
-					 * If the device has gone
-					 *  call not oper handler        	
-					 */       	
-					 if (( dev_oper == 1 )
-					     && ( nopfunc != NULL))
-					{
-						
-						free_irq( irq,ioinfo[irq]->irq_desc.dev_id );
-						nopfunc( irq,DEVSTAT_DEVICE_GONE );			
-
-					} /* endif */
-				}
-				else
-				{
-#ifdef CONFIG_DEBUG_CRW
-					printk( KERN_DEBUG "do_crw_pending : device "
-					        "recognition - start ...\n");
-#endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_crw_id, 4,
-								    "device recognition - start\n");
-					s390_device_recognition_irq( irq );
-
+			
 #ifdef CONFIG_DEBUG_CRW
-					printk( KERN_DEBUG "do_crw_pending : device "
-					        "recognition - done\n");
-#endif
-					if (cio_debug_initialized)
-						debug_sprintf_event(cio_debug_crw_id, 4,
-								    "device recognition - done\n");
-					/*
-					 * the device became operational
-					 */
-					if ( dev_oper == 0 )
-					{
-						devreg_t *pdevreg;
-
-						pdevreg = s390_search_devreg( ioinfo[irq] );
-
-						if ( pdevreg != NULL )
-						{
-							if ( pdevreg->oper_func != NULL )
-								pdevreg->oper_func( irq, pdevreg );
-
-						} /* endif */
-#ifdef CONFIG_PROC_FS
-						/* add new procfs entry */
-						if (cio_proc_devinfo) 
-							if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
-								cio_procfs_device_create(ioinfo[irq]->devno);
-							}
-#endif
-					}
-					/*
-					 * ... it is and was operational, but
-					 *      the devno may have changed
-					 */
-					else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL ))   					
-					{
-#ifdef CONFIG_PROC_FS
-						int devno_old = ioinfo[irq]->devno;
-#endif
-						ioinfo[irq]->nopfunc( irq,
-						                      DEVSTAT_REVALIDATE );				
-#ifdef CONFIG_PROC_FS
-						/* remove old entry, add new */
-						if (cio_proc_devinfo) {
-							cio_procfs_device_remove(devno_old);
-							cio_procfs_device_create(ioinfo[irq]->devno);
-						}
-#endif
-					} /* endif */
-
-				} /* endif */
-#ifdef CONFIG_PROC_FS
-				/* get rid of dead procfs entries */
-				if (cio_proc_devinfo) 
-					cio_procfs_device_purge();
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"subchannel %04X\n", irq);
 #endif
-			} /* endif */
+			CIO_CRW_EVENT(2, "source is subchannel %04X\n",
+				      irq);
+			s390_process_subchannel_source (irq);
 
 			break;
 
-		case CRW_RSC_MONITOR :
+		case CRW_RSC_MONITOR:
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : source is "
-			        "monitoring facility\n");
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"monitoring facility\n");
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is monitoring facility\n");
+			CIO_CRW_EVENT(2, "source is monitoring facility\n");
 			break;
 
-		case CRW_RSC_CPATH :   	
+		case CRW_RSC_CPATH:
 
 			chpid = pcrwe->crw.rsid;
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : source is "
-			        "channel path %02X\n", chpid);
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"channel path %02X\n", chpid);
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is channel path %02X\n");
+			CIO_CRW_EVENT(2, "source is channel path %02X\n");
 			break;
 
-		case CRW_RSC_CONFIG : 	
+		case CRW_RSC_CONFIG:
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : source is "
-			        "configuration-alert facility\n");
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"configuration-alert facility\n");
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is configuration-alert facility\n");
+			CIO_CRW_EVENT(2, "source is configuration-alert facility\n");
 			break;
 
-		case CRW_RSC_CSS :
+		case CRW_RSC_CSS:
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : source is "
-			        "channel subsystem\n");
+			printk (KERN_NOTICE "do_crw_pending : source is "
+				"channel subsystem\n");
+#endif
+			CIO_CRW_EVENT(2, "source is channel subsystem\n");
+#ifdef CONFIG_CHSC
+			s390_process_css();
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "source is channel subsystem\n");
 			break;
 
-		default :
+		default:
 
 #ifdef CONFIG_DEBUG_CRW
-			printk( KERN_NOTICE "do_crw_pending : unknown source\n");
+			printk (KERN_NOTICE
+				"do_crw_pending : unknown source\n");
 #endif
-			if (cio_debug_initialized)
-				debug_sprintf_event(cio_debug_crw_id, 2,
-						    "unknown source\n");
-			break;		
+			CIO_CRW_EVENT( 2, "unknown source\n");
+			break;
 
-		} /* endswitch */
+		}
 
 		pcrwe = pcrwe->crwe_next;
 
-	} /* endwhile */
+	}
 
 #ifdef CONFIG_DEBUG_CRW
-	printk( KERN_DEBUG "do_crw_pending : done\n");
+	printk (KERN_DEBUG "do_crw_pending : done\n");
 #endif
-	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_crw_id, 2,
-				    "do_crw_pending: done\n");
-   return;
+	CIO_CRW_EVENT(2, "do_crw_pending: done\n");
+	return;
 }
 
-
 /* added by Holger Smolinski for reipl support in reipl.S */
 extern void do_reipl (int);
 void
-reipl ( int sch )
+reipl (int sch)
 {
 	int i;
 	s390_dev_info_t dev_info;
 
-	for ( i = 0; i <= highest_subchannel; i ++ ) 
-	{
-		if (    get_dev_info_by_irq( i, &dev_info ) == 0
-                    && (dev_info.status & DEVSTAT_DEVICE_OWNED) )
-		{
-			free_irq ( i, ioinfo[i]->irq_desc.dev_id );
+	for (i = 0; i <= highest_subchannel; i++) {
+		if (get_dev_info_by_irq (i, &dev_info) == 0
+		    && (dev_info.status & DEVSTAT_DEVICE_OWNED)) {
+			free_irq (i, ioinfo[i]->irq_desc.dev_id);
 		}
 	}
-
 	if (MACHINE_IS_VM)
-		cpcmd("IPL", NULL, 0);
+		cpcmd ("IPL", NULL, 0);
 	else
-		do_reipl( 0x10000 | sch );
+		do_reipl (0x10000 | sch);
 }
 
-
 /*
  * Function: cio_debug_init
  * Initializes three debug logs (under /proc/s390dbf) for common I/O:
@@ -6628,40 +7731,29 @@
  * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
  * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
  */
-int cio_debug_init( void )
+int
+cio_debug_init (void)
 {
 	int ret = 0;
 
-	cio_debug_msg_id = debug_register("cio_msg",4,4,16*sizeof(long));
+	cio_debug_msg_id = debug_register ("cio_msg", 4, 4, 16 * sizeof (long));
 	if (cio_debug_msg_id != NULL) {
-		debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
-#ifdef CONFIG_DEBUG_IO
-		debug_set_level(cio_debug_msg_id, 6);
-#else /* CONFIG_DEBUG_IO */
-		debug_set_level(cio_debug_msg_id, 2);
-#endif /* CONFIG_DEBUG_IO */
+		debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
+		debug_set_level (cio_debug_msg_id, 6);
 	} else {
 		ret = -1;
 	}
-	cio_debug_trace_id = debug_register("cio_trace",4,4,8);
+	cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8);
 	if (cio_debug_trace_id != NULL) {
-		debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
-#ifdef CONFIG_DEBUG_IO
-		debug_set_level(cio_debug_trace_id, 6);
-#else /* CONFIG_DEBUG_IO */
-		debug_set_level(cio_debug_trace_id, 2);
-#endif /* CONFIG_DEBUG_IO */
+		debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
+		debug_set_level (cio_debug_trace_id, 6);
 	} else {
 		ret = -1;
 	}
-	cio_debug_crw_id = debug_register("cio_crw",2,4,16*sizeof(long));
+	cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16 * sizeof (long));
 	if (cio_debug_crw_id != NULL) {
-		debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
-#ifdef CONFIG_DEBUG_CRW
-		debug_set_level(cio_debug_crw_id, 6);
-#else /* CONFIG_DEBUG_CRW */
-		debug_set_level(cio_debug_crw_id, 2);
-#endif /* CONFIG_DEBUG_CRW */
+		debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
+		debug_set_level (cio_debug_crw_id, 6);
 	} else {
 		ret = -1;
 	}
@@ -6671,157 +7763,325 @@
 	return 0;
 }
 
-__initcall(cio_debug_init);
+__initcall (cio_debug_init);
 
 #ifdef CONFIG_PROC_FS
+#ifdef CONFIG_CHSC
+/*
+ * Function: cio_parse_chpids_proc_parameters
+ * parse the stuff piped to /proc/chpids
+ */
+void 
+cio_parse_chpids_proc_parameters(char* buf)
+{
+	int i;
+	int cp;
+	int ret;
+
+	if (strstr(buf, "on ")) {
+		for (i=0; i<3; i++) {
+			buf++;
+		}
+		cp = blacklist_strtoul(buf, &buf);
+
+		chsc_get_sch_descriptions();
+		if (!cio_chsc_desc_avail) {
+			printk(KERN_ERR "Could not get chpid status, "
+			       "vary on/off not available\n");
+			return;
+		}
+ 
+		if (!test_bit(cp, &chpids)) {
+			ret = s390_vary_chpid(cp, 1);
+			if (ret == -EINVAL) {
+#ifdef CONFIG_DEBUG_CHSC
+				printk(KERN_ERR "/proc/chpids: "
+				       "Invalid chpid specified\n");
+#else /* CONFIG_DEBUG_CHSC */
+				printk(KERN_DEBUG "/proc/chpids: "
+				       "Invalid chpid specified\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			} else if (ret == 0) {
+				printk(KERN_INFO "/proc/chpids: "
+				       "Varied chpid %x logically online\n",
+				       cp);
+			}
+		} else {
+			printk(KERN_ERR "/proc/chpids: chpid %x is "
+			       "already online\n",
+			       cp);
+		}
+	} else if (strstr(buf, "off ")) {
+		for (i=0; i<4; i++) {
+			buf++;
+		}
+		cp = blacklist_strtoul(buf, &buf);
+
+		chsc_get_sch_descriptions();
+		if (!cio_chsc_desc_avail) {
+			printk(KERN_ERR "Could not get chpid status, "
+			       "vary on/off not available\n");
+			return;
+		}
+		
+		if (test_bit(cp, &chpids)) {
+			ret = s390_vary_chpid(cp, 0);
+			if (ret == -EINVAL) {
+#ifdef CONFIG_DEBUG_CHSC
+				printk(KERN_ERR "/proc/chpids: "
+				       "Invalid chpid specified\n");
+#else /* CONFIG_DEBUG_CHSC */
+				printk(KERN_DEBUG "/proc/chpids: "
+				       "Invalid chpid specified\n");
+#endif /* CONFIG_DEBUG_CHSC */
+			} else if (ret == 0) {
+				printk(KERN_INFO "/proc/chpids: "
+				       "Varied chpid %x logically offline\n",
+				       cp);
+			}
+		} else { 
+			printk(KERN_ERR "/proc/chpids: "
+			       "chpid %x is already offline\n",
+			       cp);
+		}
+	} else {
+		printk(KERN_ERR "/proc/chpids: Parse error; "
+		       "try using '{on,off} <chpid>'\n");
+	}
+}
+
+
+/*
+ * Function: s390_vary_chpid
+ * Varies the specified chpid online or offline
+ */
+int 
+s390_vary_chpid( __u8 chpid, int on) 
+{
+	char dbf_text[15];
+	int irq;
+
+	if ((chpid <=0) || (chpid >= NR_CHPIDS))
+		return -EINVAL;
+
+	sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid);
+	CIO_TRACE_EVENT( 2, dbf_text);
+
+	if (!test_bit(chpid, &chpids_known)) {
+		printk(KERN_ERR "Can't vary unknown chpid %02X\n", chpid);
+		return -EINVAL;
+	}
+
+	if (on && test_bit(chpid, &chpids_logical)) {
+		printk(KERN_ERR "chpid %02X already logically online\n", 
+		       chpid);
+		return -EINVAL;
+	}
+
+	if (!on && !test_bit(chpid, &chpids_logical)) {
+		printk(KERN_ERR "chpid %02X already logically offline\n", 
+		       chpid);
+		return -EINVAL;
+	}
+
+	if (on) {
+		set_bit(chpid, &chpids_logical);
+		set_bit(chpid, &chpids);
+
+	} else {
+		clear_bit(chpid, &chpids_logical);
+		clear_bit(chpid, &chpids);
+	}
+
+	/*
+	 * Redo PathVerification on the devices the chpid connects to 
+	 */
+	
+	for (irq=0;irq<=highest_subchannel;irq++) {
+
+		/* 
+		 * We don't need to adjust the opm, as this will be done in
+		 * DevicePathVerification...
+		 */
+
+		if (ioinfo[irq] == INVALID_STORAGE_AREA)
+			continue;
+
+		if (ioinfo[irq]->st)
+			continue;
+
+		if (ioinfo[irq]->ssd_info.valid) {
+			if ((ioinfo[irq]->ssd_info.chpid[0] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[1] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[2] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[3] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[4] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[5] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[6] == chpid) ||
+			    (ioinfo[irq]->ssd_info.chpid[7] == chpid)) {
+#ifdef CONFIG_DEBUG_CHSC
+				printk(KERN_DEBUG "Calling "
+				       "DevicePathVerification for irq %d\n", 
+				       irq);
+#endif /* CONFIG_DEBUG_CHSC */
+				s390_DevicePathVerification(irq, 0);
+			}
+		}
+	}
+
+	return 0;
+}
+#endif /* CONFIG_CHSC */
+
 /* 
  * Display info on subchannels in /proc/subchannels. 
  * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      
  */
 
 typedef struct {
-     char *data;
-     int len;
+	char *data;
+	int len;
 } tempinfo_t;
 
 #define MIN(a,b) ((a)<(b)?(a):(b))
 
 static struct proc_dir_entry *chan_subch_entry;
 
-static int chan_subch_open( struct inode *inode, struct file *file)
+static int
+chan_subch_open (struct inode *inode, struct file *file)
 {
-     int rc = 0;
-     int size = 1;
-     int len = 0;
-     int i = 0;
-     int j = 0;
-     tempinfo_t *info;
-     
-     info = (tempinfo_t *) vmalloc( sizeof (tempinfo_t));
-     if (info == NULL) {
-	  printk( KERN_WARNING "No memory available for data\n");
-	  return -ENOMEM;
-     } else {
-	  file->private_data = ( void * ) info;
-     }
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	int i = 0;
+	int j = 0;
+	tempinfo_t *info;
 
-     size += (highest_subchannel+1) * 128;
-     info->data = (char *) vmalloc( size );
-     
-     if (size && info->data == NULL) {
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
+	if (info == NULL) {
 		printk (KERN_WARNING "No memory available for data\n");
-		vfree (info);
 		return -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
 	}
-     
-     len += sprintf( info->data+len, 
-		     "Device sch.  Dev Type/Model CU  in use  PIM PAM POM LPUM CHPIDs\n");
-     len += sprintf( info->data+len, 
-		     "--------------------------------------------------------------------------\n");
-
-     for ( i=0; i <= highest_subchannel; i++) {
-	  if ( !((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA) || !(ioinfo[i]->ui.flags.oper)) ) {
-	       len += sprintf( info->data+len, 
-			       "%04X   %04X  ", 
-			       ioinfo[i]->schib.pmcw.dev, 
-			       i );
-	       if ( ioinfo[i]->senseid.dev_type != 0 ) {
-		    len += sprintf( info->data+len, 
-				    "%04X/%02X   %04X/%02X", 
-				    ioinfo[i]->senseid.dev_type,
-				    ioinfo[i]->senseid.dev_model, 
-				    ioinfo[i]->senseid.cu_type,
-				    ioinfo[i]->senseid.cu_model );
-	       } else {
-		    len += sprintf( info->data+len, 
-				    "          %04X/%02X", 
-				    ioinfo[i]->senseid.cu_type, 
-				    ioinfo[i]->senseid.cu_model );
-	       }
-	       if (ioinfo[i]->ui.flags.ready) {
-		    len += sprintf( info->data+len, "  yes " );
-	       } else {
-		    len += sprintf( info->data+len, "      " );
-	       }
-	       len += sprintf( info->data+len,
-			       "    %02X  %02X  %02X  %02X   ",
-			       ioinfo[i]->schib.pmcw.pim,
-			       ioinfo[i]->schib.pmcw.pam,
-			       ioinfo[i]->schib.pmcw.pom,
-			       ioinfo[i]->schib.pmcw.lpum );
-	       for ( j=0; j < 8; j++ ) {
-		    len += sprintf( info->data+len,
-				    "%02X",
-				    ioinfo[i]->schib.pmcw.chpid[j] );
-		    if (j==3) {
-			 len += sprintf( info->data+len, " " );
-		    }
-	       }
-	       len += sprintf( info->data+len, "\n" );
-	  }
-     }
-     info->len = len;
 
-     return rc;
-}
+	size += (highest_subchannel + 1) * 128;
+	info->data = (char *) vmalloc (size);
 
-static int chan_subch_close( struct inode *inode, struct file *file)
-{
-     int rc = 0;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+	if (size && info->data == NULL) {
+		printk (KERN_WARNING "No memory available for data\n");
+		vfree (info);
+		return -ENOMEM;
+	}
 
-     if (p_info) {
-	  if (p_info->data)
-	       vfree( p_info->data );
-	  vfree( p_info );
-     }
-     
-     return rc;
-}
+	len += sprintf (info->data + len,
+			"Device sch.  Dev Type/Model CU  in use  PIM PAM POM CHPIDs\n");
+	len += sprintf (info->data + len,
+			"---------------------------------------------------------------------\n");
+
+	for (i = 0; i <= highest_subchannel; i++) {
+		if (!((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA)
+		      || (ioinfo[i]->st )|| !(ioinfo[i]->ui.flags.oper))) {
+			len +=
+			    sprintf (info->data + len, "%04X   %04X  ",
+				     ioinfo[i]->schib.pmcw.dev, i);
+			if (ioinfo[i]->senseid.dev_type != 0) {
+				len += sprintf (info->data + len,
+						"%04X/%02X   %04X/%02X",
+						ioinfo[i]->senseid.dev_type,
+						ioinfo[i]->senseid.dev_model,
+						ioinfo[i]->senseid.cu_type,
+						ioinfo[i]->senseid.cu_model);
+			} else {
+				len += sprintf (info->data + len,
+						"          %04X/%02X",
+						ioinfo[i]->senseid.cu_type,
+						ioinfo[i]->senseid.cu_model);
+			}
+			if (ioinfo[i]->ui.flags.ready) {
+				len += sprintf (info->data + len, "  yes ");
+			} else {
+				len += sprintf (info->data + len, "      ");
+			}
+			len += sprintf (info->data + len,
+					"    %02X  %02X  %02X  ",
+					ioinfo[i]->schib.pmcw.pim,
+					ioinfo[i]->schib.pmcw.pam,
+					ioinfo[i]->schib.pmcw.pom);
+			for (j = 0; j < 8; j++) {
+				len += sprintf (info->data + len,
+						"%02X",
+						ioinfo[i]->schib.pmcw.chpid[j]);
+				if (j == 3) {
+					len += sprintf (info->data + len, " ");
+				}
+			}
+			len += sprintf (info->data + len, "\n");
+		}
+	}
+	info->len = len;
 
-static ssize_t chan_subch_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
-{
-     loff_t len;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-     
-     if ( *offset>=p_info->len) {
-	  return 0;
-     } else {
-	  len = MIN(user_len, (p_info->len - *offset));
-	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
-	       return -EFAULT; 
-	  (* offset) += len;
-	  return len;
-     }
+	return rc;
+}
+
+static int
+chan_subch_close (struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+	if (p_info) {
+		if (p_info->data)
+			vfree (p_info->data);
+		vfree (p_info);
+	}
+
+	return rc;
 }
 
-static struct file_operations chan_subch_file_ops =
+static ssize_t
+chan_subch_read (struct file *file, char *user_buf, size_t user_len,
+		 loff_t * offset)
 {
-     read:chan_subch_read,
-     open:chan_subch_open,
-     release:chan_subch_close,
+	loff_t len;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+	if (*offset >= p_info->len) {
+		return 0;
+	} else {
+		len = MIN (user_len, (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
+		return len;
+	}
+}
+
+static struct file_operations chan_subch_file_ops = {
+	read:chan_subch_read, open:chan_subch_open, release:chan_subch_close,
 };
 
-static int chan_proc_init( void )
+static int
+chan_proc_init (void)
 {
-     chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root);
-     chan_subch_entry->proc_fops = &chan_subch_file_ops;
+	chan_subch_entry =
+	    create_proc_entry ("subchannels", S_IFREG | S_IRUGO, &proc_root);
+	chan_subch_entry->proc_fops = &chan_subch_file_ops;
 
-     return 1;
+	return 1;
 }
 
-__initcall(chan_proc_init);
+__initcall (chan_proc_init);
 
-void chan_proc_cleanup( void )
+void
+chan_proc_cleanup (void)
 {
-     remove_proc_entry( "subchannels", &proc_root);
+	remove_proc_entry ("subchannels", &proc_root);
 }
 
 /* 
  * Display device specific information under /proc/deviceinfo/<devno>
- */
-
-static struct proc_dir_entry *cio_procfs_deviceinfo_root = NULL;
+ */ static struct proc_dir_entry *cio_procfs_deviceinfo_root = NULL;
 
 /* 
  * cio_procfs_device_list holds all devno-specific procfs directories
@@ -6835,7 +8095,7 @@
 	struct proc_dir_entry *cio_chpid_entry;
 } cio_procfs_entry_t;
 
-typedef struct _cio_procfs_device{
+typedef struct _cio_procfs_device {
 	struct _cio_procfs_device *next;
 	cio_procfs_entry_t *entry;
 } cio_procfs_device_t;
@@ -6846,38 +8106,41 @@
  * File operations
  */
 
-static int cio_device_entry_close( struct inode *inode, struct file *file)
+static int
+cio_device_entry_close (struct inode *inode, struct file *file)
 {
-     int rc = 0;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+	int rc = 0;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
 
-     if (p_info) {
-	  if (p_info->data)
-	       vfree( p_info->data );
-	  vfree( p_info );
-     }
-     
-     return rc;
+	if (p_info) {
+		if (p_info->data)
+			vfree (p_info->data);
+		vfree (p_info);
+	}
+
+	return rc;
 }
 
-static ssize_t cio_device_entry_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+static ssize_t
+cio_device_entry_read (struct file *file, char *user_buf, size_t user_len,
+		       loff_t * offset)
 {
-     loff_t len;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-     
-     if ( *offset>=p_info->len) {
-	  return 0;
-     } else {
-	  len = MIN(user_len, (p_info->len - *offset));
-	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
-	       return -EFAULT; 
-	  (* offset) += len;
-	  return len;
-     }
-}
+	loff_t len;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
 
+	if (*offset >= p_info->len) {
+		return 0;
+	} else {
+		len = MIN (user_len, (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
+		return len;
+	}
+}
 
-static int cio_sensedata_entry_open( struct inode *inode, struct file *file)
+static int
+cio_sensedata_entry_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -6885,49 +8148,67 @@
 	tempinfo_t *info;
 	int irq;
 	int devno;
-	char * devno_str;
+	char *devno_str;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 		size += 2 * 32;
-		info->data = (char *) vmalloc(size);
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk(KERN_WARNING "No memory available for data\n");
-			vfree(info);
+			printk (KERN_WARNING "No memory available for data\n");
+			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
-			memset(devno_str, 0, 6*sizeof(char));
-			memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
-			devno = simple_strtoul(devno_str, &devno_str, 16);
-			irq = get_irq_by_devno(devno);
+			devno_str = kmalloc (6 * sizeof (char), GFP_KERNEL);
+			memset (devno_str, 0, 6 * sizeof (char));
+			memcpy (devno_str,
+				file->f_dentry->d_parent->d_name.name,
+				strlen (file->f_dentry->d_parent->d_name.name) +
+				1);
+			devno = simple_strtoul (devno_str, &devno_str, 16);
+			irq = get_irq_by_devno (devno);
 			if (irq != -1) {
-				len += sprintf(info->data+len, "Dev Type/Mod: ");
+				len +=
+				    sprintf (info->data + len,
+					     "Dev Type/Mod: ");
 				if (ioinfo[irq]->senseid.dev_type == 0) {
-					len += sprintf(info->data+len, "%04X/%02X\n",
-						       ioinfo[irq]->senseid.cu_type,
-						       ioinfo[irq]->senseid.cu_model);
+					len +=
+					    sprintf (info->data + len,
+						     "%04X/%02X\n",
+						     ioinfo[irq]->senseid.
+						     cu_type,
+						     ioinfo[irq]->senseid.
+						     cu_model);
 				} else {
-					len += sprintf(info->data+len, "%04X/%02X\n",
-						       ioinfo[irq]->senseid.dev_type,
-						       ioinfo[irq]->senseid.dev_model);
-					len+= sprintf(info->data+len, "CU Type/Mod:  %04X/%02X\n",
-						      ioinfo[irq]->senseid.cu_type,
-						      ioinfo[irq]->senseid.cu_model);
+					len +=
+					    sprintf (info->data + len,
+						     "%04X/%02X\n",
+						     ioinfo[irq]->senseid.
+						     dev_type,
+						     ioinfo[irq]->senseid.
+						     dev_model);
+					len +=
+					    sprintf (info->data + len,
+						     "CU Type/Mod:  %04X/%02X\n",
+						     ioinfo[irq]->senseid.
+						     cu_type,
+						     ioinfo[irq]->senseid.
+						     cu_model);
 				}
 			}
 			info->len = len;
 		}
 	}
-	
+
 	return rc;
 }
 
-static int cio_in_use_entry_open( struct inode *inode, struct file *file)
+static int
+cio_in_use_entry_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -6935,37 +8216,44 @@
 	tempinfo_t *info;
 	int irq;
 	int devno;
-	char * devno_str;
+	char *devno_str;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 		size += 8;
-		info->data = (char *) vmalloc(size);
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk(KERN_WARNING "No memory available for data\n");
-			vfree(info);
+			printk (KERN_WARNING "No memory available for data\n");
+			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
-			memset(devno_str, 0, 6*sizeof(char));
-			memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
-			devno = simple_strtoul(devno_str, &devno_str, 16);
-			irq = get_irq_by_devno(devno);
+			devno_str = kmalloc (6 * sizeof (char), GFP_KERNEL);
+			memset (devno_str, 0, 6 * sizeof (char));
+			memcpy (devno_str,
+				file->f_dentry->d_parent->d_name.name,
+				strlen (file->f_dentry->d_parent->d_name.name) +
+				1);
+			devno = simple_strtoul (devno_str, &devno_str, 16);
+			irq = get_irq_by_devno (devno);
 			if (irq != -1) {
-				len += sprintf(info->data+len, "%s\n", ioinfo[irq]->ui.flags.ready?"yes":"no");
+				len +=
+				    sprintf (info->data + len, "%s\n",
+					     ioinfo[irq]->ui.flags.
+					     ready ? "yes" : "no");
 			}
 			info->len = len;
 		}
 	}
-	
+
 	return rc;
 }
 
-static int cio_chpid_entry_open( struct inode *inode, struct file *file)
+static int
+cio_chpid_entry_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -6974,30 +8262,38 @@
 	int irq;
 	int devno;
 	int i;
-	char * devno_str;
+	char *devno_str;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
-		size += 8*16;
-		info->data = (char *) vmalloc(size);
+		size += 8 * 16;
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk(KERN_WARNING "No memory available for data\n");
-			vfree(info);
+			printk (KERN_WARNING "No memory available for data\n");
+			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
-			memset(devno_str, 0, 6*sizeof(char));
-			memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
-			devno = simple_strtoul(devno_str, &devno_str, 16);
-			irq = get_irq_by_devno(devno);
+			devno_str = kmalloc (6 * sizeof (char), GFP_KERNEL);
+			memset (devno_str, 0, 6 * sizeof (char));
+			memcpy (devno_str,
+				file->f_dentry->d_parent->d_name.name,
+				strlen (file->f_dentry->d_parent->d_name.name) +
+				1);
+			devno = simple_strtoul (devno_str, &devno_str, 16);
+			irq = get_irq_by_devno (devno);
 			if (irq != -1) {
-				for (i=0; i<8; i++) {
-					len += sprintf(info->data+len, "CHPID[%d]: ", i);
-					len += sprintf(info->data+len, "%02X\n", ioinfo[irq]->schib.pmcw.chpid[i]);
+				for (i = 0; i < 8; i++) {
+					len +=
+					    sprintf (info->data + len,
+						     "CHPID[%d]: ", i);
+					len +=
+					    sprintf (info->data + len, "%02X\n",
+						     ioinfo[irq]->schib.pmcw.
+						     chpid[i]);
 				}
 			}
 			info->len = len;
@@ -7007,25 +8303,19 @@
 	return rc;
 }
 
-static struct file_operations cio_sensedata_entry_file_ops =
-{
-     read:cio_device_entry_read,
-     open:cio_sensedata_entry_open,
-     release:cio_device_entry_close,
+static struct file_operations cio_sensedata_entry_file_ops = {
+	read:cio_device_entry_read, open:cio_sensedata_entry_open,
+	release:cio_device_entry_close,
 };
 
-static struct file_operations cio_in_use_entry_file_ops =
-{
-     read:cio_device_entry_read,
-     open:cio_in_use_entry_open,
-     release:cio_device_entry_close,
+static struct file_operations cio_in_use_entry_file_ops = {
+	read:cio_device_entry_read, open:cio_in_use_entry_open,
+	release:cio_device_entry_close,
 };
 
-static struct file_operations cio_chpid_entry_file_ops =
-{
-     read:cio_device_entry_read,
-     open:cio_chpid_entry_open,
-     release:cio_device_entry_close,
+static struct file_operations cio_chpid_entry_file_ops = {
+	read:cio_device_entry_read, open:cio_chpid_entry_open,
+	release:cio_device_entry_close,
 };
 
 /*
@@ -7033,7 +8323,8 @@
  * create procfs entry for given device number
  * and insert it into list
  */
-int cio_procfs_device_create(int devno)
+int
+cio_procfs_device_create (int devno)
 {
 	cio_procfs_entry_t *entry;
 	cio_procfs_device_t *tmp;
@@ -7042,26 +8333,30 @@
 	int i;
 	int rc = 0;
 
-
 	/* create the directory entry */
-	entry = (cio_procfs_entry_t *)kmalloc(sizeof(cio_procfs_entry_t), GFP_KERNEL);
+	entry =
+	    (cio_procfs_entry_t *) kmalloc (sizeof (cio_procfs_entry_t),
+					    GFP_KERNEL);
 	if (entry) {
 		entry->devno = devno;
-		sprintf(buf, "%x", devno);
-		entry->cio_device_entry = proc_mkdir(buf, cio_procfs_deviceinfo_root);
-		
+		sprintf (buf, "%x", devno);
+		entry->cio_device_entry =
+		    proc_mkdir (buf, cio_procfs_deviceinfo_root);
+
 		if (entry->cio_device_entry) {
-			tmp = (cio_procfs_device_t *)kmalloc(sizeof(cio_procfs_device_t), GFP_KERNEL);
+			tmp = (cio_procfs_device_t *)
+			    kmalloc (sizeof (cio_procfs_device_t), GFP_KERNEL);
 			if (tmp) {
 				tmp->entry = entry;
-				
+
 				if (cio_procfs_device_list == NULL) {
 					cio_procfs_device_list = tmp;
 					tmp->next = NULL;
 				} else {
 					where = cio_procfs_device_list;
 					i = where->entry->devno;
-					while ((devno>i) && (where->next != NULL)) {
+					while ((devno > i)
+					       && (where->next != NULL)) {
 						where = where->next;
 						i = where->entry->devno;
 					}
@@ -7074,26 +8369,42 @@
 					}
 				}
 				/* create the different entries */
-				entry->cio_sensedata_entry = create_proc_entry( "sensedata", S_IFREG|S_IRUGO, entry->cio_device_entry);
-				entry->cio_sensedata_entry->proc_fops = &cio_sensedata_entry_file_ops;
-				entry->cio_in_use_entry = create_proc_entry( "in_use", S_IFREG|S_IRUGO, entry->cio_device_entry);
-				entry->cio_in_use_entry->proc_fops = &cio_in_use_entry_file_ops;
-				entry->cio_chpid_entry = create_proc_entry( "chpids", S_IFREG|S_IRUGO, entry->cio_device_entry);
-				entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops;
+				entry->cio_sensedata_entry =
+				    create_proc_entry ("sensedata",
+						       S_IFREG | S_IRUGO,
+						       entry->cio_device_entry);
+				entry->cio_sensedata_entry->proc_fops =
+				    &cio_sensedata_entry_file_ops;
+				entry->cio_in_use_entry =
+				    create_proc_entry ("in_use",
+						       S_IFREG | S_IRUGO,
+						       entry->cio_device_entry);
+				entry->cio_in_use_entry->proc_fops =
+				    &cio_in_use_entry_file_ops;
+				entry->cio_chpid_entry =
+				    create_proc_entry ("chpids",
+						       S_IFREG | S_IRUGO,
+						       entry->cio_device_entry);
+				entry->cio_chpid_entry->proc_fops =
+				    &cio_chpid_entry_file_ops;
 			} else {
-				printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
-				remove_proc_entry(buf, cio_procfs_deviceinfo_root);
-				kfree(entry);
+				printk (KERN_WARNING
+					"Error, could not allocate procfs structure!\n");
+				remove_proc_entry (buf,
+						   cio_procfs_deviceinfo_root);
+				kfree (entry);
 				rc = -ENOMEM;
 			}
 		} else {
-			printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
-			kfree(entry);
+			printk (KERN_WARNING
+				"Error, could not allocate procfs structure!\n");
+			kfree (entry);
 			rc = -ENOMEM;
 		}
 
 	} else {
-		printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
+		printk (KERN_WARNING
+			"Error, could not allocate procfs structure!\n");
 		rc = -ENOMEM;
 	}
 	return rc;
@@ -7103,36 +8414,36 @@
  * Function: cio_procfs_device_remove
  * remove procfs entry for given device number
  */
-int cio_procfs_device_remove(int devno)
+int
+cio_procfs_device_remove (int devno)
 {
 	int rc = 0;
 	cio_procfs_device_t *tmp;
 	cio_procfs_device_t *prev = NULL;
 
-	tmp=cio_procfs_device_list;
+	tmp = cio_procfs_device_list;
 	while (tmp) {
 		if (tmp->entry->devno == devno)
 			break;
 		prev = tmp;
 		tmp = tmp->next;
 	}
-
 	if (tmp) {
 		char buf[8];
-		
-		remove_proc_entry("sensedata", tmp->entry->cio_device_entry);
-		remove_proc_entry("in_use", tmp->entry->cio_device_entry);
-		remove_proc_entry("chpid", tmp->entry->cio_device_entry);
-		sprintf(buf, "%x", devno);
-		remove_proc_entry(buf, cio_procfs_deviceinfo_root);
-		
+
+		remove_proc_entry ("sensedata", tmp->entry->cio_device_entry);
+		remove_proc_entry ("in_use", tmp->entry->cio_device_entry);
+		remove_proc_entry ("chpid", tmp->entry->cio_device_entry);
+		sprintf (buf, "%x", devno);
+		remove_proc_entry (buf, cio_procfs_deviceinfo_root);
+
 		if (tmp == cio_procfs_device_list) {
 			cio_procfs_device_list = tmp->next;
 		} else {
 			prev->next = tmp->next;
 		}
-		kfree(tmp->entry);
-		kfree(tmp);
+		kfree (tmp->entry);
+		kfree (tmp);
 	} else {
 		rc = -ENODEV;
 	}
@@ -7145,17 +8456,17 @@
  * purge /proc/deviceinfo of entries for gone devices
  */
 
-int cio_procfs_device_purge(void) 
+int
+cio_procfs_device_purge (void)
 {
 	int i;
 
-	for (i=0; i<=highest_subchannel; i++) {
+	for (i = 0; i <= highest_subchannel; i++) {
 		if (ioinfo[i] != INVALID_STORAGE_AREA) {
-			if (!ioinfo[i]->ui.flags.oper) 
-				cio_procfs_device_remove(ioinfo[i]->devno);
+			if (!ioinfo[i]->ui.flags.oper)
+				cio_procfs_device_remove (ioinfo[i]->devno);
 		}
 	}
-
 	return 0;
 }
 
@@ -7163,38 +8474,45 @@
  * Function: cio_procfs_create
  * create /proc/deviceinfo/ and subdirs for the devices
  */
-static int cio_procfs_create( void )
+static int
+cio_procfs_create (void)
 {
 	int irq;
 
 	if (cio_proc_devinfo) {
 
-		cio_procfs_deviceinfo_root = proc_mkdir( "deviceinfo", &proc_root);
-		
+		cio_procfs_deviceinfo_root =
+		    proc_mkdir ("deviceinfo", &proc_root);
+
 		if (highest_subchannel >= MAX_CIO_PROCFS_ENTRIES) {
-			printk(KERN_ALERT "Warning: Not enough inodes for creating all entries under /proc/deviceinfo/. "
-			       "Not every device will get an entry.\n");
+			printk (KERN_ALERT
+				"Warning: Not enough inodes for creating all "
+				"entries under /proc/deviceinfo/. "
+				"Not every device will get an entry.\n");
 		}
-		
-		for (irq=0; irq<=highest_subchannel; irq++) {
+
+		for (irq = 0; irq <= highest_subchannel; irq++) {
 			if (irq >= MAX_CIO_PROCFS_ENTRIES)
 				break;
 			if (ioinfo[irq] != INVALID_STORAGE_AREA) {
-				if (ioinfo[irq]->ui.flags.oper) 
-					if (cio_procfs_device_create(ioinfo[irq]->devno) == -ENOMEM) {
-						printk(KERN_CRIT "Out of memory while creating entries in /proc/deviceinfo/, "
-						       "not all devices might show up\n");
-					break;
+				if (ioinfo[irq]->ui.flags.oper)
+					if (cio_procfs_device_create
+					    (ioinfo[irq]->devno) == -ENOMEM) {
+						printk (KERN_CRIT
+							"Out of memory while creating "
+							"entries in /proc/deviceinfo/, "
+							"not all devices might show up\n");
+						break;
 					}
 			}
 		}
-	
+
 	}
-	
+
 	return 1;
 }
 
-__initcall(cio_procfs_create);
+__initcall (cio_procfs_create);
 
 /*
  * Entry /proc/cio_ignore to display blacklisted ranges of devices.
@@ -7206,7 +8524,8 @@
  */
 
 static struct proc_dir_entry *cio_ignore_proc_entry;
-static int cio_ignore_proc_open(struct inode *inode, struct file *file)
+static int
+cio_ignore_proc_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -7215,71 +8534,80 @@
 	long flags;
 	int i, j;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 		size += nr_ignored * 6;
-		info->data = (char *) vmalloc(size);
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk( KERN_WARNING "No memory available for data\n");
+			printk (KERN_WARNING "No memory available for data\n");
 			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			spin_lock_irqsave( &blacklist_lock, flags ); 
-			for (i=0;i<=highest_ignored;i++) 
-				if (test_bit(i,&bl_dev)) {
-					len += sprintf(info->data+len, "%04x ", i);
-					for (j=i;(j<=highest_ignored) && (test_bit(j,&bl_dev));j++);
+			spin_lock_irqsave (&blacklist_lock, flags);
+			for (i = 0; i <= highest_ignored; i++)
+				if (test_bit (i, &bl_dev)) {
+					len +=
+					    sprintf (info->data + len, "%04x ",
+						     i);
+					for (j = i; (j <= highest_ignored)
+					     && (test_bit (j, &bl_dev)); j++) ;
 					j--;
-					if (i != j) 
-						len += sprintf(info->data+len, "- %04x", j);
-				len += sprintf(info->data+len, "\n");
-					i=j;
-			}
-			spin_unlock_irqrestore( &blacklist_lock, flags );
+					if (i != j)
+						len +=
+						    sprintf (info->data + len,
+							     "- %04x", j);
+					len += sprintf (info->data + len, "\n");
+					i = j;
+				}
+			spin_unlock_irqrestore (&blacklist_lock, flags);
 			info->len = len;
 		}
 	}
 	return rc;
 }
 
-static int cio_ignore_proc_close(struct inode *inode, struct file *file)
+static int
+cio_ignore_proc_close (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
 
-     if (p_info) {
-	  if (p_info->data)
-	       vfree( p_info->data );
-	  vfree( p_info );
-     }
-     
-     return rc;
+	if (p_info) {
+		if (p_info->data)
+			vfree (p_info->data);
+		vfree (p_info);
+	}
+
+	return rc;
 }
 
-static ssize_t cio_ignore_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+static ssize_t
+cio_ignore_proc_read (struct file *file, char *user_buf, size_t user_len,
+		      loff_t * offset)
 {
-     loff_t len;
-     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-     
-     if ( *offset>=p_info->len) {
-	  return 0;
-     } else {
-	  len = MIN(user_len, (p_info->len - *offset));
-	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
-	       return -EFAULT; 
-	  (* offset) += len;
-	  return len;
-     }
+	loff_t len;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+	if (*offset >= p_info->len) {
+		return 0;
+	} else {
+		len = MIN (user_len, (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
+		return len;
+	}
 }
 
-static ssize_t cio_ignore_proc_write (struct file *file, const char *user_buf,
-				      size_t user_len, loff_t * offset)
+static ssize_t
+cio_ignore_proc_write (struct file *file, const char *user_buf,
+		       size_t user_len, loff_t * offset)
 {
-	char *buffer = vmalloc (user_len);
+	char *buffer = vmalloc (user_len + 1);
 
 	if (buffer == NULL)
 		return -ENOMEM;
@@ -7287,35 +8615,37 @@
 		vfree (buffer);
 		return -EFAULT;
 	}
-	buffer[user_len]='\0';
-#ifdef CIO_DEBUG_IO
-	printk ( KERN_DEBUG "/proc/cio_ignore: '%s'\n", buffer);
-#endif /* CIO_DEBUG_IO */
+	buffer[user_len] = '\0';
+#ifdef CONFIG_DEBUG_IO
+	printk (KERN_DEBUG "/proc/cio_ignore: '%s'\n", buffer);
+#endif /* CONFIG_DEBUG_IO */
 	if (cio_debug_initialized)
-		debug_sprintf_event(cio_debug_msg_id, 2, "/proc/cio_ignore: '%s'\n",buffer);
+		debug_sprintf_event (cio_debug_msg_id, 2,
+				     "/proc/cio_ignore: '%s'\n", buffer);
 
-	blacklist_parse_proc_parameters(buffer);
+	blacklist_parse_proc_parameters (buffer);
 
+	vfree (buffer);
 	return user_len;
 }
 
-static struct file_operations cio_ignore_proc_file_ops =
-{
-	read:cio_ignore_proc_read,
-	open:cio_ignore_proc_open,
-	write:cio_ignore_proc_write,
-	release:cio_ignore_proc_close,
+static struct file_operations cio_ignore_proc_file_ops = {
+	read:cio_ignore_proc_read, open:cio_ignore_proc_open,
+	write:cio_ignore_proc_write, release:cio_ignore_proc_close,
 };
 
-static int cio_ignore_proc_init(void)
+static int
+cio_ignore_proc_init (void)
 {
-	cio_ignore_proc_entry = create_proc_entry("cio_ignore", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
+	cio_ignore_proc_entry =
+	    create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR,
+			       &proc_root);
 	cio_ignore_proc_entry->proc_fops = &cio_ignore_proc_file_ops;
 
 	return 1;
 }
 
-__initcall(cio_ignore_proc_init);
+__initcall (cio_ignore_proc_init);
 
 /*
  * Entry /proc/irq_count
@@ -7324,7 +8654,8 @@
 
 static struct proc_dir_entry *cio_irq_proc_entry;
 
-static int cio_irq_proc_open(struct inode *inode, struct file *file)
+static int
+cio_irq_proc_open (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	int size = 1;
@@ -7332,22 +8663,24 @@
 	tempinfo_t *info;
 	int i;
 
-	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk( KERN_WARNING "No memory available for data\n");
+		printk (KERN_WARNING "No memory available for data\n");
 		rc = -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 		size += NR_CPUS * 16;
-		info->data = (char *) vmalloc(size);
+		info->data = (char *) vmalloc (size);
 		if (size && info->data == NULL) {
-			printk( KERN_WARNING "No memory available for data\n");
+			printk (KERN_WARNING "No memory available for data\n");
 			vfree (info);
 			rc = -ENOMEM;
 		} else {
-			for (i=0; i< NR_CPUS; i++) {
-				if (s390_irq_count[i] != 0) 
-					len += sprintf(info->data+len, "%lx\n", s390_irq_count[i]);
+			for (i = 0; i < NR_CPUS; i++) {
+				if (s390_irq_count[i] != 0)
+					len +=
+					    sprintf (info->data + len, "%lx\n",
+						     s390_irq_count[i]);
 			}
 			info->len = len;
 		}
@@ -7355,88 +8688,260 @@
 	return rc;
 }
 
-static int cio_irq_proc_close(struct inode *inode, struct file *file)
+static int
+cio_irq_proc_close (struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
 
 	if (p_info) {
-		if (p_info->data) 
-			vfree(p_info->data);
-		vfree(p_info);
+		if (p_info->data)
+			vfree (p_info->data);
+		vfree (p_info);
 	}
 
 	return rc;
 }
 
-static ssize_t cio_irq_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+static ssize_t
+cio_irq_proc_read (struct file *file, char *user_buf, size_t user_len,
+		   loff_t * offset)
 {
 	loff_t len;
 	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-	
-	if ( *offset>=p_info->len) {
+
+	if (*offset >= p_info->len) {
 		return 0;
 	} else {
-		len = MIN(user_len, (p_info->len - *offset));
-		if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
-			return -EFAULT; 
-		(* offset) += len;
+		len = MIN (user_len, (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
 		return len;
 	}
 }
 
-static struct file_operations cio_irq_proc_file_ops = 
-	{
-		read:    cio_irq_proc_read,
-		open:    cio_irq_proc_open,
-		release: cio_irq_proc_close,
-	};
+static struct file_operations cio_irq_proc_file_ops = {
+	read:cio_irq_proc_read, open:cio_irq_proc_open,
+	release:cio_irq_proc_close,
+};
 
-static int cio_irq_proc_init(void)
+static int
+cio_irq_proc_init (void)
 {
 
 	int i;
 
 	if (cio_count_irqs) {
-		for (i=0; i<NR_CPUS; i++) 
-			s390_irq_count[i]=0;
-		cio_irq_proc_entry = create_proc_entry("irq_count", S_IFREG|S_IRUGO, &proc_root);
+		for (i = 0; i < NR_CPUS; i++)
+			s390_irq_count[i] = 0;
+		cio_irq_proc_entry =
+		    create_proc_entry ("irq_count", S_IFREG | S_IRUGO,
+				       &proc_root);
 		cio_irq_proc_entry->proc_fops = &cio_irq_proc_file_ops;
 	}
 
 	return 1;
 }
 
-__initcall(cio_irq_proc_init);	
+__initcall (cio_irq_proc_init);
+
+
+#ifdef CONFIG_CHSC
+/*
+ * /proc/chpids to display available chpids
+ * vary chpids on/off by piping to it
+ */
+
+static struct proc_dir_entry *cio_chpids_proc_entry;
+
+static int 
+cio_chpids_proc_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	tempinfo_t *info;
+	int i;
+
+	if (!cio_chsc_desc_avail) {
+		/* 
+		 * We have not yet retrieved the link addresses,
+		 * so we do it now.
+		 */
+		chsc_get_sch_descriptions();
+	}
+
+
+	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	if (info == NULL) {
+		printk( KERN_WARNING "No memory available for data\n");
+		rc = -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
+		size += NR_CHPIDS * 16;
+		info->data = (char *) vmalloc(size);
+		if ( size && info->data == NULL) {
+			printk( KERN_WARNING "No memory available for data\n");
+			vfree (info);
+			rc = -ENOMEM;
+		} else {
+			/* update our stuff */
+			chsc_get_sch_descriptions();
+			if (!cio_chsc_desc_avail) {
+				len += sprintf(info->data+len, "no info available\n");
+			} else {
+				for (i=0;i<NR_CHPIDS;i++) {
+					if ((test_bit(i, &chpids)) && 
+					    test_bit(i, &chpids_logical))
+						len += sprintf(info->data+len, 
+							       "%02X online\n", 
+							       i);
+					else if (test_bit(i, &chpids_known))
+						len += sprintf(info->data+len, 
+							       "%02X logically offline\n", 
+							       i);
+				}
+			}
+			info->len = len;
+		}
+	}
+	return rc;
+}
+
+static int 
+cio_chpids_proc_close(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+     if (p_info) {
+	  if (p_info->data)
+	       vfree( p_info->data );
+	  vfree( p_info );
+     }
+     
+     return rc;
+}
+
+static ssize_t 
+cio_chpids_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+{
+     loff_t len;
+     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+     
+     if ( *offset>=p_info->len) {
+	  return 0;
+     } else {
+	  len = MIN(user_len, (p_info->len - *offset));
+	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+	       return -EFAULT; 
+	  (* offset) += len;
+	  return len;
+     }
+}
+
+static ssize_t 
+cio_chpids_proc_write (struct file *file, const char *user_buf,
+		       size_t user_len, loff_t * offset)
+{
+	char *buffer = vmalloc (user_len + 1);
+
+	if (buffer == NULL)
+		return -ENOMEM;
+	if (copy_from_user (buffer, user_buf, user_len)) {
+		vfree (buffer);
+		return -EFAULT;
+	}
+	buffer[user_len]='\0';
+#ifdef CIO_DEBUG_IO
+	printk("/proc/chpids: '%s'\n", buffer);
+#endif /* CIO_DEBUG_IO */
+	CIO_MSG_EVENT( 2, "/proc/chpids: '%s'\n", buffer);
+
+	cio_parse_chpids_proc_parameters(buffer);
+
+	vfree (buffer);
+	return user_len;
+}
+
+static struct file_operations cio_chpids_proc_file_ops =
+{
+	read:cio_chpids_proc_read,
+	open:cio_chpids_proc_open,
+	write:cio_chpids_proc_write,
+	release:cio_chpids_proc_close,
+};
+
+static int 
+cio_chpids_proc_init(void)
+{
+
+	cio_chpids_proc_entry = create_proc_entry("chpids", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
+	cio_chpids_proc_entry->proc_fops = &cio_chpids_proc_file_ops;
+	
+	return 1;
+
 
+}
+
+__initcall(cio_chpids_proc_init);
+#endif
 /* end of procfs stuff */
 #endif
 
-schib_t *s390_get_schib( int irq )
+schib_t *
+s390_get_schib (int irq)
 {
-	if ( (irq > highest_subchannel) || (irq < 0) )
+	if ((irq > highest_subchannel) || (irq < 0))
+		return NULL;
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
 		return NULL;
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+	if (ioinfo[irq]->st)
 		return NULL;
 	return &ioinfo[irq]->schib;
 
 }
 
+int
+s390_set_private_data(int irq, void *data)
+{
+	SANITY_CHECK(irq);
+	
+	ioinfo[irq]->private_data = data;
+		
+	return 0;
+}
+
+void *
+s390_get_private_data(int irq)
+{
+	if ((irq > highest_subchannel) || (irq < 0))
+		return NULL;
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return NULL;
+	if (ioinfo[irq]->st)
+		return NULL;
+	return ioinfo[irq]->private_data;
+}
 
-EXPORT_SYMBOL(halt_IO);
-EXPORT_SYMBOL(clear_IO);
-EXPORT_SYMBOL(do_IO);
-EXPORT_SYMBOL(resume_IO);
-EXPORT_SYMBOL(ioinfo);
-EXPORT_SYMBOL(get_dev_info_by_irq);
-EXPORT_SYMBOL(get_dev_info_by_devno);
-EXPORT_SYMBOL(get_irq_by_devno);
-EXPORT_SYMBOL(get_devno_by_irq);
-EXPORT_SYMBOL(get_irq_first);
-EXPORT_SYMBOL(get_irq_next);
-EXPORT_SYMBOL(read_conf_data);
-EXPORT_SYMBOL(read_dev_chars);
-EXPORT_SYMBOL(s390_request_irq_special);
-EXPORT_SYMBOL(s390_get_schib);
-EXPORT_SYMBOL(s390_register_adapter_interrupt);
-EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
+EXPORT_SYMBOL (halt_IO);
+EXPORT_SYMBOL (clear_IO);
+EXPORT_SYMBOL (do_IO);
+EXPORT_SYMBOL (resume_IO);
+EXPORT_SYMBOL (ioinfo);
+EXPORT_SYMBOL (get_dev_info_by_irq);
+EXPORT_SYMBOL (get_dev_info_by_devno);
+EXPORT_SYMBOL (get_irq_by_devno);
+EXPORT_SYMBOL (get_devno_by_irq);
+EXPORT_SYMBOL (get_irq_first);
+EXPORT_SYMBOL (get_irq_next);
+EXPORT_SYMBOL (read_conf_data);
+EXPORT_SYMBOL (read_dev_chars);
+EXPORT_SYMBOL (s390_request_irq_special);
+EXPORT_SYMBOL (s390_get_schib);
+EXPORT_SYMBOL (s390_register_adapter_interrupt);
+EXPORT_SYMBOL (s390_unregister_adapter_interrupt);
+EXPORT_SYMBOL (s390_set_private_data);
+EXPORT_SYMBOL (s390_get_private_data);
+EXPORT_SYMBOL (s390_trigger_resense);
diff -urN linux-2.4.20-pre1/drivers/s390/s390mach.c linux-2.4.20-pre2/drivers/s390/s390mach.c
--- linux-2.4.20-pre1/drivers/s390/s390mach.c	Fri Nov  9 14:05:02 2001
+++ linux-2.4.20-pre2/drivers/s390/s390mach.c	Mon Aug 12 16:34:16 2002
@@ -22,6 +22,11 @@
 #include <asm/s390io.h>
 #include <asm/s390dyn.h>
 #include <asm/s390mach.h>
+#ifdef CONFIG_MACHCHK_WARNING
+#include <asm/signal.h>
+#endif
+
+extern void ctrl_alt_del(void);
 
 #define S390_MACHCHK_DEBUG
 
@@ -31,6 +36,9 @@
 static void        s390_enqueue_free_mchchk( mache_t *mchchk );
 static mache_t    *s390_dequeue_free_mchchk( void );
 static int         s390_collect_crw_info( void );
+#ifdef CONFIG_MACHCHK_WARNING
+static int         s390_post_warning( void );
+#endif
 
 static mache_t    *mchchk_queue_head = NULL;
 static mache_t    *mchchk_queue_tail = NULL;
@@ -41,6 +49,9 @@
 
 static struct semaphore s_sem;
 
+#ifdef CONFIG_MACHCHK_WARNING
+static int mchchk_wng_posted = 0;
+#endif
 
 /*
  * s390_init_machine_check
@@ -98,31 +109,50 @@
 	} /* endif */
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "init_mach : starting machine check handler\n");
+	printk( KERN_NOTICE "init_mach : starting machine check handler\n");
 #endif	
 
 	kernel_thread( s390_machine_check_handler, &s_sem, CLONE_FS | CLONE_FILES);
 
 	ctl_clear_bit( 14, 25 );  // disable damage MCH 	
+
+	ctl_set_bit( 14, 26 ); /* enable degradation MCH */
+	ctl_set_bit( 14, 27 ); /* enable system recovery MCH */
 #if 1
   	ctl_set_bit( 14, 28 );		// enable channel report MCH
 #endif
+#ifdef CONFIG_MACHCK_WARNING
+	ctl_set_bit( 14, 24);   /* enable warning MCH */
+#endif
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "init_mach : machine check buffer : head = %08X\n",
+	printk( KERN_DEBUG "init_mach : machine check buffer : head = %08X\n",
             (unsigned)&mchchk_queue_head);
-	printk( "init_mach : machine check buffer : tail = %08X\n",
+	printk( KERN_DEBUG "init_mach : machine check buffer : tail = %08X\n",
             (unsigned)&mchchk_queue_tail);
-	printk( "init_mach : machine check buffer : free = %08X\n",
+	printk( KERN_DEBUG "init_mach : machine check buffer : free = %08X\n",
             (unsigned)&mchchk_queue_free);
-	printk( "init_mach : CRW entry buffer anchor = %08X\n",
+	printk( KERN_DEBUG "init_mach : CRW entry buffer anchor = %08X\n",
             (unsigned)&crw_buffer_anchor);
-	printk( "init_mach : machine check handler ready\n");
+	printk( KERN_DEBUG "init_mach : machine check handler ready\n");
 #endif	
 
 	return;
 }
 
+static void s390_handle_damage(char * msg){
+
+	unsigned long caller = (unsigned long) __builtin_return_address(0);
+
+	printk(KERN_EMERG "%s\n", msg);
+#ifdef CONFIG_SMP
+	smp_send_stop();
+#endif
+	disabled_wait(caller);
+	return;
+}
+
+
 /*
  * s390_do_machine_check
  *
@@ -135,13 +165,31 @@
 	mcic_t   mcic;
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "s390_do_machine_check : starting ...\n");
+	printk( KERN_INFO "s390_do_machine_check : starting ...\n");
 #endif
 
 	memcpy( &mcic,
 	        &S390_lowcore.mcck_interruption_code,
 	        sizeof(__u64));
  		
+	if (mcic.mcc.mcd.sd) /* system damage */
+		s390_handle_damage("received system damage machine check\n");
+
+	if (mcic.mcc.mcd.pd) /* instruction processing damage */
+		s390_handle_damage("received instruction processing damage machine check\n");
+
+	if (mcic.mcc.mcd.se) /* storage error uncorrected */
+		s390_handle_damage("received storage error uncorrected machine check\n");
+
+	if (mcic.mcc.mcd.sc) /* storage error corrected */
+		printk(KERN_WARNING "received storage error corrected machine check\n");
+
+	if (mcic.mcc.mcd.ke) /* storage key-error uncorrected */
+		s390_handle_damage("received storage key-error uncorrected machine check\n");
+
+	if (mcic.mcc.mcd.ds && mcic.mcc.mcd.fa) /* storage degradation */
+		s390_handle_damage("received storage degradation machine check\n");
+
 	if ( mcic.mcc.mcd.cp )	// CRW pending ?
 	{
 		crw_count = s390_collect_crw_info();
@@ -153,9 +201,38 @@
 		} /* endif */
 
 	} /* endif */
+#ifdef CONFIG_MACHCHK_WARNING
+/*
+ * The warning may remain for a prolonged period on the bare iron.
+ * (actually till the machine is powered off, or until the problem is gone)
+ * So we just stop listening for the WARNING MCH and prevent continuously
+ * being interrupted.  One caveat is however, that we must do this per 
+ * processor and cannot use the smp version of ctl_clear_bit().
+ * On VM we only get one interrupt per virtally presented machinecheck.
+ * Though one suffices, we may get one interrupt per (virtual) processor. 
+ */
+	if ( mcic.mcc.mcd.w )	// WARNING pending ?
+	{
+		// Use single machine clear, as we cannot handle smp right now
+		__ctl_clear_bit( 14, 24 );	// Disable WARNING MCH
+
+		if ( ! mchchk_wng_posted )
+		{ 
+			mchchk_wng_posted = s390_post_warning();
+
+			if ( mchchk_wng_posted )
+			{
+				up( &s_sem );
+
+			} /* endif */
+
+		} /* endif */
+
+	} /* endif */
+#endif
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "s390_do_machine_check : done \n");
+	printk( KERN_INFO "s390_do_machine_check : done \n");
 #endif
 
 	return;
@@ -183,19 +260,19 @@
         sigfillset(&current->blocked);
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "mach_handler : ready\n");
+	printk( KERN_NOTICE "mach_handler : ready\n");
 #endif	
 
 	do {
 
 #ifdef S390_MACHCHK_DEBUG
-		printk( "mach_handler : waiting for wakeup\n");
+		printk( KERN_NOTICE "mach_handler : waiting for wakeup\n");
 #endif	
 
 		down_interruptible( sem );
 
 #ifdef S390_MACHCHK_DEBUG
-		printk( "\nmach_handler : wakeup ... \n");
+		printk( KERN_NOTICE "\nmach_handler : wakeup ... \n");
 #endif	
 		found = 0; /* init ... */
 
@@ -240,6 +317,16 @@
 
 			} /* endif */
 
+#ifdef CONFIG_MACHCHK_WARNING
+			if ( pmache->mcic.mcc.mcd.w )
+			{
+				ctrl_alt_del();		// shutdown NOW!
+#ifdef S390_MACHCHK_DEBUG
+			printk( KERN_DEBUG "mach_handler : kill -SIGPWR init\n");
+#endif
+			} /* endif */
+#endif
+
 			s390_enqueue_free_mchchk( pmache );
 		}
 		else
@@ -247,7 +334,7 @@
 
 			// unconditional surrender ...
 #ifdef S390_MACHCHK_DEBUG
-			printk( "mach_handler : nothing to do, sleeping\n");
+			printk( KERN_DEBUG "mach_handler : nothing to do, sleeping\n");
 #endif	
 
 		} /* endif */	
@@ -424,7 +511,7 @@
 	int      count  = 0;    /* CRW count */
 
 #ifdef S390_MACHCHK_DEBUG
-	printk( "crw_info : looking for CRWs ...\n");
+	printk( KERN_DEBUG "crw_info : looking for CRWs ...\n");
 #endif
 
 	do
@@ -436,7 +523,7 @@
 			count++;
 			
 #ifdef S390_MACHCHK_DEBUG
-			printk( "crw_info : CRW reports "
+			printk( KERN_DEBUG "crw_info : CRW reports "
 			        "slct=%d, oflw=%d, chn=%d, "
 			        "rsc=%X, anc=%d, erc=%X, "
 			        "rsid=%X\n",
@@ -508,7 +595,7 @@
 			if ( pccrw->crw.chn )
 			{
 #ifdef S390_MACHCHK_DEBUG
-				printk( "crw_info : "
+				printk( KERN_DEBUG "crw_info : "
 				        "chained CRWs pending ...\n\n");
 #endif
 				chain = 1;
@@ -532,3 +619,40 @@
 	return( count );
 }
 
+#ifdef CONFIG_MACHCHK_WARNING
+/*
+ * s390_post_warning
+ *
+ * Post a warning type machine check
+ *
+ * The function returns 1 when succesfull (panics otherwise)
+ */
+static int s390_post_warning( void )
+{
+	mache_t  *pmache = NULL; /* ptr to mchchk entry */
+
+	pmache = s390_dequeue_free_mchchk();
+
+	if ( pmache != NULL )
+	{
+		memset( pmache, '\0', sizeof(mache_t) );
+
+		pmache->mcic.mcc.mcd.w = 1;
+
+		s390_enqueue_mchchk( pmache );
+	}
+	else
+	{
+		panic( 	"post_warning : "
+			"unable to dequeue "
+			"free mchchk buffer" );
+	} /* endif */
+
+#ifdef S390_MACHCHK_DEBUG
+	printk( KERN_DEBUG "post_warning : 1 warning machine check posted\n");
+#endif
+
+	return ( 1 );
+}
+#endif
+
diff -urN linux-2.4.20-pre1/drivers/s390/sysinfo.c linux-2.4.20-pre2/drivers/s390/sysinfo.c
--- linux-2.4.20-pre1/drivers/s390/sysinfo.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.20-pre2/drivers/s390/sysinfo.c	Mon Aug 12 16:34:16 2002
@@ -239,106 +239,99 @@
 
 	level = stsi_0 ();
 
-	if (level < 1)
-		goto out;
-	if (stsi_1_1_1 (&info->sysinfo_1_1_1))
-		goto out;
-
-	len += sprintf (page+len, "Manufacturer:         %-16.16s\n",
-			info->sysinfo_1_1_1.manufacturer);
-	len += sprintf (page+len, "Type:                 %-4.4s\n",
-			info->sysinfo_1_1_1.type);
-	len += sprintf (page+len, "Model:                %-16.16s\n",
-			info->sysinfo_1_1_1.model);
-	len += sprintf (page+len, "Sequence Code:        %-16.16s\n",
-			info->sysinfo_1_1_1.sequence);
-	len += sprintf (page+len, "Plant:                %-4.4s\n",
-			info->sysinfo_1_1_1.plant);
-
-	if (stsi_1_2_2 (&info->sysinfo_1_2_2))
-		goto out;
-
-	len += sprintf (page+len, "\n");
-	len += sprintf (page+len, "CPUs Total:           %d\n",
-			info->sysinfo_1_2_2.cpus_total);
-	len += sprintf (page+len, "CPUs Configured:      %d\n",
-			info->sysinfo_1_2_2.cpus_configured);
-	len += sprintf (page+len, "CPUs Standby:         %d\n",
-			info->sysinfo_1_2_2.cpus_standby);
-	len += sprintf (page+len, "CPUs Reserved:        %d\n",
-			info->sysinfo_1_2_2.cpus_reserved);
-
-	len += sprintf (page+len, "Capability:           %d\n",
-			info->sysinfo_1_2_2.capability);
-
-	for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++)
-		len += sprintf (page+len, "Adjustment %02d-way:    %d\n",
-				i, info->sysinfo_1_2_2.adjustment[i-2]);
-			
-	if (level < 2)
-		goto out;
-	if (stsi_2_2_2 (&info->sysinfo_2_2_2))
-		goto out;
-
-	len += sprintf (page+len, "\n");
-	len += sprintf (page+len, "LPAR Number:          %d\n",
-			info->sysinfo_2_2_2.lpar_number);
-
-	len += sprintf (page+len, "LPAR Characteristics: ");
-	if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED)
-		len += sprintf (page+len, "Dedicated ");
-	if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED)
-		len += sprintf (page+len, "Shared ");
-	if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED)
-		len += sprintf (page+len, "Limited ");
-	len += sprintf (page+len, "\n");
-
-	len += sprintf (page+len, "LPAR Name:            %-8.8s\n",
-			info->sysinfo_2_2_2.name);
-
-	len += sprintf (page+len, "LPAR Adjustment:      %d\n",
-			info->sysinfo_2_2_2.caf);
-
-	len += sprintf (page+len, "LPAR CPUs Total:      %d\n",
-			info->sysinfo_2_2_2.cpus_total);
-	len += sprintf (page+len, "LPAR CPUs Configured: %d\n",
-			info->sysinfo_2_2_2.cpus_configured);
-	len += sprintf (page+len, "LPAR CPUs Standby:    %d\n",
-			info->sysinfo_2_2_2.cpus_standby);
-	len += sprintf (page+len, "LPAR CPUs Reserved:   %d\n",
-			info->sysinfo_2_2_2.cpus_reserved);
-	len += sprintf (page+len, "LPAR CPUs Dedicated:  %d\n",
-			info->sysinfo_2_2_2.cpus_dedicated);
-	len += sprintf (page+len, "LPAR CPUs Shared:     %d\n",
-			info->sysinfo_2_2_2.cpus_shared);
-
-	if (level < 3)
-		goto out;
-	if (stsi_3_2_2 (&info->sysinfo_3_2_2))
-		goto out;
+	if (level >= 1 && stsi_1_1_1 (&info->sysinfo_1_1_1) == 0)
+	{
+		len += sprintf (page+len, "Manufacturer:         %-16.16s\n",
+				info->sysinfo_1_1_1.manufacturer);
+		len += sprintf (page+len, "Type:                 %-4.4s\n",
+				info->sysinfo_1_1_1.type);
+		len += sprintf (page+len, "Model:                %-16.16s\n",
+				info->sysinfo_1_1_1.model);
+		len += sprintf (page+len, "Sequence Code:        %-16.16s\n",
+				info->sysinfo_1_1_1.sequence);
+		len += sprintf (page+len, "Plant:                %-4.4s\n",
+				info->sysinfo_1_1_1.plant);
+	}
+
+	if (level >= 1 && stsi_1_2_2 (&info->sysinfo_1_2_2) == 0)
+	{
+		len += sprintf (page+len, "\n");
+		len += sprintf (page+len, "CPUs Total:           %d\n",
+				info->sysinfo_1_2_2.cpus_total);
+		len += sprintf (page+len, "CPUs Configured:      %d\n",
+				info->sysinfo_1_2_2.cpus_configured);
+		len += sprintf (page+len, "CPUs Standby:         %d\n",
+				info->sysinfo_1_2_2.cpus_standby);
+		len += sprintf (page+len, "CPUs Reserved:        %d\n",
+				info->sysinfo_1_2_2.cpus_reserved);
+	
+		len += sprintf (page+len, "Capability:           %d\n",
+				info->sysinfo_1_2_2.capability);
+
+		for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++)
+			len += sprintf (page+len, "Adjustment %02d-way:    %d\n",
+					i, info->sysinfo_1_2_2.adjustment[i-2]);
+	}
 
-	for (i = 0; i < info->sysinfo_3_2_2.count; i++)
+	if (level >= 2 && stsi_2_2_2 (&info->sysinfo_2_2_2) == 0)
 	{
 		len += sprintf (page+len, "\n");
-		len += sprintf (page+len, "VM%02d Name:            %-8.8s\n",
-				i, info->sysinfo_3_2_2.vm[i].name);
-		len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n",
-				i, info->sysinfo_3_2_2.vm[i].cpi);
-
-		len += sprintf (page+len, "VM%02d Adjustment:      %d\n",
-				i, info->sysinfo_3_2_2.vm[i].caf);
-
-		len += sprintf (page+len, "VM%02d CPUs Total:      %d\n",
-				i, info->sysinfo_3_2_2.vm[i].cpus_total);
-		len += sprintf (page+len, "VM%02d CPUs Configured: %d\n",
-				i, info->sysinfo_3_2_2.vm[i].cpus_configured);
-		len += sprintf (page+len, "VM%02d CPUs Standby:    %d\n",
-				i, info->sysinfo_3_2_2.vm[i].cpus_standby);
-		len += sprintf (page+len, "VM%02d CPUs Reserved:   %d\n",
-				i, info->sysinfo_3_2_2.vm[i].cpus_reserved);
+		len += sprintf (page+len, "LPAR Number:          %d\n",
+				info->sysinfo_2_2_2.lpar_number);
+
+		len += sprintf (page+len, "LPAR Characteristics: ");
+		if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED)
+			len += sprintf (page+len, "Dedicated ");
+		if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED)
+			len += sprintf (page+len, "Shared ");
+		if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED)
+			len += sprintf (page+len, "Limited ");
+		len += sprintf (page+len, "\n");
+	
+		len += sprintf (page+len, "LPAR Name:            %-8.8s\n",
+				info->sysinfo_2_2_2.name);
+	
+		len += sprintf (page+len, "LPAR Adjustment:      %d\n",
+				info->sysinfo_2_2_2.caf);
+	
+		len += sprintf (page+len, "LPAR CPUs Total:      %d\n",
+				info->sysinfo_2_2_2.cpus_total);
+		len += sprintf (page+len, "LPAR CPUs Configured: %d\n",
+				info->sysinfo_2_2_2.cpus_configured);
+		len += sprintf (page+len, "LPAR CPUs Standby:    %d\n",
+				info->sysinfo_2_2_2.cpus_standby);
+		len += sprintf (page+len, "LPAR CPUs Reserved:   %d\n",
+				info->sysinfo_2_2_2.cpus_reserved);
+		len += sprintf (page+len, "LPAR CPUs Dedicated:  %d\n",
+				info->sysinfo_2_2_2.cpus_dedicated);
+		len += sprintf (page+len, "LPAR CPUs Shared:     %d\n",
+				info->sysinfo_2_2_2.cpus_shared);
+	}
+
+	if (level >= 3 && stsi_3_2_2 (&info->sysinfo_3_2_2) == 0)
+	{
+		for (i = 0; i < info->sysinfo_3_2_2.count; i++)
+		{
+			len += sprintf (page+len, "\n");
+			len += sprintf (page+len, "VM%02d Name:            %-8.8s\n",
+					i, info->sysinfo_3_2_2.vm[i].name);
+			len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n",
+					i, info->sysinfo_3_2_2.vm[i].cpi);
+	
+			len += sprintf (page+len, "VM%02d Adjustment:      %d\n",
+					i, info->sysinfo_3_2_2.vm[i].caf);
+	
+			len += sprintf (page+len, "VM%02d CPUs Total:      %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_total);
+			len += sprintf (page+len, "VM%02d CPUs Configured: %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_configured);
+			len += sprintf (page+len, "VM%02d CPUs Standby:    %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_standby);
+			len += sprintf (page+len, "VM%02d CPUs Reserved:   %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_reserved);
+		}
 	}
 
-out:
 	free_page (info_page);
         return len;
 }
diff -urN linux-2.4.20-pre1/drivers/sbus/char/Config.in linux-2.4.20-pre2/drivers/sbus/char/Config.in
--- linux-2.4.20-pre1/drivers/sbus/char/Config.in	Tue Feb  8 18:23:13 2000
+++ linux-2.4.20-pre2/drivers/sbus/char/Config.in	Mon Aug 12 16:34:16 2002
@@ -2,7 +2,7 @@
 comment 'Misc Linux/SPARC drivers'
 tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO
 tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC
-if [ "$ARCH" = "sparc64" ]; then
+if [ "$CONFIG_SPARC64" = "y" ]; then
    if [ "$CONFIG_PCI" = "y" ]; then
       tristate 'Siemens SAB82532 serial support' CONFIG_SAB82532
    fi
@@ -14,7 +14,7 @@
    tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX
    tristate 'Aurora Multiboard 1600se (EXPERIMENTAL)' CONFIG_SUN_AURORA
 
-   if [ "$ARCH" = "sparc" ]; then
+   if [ "$CONFIG_SPARC32" = "y" ]; then
       tristate 'Tadpole TS102 Microcontroller support (EXPERIMENTAL)' CONFIG_TADPOLE_TS102_UCTRL
 
       tristate 'JavaStation OS Flash SIMM (EXPERIMENTAL)' CONFIG_SUN_JSFLASH
diff -urN linux-2.4.20-pre1/drivers/scsi/aacraid/aacraid.h linux-2.4.20-pre2/drivers/scsi/aacraid/aacraid.h
--- linux-2.4.20-pre1/drivers/scsi/aacraid/aacraid.h	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/scsi/aacraid/aacraid.h	Mon Aug 12 16:34:16 2002
@@ -806,12 +806,6 @@
 	u8			pae_support;
 };
 
-#define AllocateAndMapFibSpace(dev, MapFibContext) \
-	dev->a_ops.AllocateAndMapFibSpace(dev, MapFibContext)
-
-#define UnmapAndFreeFibSpace(dev, MapFibContext) \
-	dev->a_ops.UnmapAndFreeFibSpace(dev, MapFibContext)
-
 #define aac_adapter_interrupt(dev) \
 	dev->a_ops.adapter_interrupt(dev)
 
diff -urN linux-2.4.20-pre1/drivers/scsi/aha152x.c linux-2.4.20-pre2/drivers/scsi/aha152x.c
--- linux-2.4.20-pre1/drivers/scsi/aha152x.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/scsi/aha152x.c	Mon Aug 12 16:34:16 2002
@@ -602,7 +602,11 @@
 #define SCDONE(SCpnt)		SCDATA(SCpnt)->done
 #define SCSEM(SCpnt)		SCDATA(SCpnt)->sem
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define SG_ADDRESS(buffer)	((buffer)->address)
+#else
 #define SG_ADDRESS(buffer)	((char *) (page_address((buffer)->page)+(buffer)->offset))
+#endif
 
 /* state handling */
 static void seldi_run(struct Scsi_Host *shpnt);
@@ -2657,7 +2661,7 @@
 		 * STCNT to trigger ENSWRAP interrupt, instead of
 		 * polling for DFIFOFULL
 		 */
-		the_time=jiffies + 10*HZ;
+		the_time=jiffies + 100*HZ;
 		while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
 			barrier();
 
@@ -2670,7 +2674,7 @@
 		if(TESTHI(DMASTAT, DFIFOFULL)) {
 			fifodata = 128;
 		} else {
-			the_time=jiffies + 10*HZ;
+			the_time=jiffies + 100*HZ;
 			while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
 				barrier();
 
@@ -2826,7 +2830,7 @@
 			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
 		}
 
-		the_time=jiffies + 10*HZ;
+		the_time=jiffies + 100*HZ;
 		while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
 			barrier();
 
diff -urN linux-2.4.20-pre1/drivers/scsi/aic7xxx/aic7xxx_host.h linux-2.4.20-pre2/drivers/scsi/aic7xxx/aic7xxx_host.h
--- linux-2.4.20-pre1/drivers/scsi/aic7xxx/aic7xxx_host.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/scsi/aic7xxx/aic7xxx_host.h	Mon Aug 12 16:34:16 2002
@@ -89,7 +89,8 @@
 	present: 0,		 /* number of 7xxx's present  */\
 	unchecked_isa_dma: 0,	 /* no memory DMA restrictions*/\
 	use_clustering: ENABLE_CLUSTERING,			\
-	use_new_eh_code: 1					\
+	use_new_eh_code: 1,					\
+	highmem_io: 1,						\
 }
 
 #endif /* _AIC7XXX_HOST_H_ */
diff -urN linux-2.4.20-pre1/drivers/scsi/aic7xxx_old/aic7xxx.h linux-2.4.20-pre2/drivers/scsi/aic7xxx_old/aic7xxx.h
--- linux-2.4.20-pre1/drivers/scsi/aic7xxx_old/aic7xxx.h	Sun Mar  4 14:30:18 2001
+++ linux-2.4.20-pre2/drivers/scsi/aic7xxx_old/aic7xxx.h	Mon Aug 12 16:34:16 2002
@@ -55,7 +55,8 @@
 	present: 0,		/* number of 7xxx's present   */\
 	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
 	use_clustering: ENABLE_CLUSTERING,			\
-	use_new_eh_code: 0					\
+	use_new_eh_code: 0,					\
+	highmem_io: 1						\
 }
 
 extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
diff -urN linux-2.4.20-pre1/drivers/scsi/fdomain.c linux-2.4.20-pre2/drivers/scsi/fdomain.c
--- linux-2.4.20-pre1/drivers/scsi/fdomain.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.20-pre2/drivers/scsi/fdomain.c	Mon Aug 12 16:34:16 2002
@@ -2041,7 +2041,7 @@
 		free_irq(shpnt->irq, shpnt);
 	if (shpnt->io_port && shpnt->n_io_port)
 		release_region(shpnt->io_port, shpnt->n_io_port);
-
+	return 0;
 }
 
 MODULE_LICENSE("GPL");
diff -urN linux-2.4.20-pre1/drivers/scsi/hosts.c linux-2.4.20-pre2/drivers/scsi/hosts.c
--- linux-2.4.20-pre1/drivers/scsi/hosts.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.20-pre2/drivers/scsi/hosts.c	Mon Aug 12 16:34:16 2002
@@ -129,7 +129,7 @@
  * once we are 100% sure that we want to use this host adapter -  it is a
  * pain to reverse this, so we try to avoid it 
  */
-
+extern int blk_nohighio;
 struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
     struct Scsi_Host * retval, *shpnt, *o_shp;
     Scsi_Host_Name *shn, *shn2;
@@ -235,6 +235,8 @@
     retval->cmd_per_lun = tpnt->cmd_per_lun;
     retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
     retval->use_clustering = tpnt->use_clustering;   
+    if (!blk_nohighio)
+	retval->highmem_io = tpnt->highmem_io;
 
     retval->select_queue_depths = tpnt->select_queue_depths;
     retval->max_sectors = tpnt->max_sectors;
diff -urN linux-2.4.20-pre1/drivers/scsi/hosts.h linux-2.4.20-pre2/drivers/scsi/hosts.h
--- linux-2.4.20-pre1/drivers/scsi/hosts.h	Mon Feb 25 11:38:04 2002
+++ linux-2.4.20-pre2/drivers/scsi/hosts.h	Mon Aug 12 16:34:16 2002
@@ -291,6 +291,8 @@
      */
     unsigned emulated:1;
 
+    unsigned highmem_io:1;
+
     /*
      * Name of proc directory
      */
@@ -390,6 +392,8 @@
     unsigned in_recovery:1;
     unsigned unchecked_isa_dma:1;
     unsigned use_clustering:1;
+    unsigned highmem_io:1;
+
     /*
      * True if this host was loaded as a loadable module
      */
diff -urN linux-2.4.20-pre1/drivers/scsi/ide-scsi.c linux-2.4.20-pre2/drivers/scsi/ide-scsi.c
--- linux-2.4.20-pre1/drivers/scsi/ide-scsi.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/scsi/ide-scsi.c	Mon Aug 12 16:34:16 2002
@@ -739,7 +739,7 @@
 	int segments = pc->scsi_cmd->use_sg;
 	struct scatterlist *sg = pc->scsi_cmd->request_buffer;
 
-	if (!drive->using_dma || !pc->request_transfer || pc->request_transfer % 1024)
+	if (!drive->using_dma || !pc->request_transfer || pc->request_transfer & 1023)
 		return NULL;
 	if (idescsi_set_direction(pc))
 		return NULL;
@@ -750,12 +750,22 @@
 		printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10);
 #endif /* IDESCSI_DEBUG_LOG */
 		while (segments--) {
-			bh->b_data = sg->address;
+			if (sg->address) {
+				bh->b_page = virt_to_page(sg->address);
+				bh->b_data = (char *) ((unsigned long) sg->address & ~PAGE_MASK);
+			} else if (sg->page) {
+				bh->b_page = sg->page;
+				bh->b_data = (char *) sg->offset;
+			}
+
 			bh->b_size = sg->length;
 			bh = bh->b_reqnext;
 			sg++;
 		}
 	} else {
+		/*
+		 * non-sg requests are guarenteed not to reside in highmem /jens
+		 */
 		if ((first_bh = bh = idescsi_kmalloc_bh (1)) == NULL)
 			return NULL;
 #if IDESCSI_DEBUG_LOG
diff -urN linux-2.4.20-pre1/drivers/scsi/lasi700.c linux-2.4.20-pre2/drivers/scsi/lasi700.c
--- linux-2.4.20-pre1/drivers/scsi/lasi700.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.20-pre2/drivers/scsi/lasi700.c	Mon Aug 12 16:34:16 2002
@@ -152,12 +152,6 @@
 		return 1;
 	}
 	memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
-	if(request_mem_region(base, 64, driver_name) == NULL) {
-		printk(KERN_ERR "%s: Failed to claim memory region\n",
-		       driver_name);
-		kfree(hostdata);
-		return 1;
-	}
 	hostdata->base = base;
 	hostdata->differential = 0;
 	if(dev->id.sversion == LASI_700_SVERSION) {
@@ -172,7 +166,6 @@
 	hostdata->pci_dev = ccio_get_fake(dev);
 	if((host = NCR_700_detect(host_tpnt, hostdata)) == NULL) {
 		kfree(hostdata);
-		release_mem_region(host->base, 64);
 		return 1;
 	}
 	host->irq = dev->irq;
@@ -196,7 +189,6 @@
 	NCR_700_release(host);
 	kfree(hostdata);
 	free_irq(host->irq, host);
-	release_mem_region(host->base, 64);
 	unregister_parisc_driver(&lasi700_driver);
 	return 1;
 }
diff -urN linux-2.4.20-pre1/drivers/scsi/megaraid.h linux-2.4.20-pre2/drivers/scsi/megaraid.h
--- linux-2.4.20-pre1/drivers/scsi/megaraid.h	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/scsi/megaraid.h	Mon Aug 12 16:34:16 2002
@@ -223,7 +223,8 @@
     cmd_per_lun:    	MAX_CMD_PER_LUN,	/* SCSI Commands per LUN	*/\
     present:	  	0,		       	/* Present			*/\
     unchecked_isa_dma:	0,		       	/* Default Unchecked ISA DMA	*/\
-    use_clustering:   	ENABLE_CLUSTERING  	/* Enable Clustering		*/\
+    use_clustering:   	ENABLE_CLUSTERING, 	/* Enable Clustering		*/\
+	highmem_io:		1, /* enable HIGHMEM I/O */ \
   }
 #endif
 
diff -urN linux-2.4.20-pre1/drivers/scsi/pas16.c linux-2.4.20-pre2/drivers/scsi/pas16.c
--- linux-2.4.20-pre1/drivers/scsi/pas16.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/drivers/scsi/pas16.c	Mon Aug 12 16:34:16 2002
@@ -311,7 +311,7 @@
  *	the passed in pas16= options
  */
 
-int __init pas16_setup(char *str, int *ints)
+int __init pas16_setup(char *str)
 {
 	static int commandline_current = 0;
 	int i;
diff -urN linux-2.4.20-pre1/drivers/scsi/qlogicfc.h linux-2.4.20-pre2/drivers/scsi/qlogicfc.h
--- linux-2.4.20-pre1/drivers/scsi/qlogicfc.h	Sun Oct 21 10:36:54 2001
+++ linux-2.4.20-pre2/drivers/scsi/qlogicfc.h	Mon Aug 12 16:34:16 2002
@@ -95,7 +95,8 @@
 	cmd_per_lun:		QLOGICFC_CMD_PER_LUN, 			   \
         present:                0,                                         \
         unchecked_isa_dma:      0,                                         \
-        use_clustering:         ENABLE_CLUSTERING 			   \
+        use_clustering:         ENABLE_CLUSTERING,			   \
+	highmem_io:		1					   \
 }
 
 #endif /* _QLOGICFC_H */
diff -urN linux-2.4.20-pre1/drivers/scsi/scsi.c linux-2.4.20-pre2/drivers/scsi/scsi.c
--- linux-2.4.20-pre1/drivers/scsi/scsi.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/scsi/scsi.c	Mon Aug 12 16:34:16 2002
@@ -191,10 +191,13 @@
  *              handler in the list - ultimately they call scsi_request_fn
  *              to do the dirty deed.
  */
-void  scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) {
-	blk_init_queue(&SDpnt->request_queue, scsi_request_fn);
-        blk_queue_headactive(&SDpnt->request_queue, 0);
-        SDpnt->request_queue.queuedata = (void *) SDpnt;
+void  scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt)
+{
+	request_queue_t *q = &SDpnt->request_queue;
+
+	blk_init_queue(q, scsi_request_fn);
+	blk_queue_headactive(q, 0);
+	q->queuedata = (void *) SDpnt;
 }
 
 #ifdef MODULE
diff -urN linux-2.4.20-pre1/drivers/scsi/scsi.h linux-2.4.20-pre2/drivers/scsi/scsi.h
--- linux-2.4.20-pre1/drivers/scsi/scsi.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/scsi/scsi.h	Mon Aug 12 16:34:16 2002
@@ -386,15 +386,6 @@
 #define ASKED_FOR_SENSE 0x20
 #define SYNC_RESET      0x40
 
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-#include <asm/pgtable.h>
-#define CONTIGUOUS_BUFFERS(X,Y) \
-	(virt_to_phys((X)->b_data+(X)->b_size-1)+1==virt_to_phys((Y)->b_data))
-#else
-#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
-#endif
-
-
 /*
  * This is the crap from the old error handling code.  We have it in a special
  * place so that we can more easily delete it later on.
@@ -633,7 +624,7 @@
 	struct scatterlist *buffer;	/* which buffer */
 	int buffers_residual;	/* how many buffers left */
 
-        dma_addr_t dma_handle;
+	dma_addr_t dma_handle;
 
 	volatile int Status;
 	volatile int Message;
diff -urN linux-2.4.20-pre1/drivers/scsi/scsi_lib.c linux-2.4.20-pre2/drivers/scsi/scsi_lib.c
--- linux-2.4.20-pre1/drivers/scsi/scsi_lib.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/scsi/scsi_lib.c	Mon Aug 12 16:34:16 2002
@@ -360,9 +360,10 @@
 				     int requeue,
 				     int frequeue)
 {
+	request_queue_t *q = &SCpnt->device->request_queue;
 	struct request *req;
 	struct buffer_head *bh;
-        Scsi_Device * SDpnt;
+	unsigned long flags;
 	int nsect;
 
 	ASSERT_LOCK(&io_request_lock, 0);
@@ -388,6 +389,7 @@
 				req->nr_sectors -= nsect;
 
 				req->current_nr_sectors = bh->b_size >> 9;
+				req->hard_cur_sectors = req->current_nr_sectors;
 				if (req->nr_sectors < req->current_nr_sectors) {
 					req->nr_sectors = req->current_nr_sectors;
 					printk("scsi_end_request: buffer-list destroyed\n");
@@ -401,37 +403,29 @@
 	 * to queue the remainder of them.
 	 */
 	if (req->bh) {
-                request_queue_t *q;
-
-		if( !requeue )
-		{
-			return SCpnt;
-		}
-
-                q = &SCpnt->device->request_queue;
-
-		req->buffer = bh->b_data;
 		/*
 		 * Bleah.  Leftovers again.  Stick the leftovers in
 		 * the front of the queue, and goose the queue again.
 		 */
-		scsi_queue_next_request(q, SCpnt);
+		if (requeue)
+			scsi_queue_next_request(q, SCpnt);
+
 		return SCpnt;
 	}
+
 	/*
 	 * This request is done.  If there is someone blocked waiting for this
 	 * request, wake them up.  Typically used to wake up processes trying
 	 * to swap a page into memory.
 	 */
-	if (req->waiting != NULL) {
+	if (req->waiting)
 		complete(req->waiting);
-	}
-	spin_lock_irq(&io_request_lock);
+
+	spin_lock_irqsave(&io_request_lock, flags);
 	req_finished_io(req);
-	spin_unlock_irq(&io_request_lock);
-	add_blkdev_randomness(MAJOR(req->rq_dev));
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
-        SDpnt = SCpnt->device;
+	add_blkdev_randomness(MAJOR(req->rq_dev));
 
 	/*
 	 * This will goose the queue request function at the end, so we don't
@@ -439,12 +433,9 @@
 	 */
 	__scsi_release_command(SCpnt);
 
-	if( frequeue ) {
-		request_queue_t *q;
+	if (frequeue)
+		scsi_queue_next_request(q, NULL);
 
-		q = &SDpnt->request_queue;
-		scsi_queue_next_request(q, NULL);                
-	}
 	return NULL;
 }
 
@@ -551,6 +542,7 @@
 	int result = SCpnt->result;
 	int this_count = SCpnt->bufflen >> 9;
 	request_queue_t *q = &SCpnt->device->request_queue;
+	struct request *req = &SCpnt->request;
 
 	/*
 	 * We must do one of several things here:
@@ -583,7 +575,7 @@
 		if (bbpnt) {
 			for (i = 0; i < SCpnt->use_sg; i++) {
 				if (bbpnt[i]) {
-					if (SCpnt->request.cmd == READ) {
+					if (req->cmd == READ) {
 						memcpy(bbpnt[i],
 						       sgpnt[i].address,
 						       sgpnt[i].length);
@@ -594,11 +586,11 @@
 		}
 		scsi_free(SCpnt->buffer, SCpnt->sglist_len);
 	} else {
-		if (SCpnt->buffer != SCpnt->request.buffer) {
-			if (SCpnt->request.cmd == READ) {
-				memcpy(SCpnt->request.buffer, SCpnt->buffer,
-				       SCpnt->bufflen);
-			}
+		if (SCpnt->buffer != req->buffer) {
+			if (PageHighMem(req->bh->b_page))
+				BUG();
+			if (req->cmd == READ)
+				memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen);
 			scsi_free(SCpnt->buffer, SCpnt->bufflen);
 		}
 	}
@@ -622,7 +614,7 @@
 					      good_sectors));
 		SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg));
 
-		SCpnt->request.errors = 0;
+		req->errors = 0;
 		/*
 		 * If multiple sectors are requested in one buffer, then
 		 * they will have been finished off by the first command.
@@ -1051,17 +1043,25 @@
 			 * get those allocated here.  
 			 */
 			if (!SDpnt->scsi_init_io_fn(SCpnt)) {
-				SCpnt = __scsi_end_request(SCpnt, 0, 
-							   SCpnt->request.nr_sectors, 0, 0);
-				if( SCpnt != NULL )
-				{
-					panic("Should not have leftover blocks\n");
-				}
+				/*
+				 * probably we ran out of sgtable memory, or
+				 * __init_io() wanted to revert to a single
+				 * segment request. this would require bouncing
+				 * on highmem i/o, so mark the device as
+				 * starved and continue later instead
+				 */
 				spin_lock_irq(&io_request_lock);
 				SHpnt->host_busy--;
 				SDpnt->device_busy--;
-				continue;
+				if (SDpnt->device_busy == 0) {
+					SDpnt->starved = 1;
+					SHpnt->some_device_starved = 1;
+				}
+				SCpnt->request.special = SCpnt;
+				list_add(&SCpnt->request.queue, &q->queue_head);
+				break;
 			}
+
 			/*
 			 * Initialize the actual SCSI command for this request.
 			 */
diff -urN linux-2.4.20-pre1/drivers/scsi/scsi_merge.c linux-2.4.20-pre2/drivers/scsi/scsi_merge.c
--- linux-2.4.20-pre1/drivers/scsi/scsi_merge.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.20-pre2/drivers/scsi/scsi_merge.c	Mon Aug 12 16:34:16 2002
@@ -6,6 +6,7 @@
  *                        Based upon conversations with large numbers
  *                        of people at Linux Expo.
  *	Support for dynamic DMA mapping: Jakub Jelinek (jakub@redhat.com).
+ *	Support for highmem I/O: Jens Axboe <axboe@suse.de>
  */
 
 /*
@@ -48,7 +49,6 @@
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
 
-
 #define __KERNEL_SYSCALLS__
 
 #include <linux/unistd.h>
@@ -95,7 +95,7 @@
 		printk("Segment 0x%p, blocks %d, addr 0x%lx\n",
 		       bh,
 		       bh->b_size >> 9,
-		       virt_to_phys(bh->b_data - 1));
+		       bh_phys(bh) - 1);
 	}
 	panic("Ththththaats all folks.  Too dangerous to continue.\n");
 }
@@ -216,11 +216,10 @@
 			 * DMA capable host, make sure that a segment doesn't span
 			 * the DMA threshold boundary.  
 			 */
-			if (dma_host &&
-			    virt_to_phys(bhnext->b_data) - 1 == ISA_DMA_THRESHOLD) {
+			if (dma_host && bh_phys(bhnext) - 1 == ISA_DMA_THRESHOLD) {
 				ret++;
 				reqsize = bhnext->b_size;
-			} else if (CONTIGUOUS_BUFFERS(bh, bhnext)) {
+			} else if (blk_seg_merge_ok(bh, bhnext)) {
 				/*
 				 * This one is OK.  Let it go.
 				 */ 
@@ -234,8 +233,7 @@
 				 * kind of screwed and we need to start
 				 * another segment.
 				 */
-				if( dma_host
-				    && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD
+				if( dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD
 				    && reqsize + bhnext->b_size > PAGE_SIZE )
 				{
 					ret++;
@@ -297,7 +295,7 @@
 }
 
 #define MERGEABLE_BUFFERS(X,Y) \
-(((((long)(X)->b_data+(X)->b_size)|((long)(Y)->b_data)) & \
+(((((long)bh_phys((X))+(X)->b_size)|((long)bh_phys((Y)))) & \
   (DMA_CHUNK_SIZE - 1)) == 0)
 
 #ifdef DMA_CHUNK_SIZE
@@ -413,6 +411,9 @@
 	if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
 		return 0;
 
+	if (!BH_PHYS_4G(req->bhtail, bh))
+		return 0;
+
 	if (use_clustering) {
 		/* 
 		 * See if we can do this without creating another
@@ -420,14 +421,11 @@
 		 * DMA capable host, make sure that a segment doesn't span
 		 * the DMA threshold boundary.  
 		 */
-		if (dma_host &&
-		    virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
+		if (dma_host && bh_phys(req->bhtail) - 1 == ISA_DMA_THRESHOLD)
 			goto new_end_segment;
-		}
-		if (CONTIGUOUS_BUFFERS(req->bhtail, bh)) {
+		if (BH_CONTIG(req->bhtail, bh)) {
 #ifdef DMA_SEGMENT_SIZE_LIMITED
-			if( dma_host
-			    && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+			if (dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD) {
 				segment_size = 0;
 				count = __count_segments(req, use_clustering, dma_host, &segment_size);
 				if( segment_size + bh->b_size > PAGE_SIZE ) {
@@ -472,6 +470,9 @@
 	if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors)
 		return 0;
 
+	if (!BH_PHYS_4G(bh, req->bh))
+		return 0;
+
 	if (use_clustering) {
 		/* 
 		 * See if we can do this without creating another
@@ -479,14 +480,12 @@
 		 * DMA capable host, make sure that a segment doesn't span
 		 * the DMA threshold boundary. 
 		 */
-		if (dma_host &&
-		    virt_to_phys(bh->b_data) - 1 == ISA_DMA_THRESHOLD) {
+		if (dma_host && bh_phys(bh) - 1 == ISA_DMA_THRESHOLD) {
 			goto new_start_segment;
 		}
-		if (CONTIGUOUS_BUFFERS(bh, req->bh)) {
+		if (BH_CONTIG(bh, req->bh)) {
 #ifdef DMA_SEGMENT_SIZE_LIMITED
-			if( dma_host
-			    && virt_to_phys(bh->b_data) - 1 >= ISA_DMA_THRESHOLD ) {
+			if (dma_host && bh_phys(bh) - 1 >= ISA_DMA_THRESHOLD) {
 				segment_size = bh->b_size;
 				count = __count_segments(req, use_clustering, dma_host, &segment_size);
 				if( count != req->nr_segments ) {
@@ -634,6 +633,9 @@
 	if ((req->nr_sectors + next->nr_sectors) > SHpnt->max_sectors)
 		return 0;
 
+	if (!BH_PHYS_4G(req->bhtail, next->bh))
+		return 0;
+
 	/*
 	 * The main question is whether the two segments at the boundaries
 	 * would be considered one or two.
@@ -645,18 +647,15 @@
 		 * DMA capable host, make sure that a segment doesn't span
 		 * the DMA threshold boundary.  
 		 */
-		if (dma_host &&
-		    virt_to_phys(req->bhtail->b_data) - 1 == ISA_DMA_THRESHOLD) {
+		if (dma_host && bh_phys(req->bhtail) - 1 == ISA_DMA_THRESHOLD)
 			goto dont_combine;
-		}
 #ifdef DMA_SEGMENT_SIZE_LIMITED
 		/*
 		 * We currently can only allocate scatter-gather bounce
 		 * buffers in chunks of PAGE_SIZE or less.
 		 */
-		if (dma_host
-		    && CONTIGUOUS_BUFFERS(req->bhtail, next->bh)
-		    && virt_to_phys(req->bhtail->b_data) - 1 >= ISA_DMA_THRESHOLD )
+		if (dma_host && BH_CONTIG(req->bhtail, next->bh)
+		    && bh_phys(req->bhtail) - 1 >= ISA_DMA_THRESHOLD)
 		{
 			int segment_size = 0;
 			int count = 0;
@@ -668,7 +667,7 @@
 			}
 		}
 #endif
-		if (CONTIGUOUS_BUFFERS(req->bhtail, next->bh)) {
+		if (BH_CONTIG(req->bhtail, next->bh)) {
 			/*
 			 * This one is OK.  Let it go.
 			 */
@@ -796,37 +795,13 @@
 	char		   * buff;
 	int		     count;
 	int		     i;
-	struct request     * req;
+	struct request     * req = &SCpnt->request;
 	int		     sectors;
 	struct scatterlist * sgpnt;
 	int		     this_count;
 	void		   ** bbpnt;
 
 	/*
-	 * FIXME(eric) - don't inline this - it doesn't depend on the
-	 * integer flags.   Come to think of it, I don't think this is even
-	 * needed any more.  Need to play with it and see if we hit the
-	 * panic.  If not, then don't bother.
-	 */
-	if (!SCpnt->request.bh) {
-		/* 
-		 * Case of page request (i.e. raw device), or unlinked buffer 
-		 * Typically used for swapping, but this isn't how we do
-		 * swapping any more.
-		 */
-		panic("I believe this is dead code.  If we hit this, I was wrong");
-#if 0
-		SCpnt->request_bufflen = SCpnt->request.nr_sectors << 9;
-		SCpnt->request_buffer = SCpnt->request.buffer;
-		SCpnt->use_sg = 0;
-		/*
-		 * FIXME(eric) - need to handle DMA here.
-		 */
-#endif
-		return 1;
-	}
-	req = &SCpnt->request;
-	/*
 	 * First we need to know how many scatter gather segments are needed.
 	 */
 	if (!sg_count_valid) {
@@ -841,21 +816,27 @@
 	 * buffer.
 	 */
 	if (dma_host && scsi_dma_free_sectors <= 10) {
-		this_count = SCpnt->request.current_nr_sectors;
+		this_count = req->current_nr_sectors;
 		goto single_segment;
 	}
 	/*
-	 * Don't bother with scatter-gather if there is only one segment.
-	 */
-	if (count == 1) {
-		this_count = SCpnt->request.nr_sectors;
+	 * we really want to use sg even for a single segment request,
+	 * however some people just cannot be bothered to write decent
+	 * driver code so we can't risk to break somebody making the
+	 * assumption that sg requests will always contain at least 2
+	 * segments. if the driver is 32-bit dma safe, then use sg for
+	 * 1 entry anyways. if not, don't rely on the driver handling this
+	 * case.
+ 	 */
+	if (count == 1 && !SCpnt->host->highmem_io) {
+		this_count = req->current_nr_sectors;
 		goto single_segment;
 	}
-	SCpnt->use_sg = count;
 
-	/* 
-	 * Allocate the actual scatter-gather table itself.
+	/*
+	 * for sane drivers, use sg even for 1 entry request
 	 */
+	SCpnt->use_sg = count;
 	SCpnt->sglist_len = (SCpnt->use_sg * sizeof(struct scatterlist));
 
 	/* If we could potentially require ISA bounce buffers, allocate
@@ -875,15 +856,25 @@
 	 * Now fill the scatter-gather table.
 	 */
 	if (!sgpnt) {
+#if 0
 		/*
 		 * If we cannot allocate the scatter-gather table, then
 		 * simply write the first buffer all by itself.
 		 */
 		printk("Warning - running *really* short on DMA buffers\n");
-		this_count = SCpnt->request.current_nr_sectors;
+		this_count = req->current_nr_sectors;
 		goto single_segment;
+#else
+		/*
+		 * it's probably better to simply always back off a little,
+		 * and let some memory be returned to dma pool instead of
+		 * always falling back to (slow) single segments
+		 */
+		return 0;
+#endif
 	}
-	/* 
+
+	/*
 	 * Next, walk the list, and fill in the addresses and sizes of
 	 * each segment.
 	 */
@@ -900,13 +891,11 @@
 
 	SCpnt->bounce_buffers = bbpnt;
 
-	for (count = 0, bh = SCpnt->request.bh;
-	     bh; bh = bh->b_reqnext) {
+	for (count = 0, bh = req->bh; bh; bh = bh->b_reqnext) {
 		if (use_clustering && bhprev != NULL) {
-			if (dma_host &&
-			    virt_to_phys(bhprev->b_data) - 1 == ISA_DMA_THRESHOLD) {
+			if (dma_host && bh_phys(bhprev) - 1 == ISA_DMA_THRESHOLD) {
 				/* Nothing - fall through */
-			} else if (CONTIGUOUS_BUFFERS(bhprev, bh)) {
+			} else if (blk_seg_merge_ok(bhprev, bh)) {
 				/*
 				 * This one is OK.  Let it go.  Note that we
 				 * do not have the ability to allocate
@@ -915,7 +904,7 @@
 				 */
 				if( dma_host ) {
 #ifdef DMA_SEGMENT_SIZE_LIMITED
-					if( virt_to_phys(bh->b_data) - 1 < ISA_DMA_THRESHOLD
+					if (bh_phys(bh) - 1 < ISA_DMA_THRESHOLD
 					    || sgpnt[count - 1].length + bh->b_size <= PAGE_SIZE ) {
 						sgpnt[count - 1].length += bh->b_size;
 						bhprev = bh;
@@ -934,13 +923,25 @@
 				}
 			}
 		}
-		count++;
-		sgpnt[count - 1].address = bh->b_data;
-		sgpnt[count - 1].page = NULL;
-		sgpnt[count - 1].length += bh->b_size;
-		if (!dma_host) {
-			SCpnt->request_bufflen += bh->b_size;
+
+		if (SCpnt->host->highmem_io) {
+			sgpnt[count].page = bh->b_page;
+			sgpnt[count].offset = bh_offset(bh);
+			sgpnt[count].address = NULL;
+		} else {
+			if (PageHighMem(bh->b_page))
+				BUG();
+
+			sgpnt[count].page = NULL;
+			sgpnt[count].address = bh->b_data;
 		}
+		
+		sgpnt[count].length = bh->b_size;
+
+		if (!dma_host)
+			SCpnt->request_bufflen += bh->b_size;
+
+		count++;
 		bhprev = bh;
 	}
 
@@ -963,6 +964,10 @@
 	for (i = 0; i < count; i++) {
 		sectors = (sgpnt[i].length >> 9);
 		SCpnt->request_bufflen += sgpnt[i].length;
+		/*
+		 * only done for dma_host, in which case .page is not
+		 * set since it's guarenteed to be a low memory page
+		 */
 		if (virt_to_phys(sgpnt[i].address) + sgpnt[i].length - 1 >
 		    ISA_DMA_THRESHOLD) {
 			if( scsi_dma_free_sectors - sectors <= 10  ) {
@@ -998,7 +1003,7 @@
 				}
 				break;
 			}
-			if (SCpnt->request.cmd == WRITE) {
+			if (req->cmd == WRITE) {
 				memcpy(sgpnt[i].address, bbpnt[i],
 				       sgpnt[i].length);
 			}
@@ -1043,8 +1048,7 @@
 	 * single-block requests if we had hundreds of free sectors.
 	 */
 	if( scsi_dma_free_sectors > 30 ) {
-		for (this_count = 0, bh = SCpnt->request.bh;
-		     bh; bh = bh->b_reqnext) {
+		for (this_count = 0, bh = req->bh; bh; bh = bh->b_reqnext) {
 			if( scsi_dma_free_sectors - this_count < 30 
 			    || this_count == sectors )
 			{
@@ -1057,21 +1061,32 @@
 		/*
 		 * Yow!   Take the absolute minimum here.
 		 */
-		this_count = SCpnt->request.current_nr_sectors;
+		this_count = req->current_nr_sectors;
 	}
 
 	/*
 	 * Now drop through into the single-segment case.
 	 */
 	
-      single_segment:
+single_segment:
+	/*
+	 * for highmem cases, we have to revert to bouncing for single
+	 * segments. rather just give up now and let the device starvation
+	 * path reinitiate this i/o later
+	 */
+	if (SCpnt->host->highmem_io)
+		return 0;
+
 	/*
 	 * Come here if for any reason we choose to do this as a single
 	 * segment.  Possibly the entire request, or possibly a small
 	 * chunk of the entire request.
 	 */
-	bh = SCpnt->request.bh;
-	buff = SCpnt->request.buffer;
+	bh = req->bh;
+	buff = req->buffer = bh->b_data;
+
+	if (PageHighMem(bh->b_page))
+		BUG();
 
 	if (dma_host) {
 		/*
@@ -1079,21 +1094,21 @@
 		 * back and allocate a really small one - enough to satisfy
 		 * the first buffer.
 		 */
-		if (virt_to_phys(SCpnt->request.bh->b_data)
-		    + (this_count << 9) - 1 > ISA_DMA_THRESHOLD) {
+		if (bh_phys(bh) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD) {
 			buff = (char *) scsi_malloc(this_count << 9);
 			if (!buff) {
 				printk("Warning - running low on DMA memory\n");
-				this_count = SCpnt->request.current_nr_sectors;
+				this_count = req->current_nr_sectors;
 				buff = (char *) scsi_malloc(this_count << 9);
 				if (!buff) {
 					dma_exhausted(SCpnt, 0);
 				}
 			}
-			if (SCpnt->request.cmd == WRITE)
-				memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9);
+			if (req->cmd == WRITE)
+				memcpy(buff, (char *) req->buffer, this_count << 9);
 		}
 	}
+
 	SCpnt->request_bufflen = this_count << 9;
 	SCpnt->request_buffer = buff;
 	SCpnt->use_sg = 0;
@@ -1132,21 +1147,11 @@
  */
 void initialize_merge_fn(Scsi_Device * SDpnt)
 {
-	request_queue_t *q;
-	struct Scsi_Host *SHpnt;
-	SHpnt = SDpnt->host;
-
-	q = &SDpnt->request_queue;
+	struct Scsi_Host *SHpnt = SDpnt->host;
+	request_queue_t *q = &SDpnt->request_queue;
+	dma64_addr_t bounce_limit;
 
 	/*
-	 * If the host has already selected a merge manager, then don't
-	 * pick a new one.
-	 */
-#if 0
-	if (q->back_merge_fn && q->front_merge_fn)
-		return;
-#endif
-	/*
 	 * If this host has an unlimited tablesize, then don't bother with a
 	 * merge manager.  The whole point of the operation is to make sure
 	 * that requests don't grow too large, and this host isn't picky.
@@ -1178,4 +1183,20 @@
 		q->merge_requests_fn = scsi_merge_requests_fn_dc;
 		SDpnt->scsi_init_io_fn = scsi_init_io_vdc;
 	}
+
+	/*
+	 * now enable highmem I/O, if appropriate
+	 */
+	bounce_limit = BLK_BOUNCE_HIGH;
+	if (SHpnt->highmem_io && (SDpnt->type == TYPE_DISK)) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			/* Platforms with virtual-DMA translation
+ 			 * hardware have no practical limit.
+			 */
+			bounce_limit = BLK_BOUNCE_ANY;
+		else
+			bounce_limit = SHpnt->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(q, bounce_limit);
 }
diff -urN linux-2.4.20-pre1/drivers/scsi/seagate.c linux-2.4.20-pre2/drivers/scsi/seagate.c
--- linux-2.4.20-pre1/drivers/scsi/seagate.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.20-pre2/drivers/scsi/seagate.c	Mon Aug 12 16:34:16 2002
@@ -21,7 +21,7 @@
  * linux 2.1.112, simplified some #defines etc. <pavel@ucw.cz>
  *
  * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to
- * read the physical disk geometry, a bad mistake. Of course it doesnt
+ * read the physical disk geometry, a bad mistake. Of course it doesn't
  * matter much what geometry one invents, but on large disks it
  * returned 256 (or more) heads, causing all kind of failures.
  * Of course this means that people might see a different geometry now,
diff -urN linux-2.4.20-pre1/drivers/scsi/sr.c linux-2.4.20-pre2/drivers/scsi/sr.c
--- linux-2.4.20-pre1/drivers/scsi/sr.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/scsi/sr.c	Mon Aug 12 16:34:16 2002
@@ -347,7 +347,8 @@
 	}
 	if (old_sg) {
 		memcpy(sg + i, old_sg, SCpnt->use_sg * sizeof(struct scatterlist));
-		memcpy(bbpnt + i, old_bbpnt, SCpnt->use_sg * sizeof(void *));
+		if (old_bbpnt)
+			memcpy(bbpnt + i, old_bbpnt, SCpnt->use_sg * sizeof(void *));
 		scsi_free(old_sg, (((SCpnt->use_sg * sizeof(struct scatterlist)) +
 				    (SCpnt->use_sg * sizeof(void *))) + 511) & ~511);
 	} else {
diff -urN linux-2.4.20-pre1/drivers/scsi/sym53c8xx.h linux-2.4.20-pre2/drivers/scsi/sym53c8xx.h
--- linux-2.4.20-pre1/drivers/scsi/sym53c8xx.h	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/drivers/scsi/sym53c8xx.h	Mon Aug 12 16:34:16 2002
@@ -97,7 +97,8 @@
 			sg_tablesize:   SCSI_NCR_SG_TABLESIZE,	\
 			cmd_per_lun:    SCSI_NCR_CMD_PER_LUN,	\
 			max_sectors:    MAX_SEGMENTS*8,		\
-			use_clustering: DISABLE_CLUSTERING} 
+			use_clustering: DISABLE_CLUSTERING,	\
+			highmem_io:	1}
 
 #else
 
diff -urN linux-2.4.20-pre1/drivers/scsi/sym53c8xx_2/sym53c8xx.h linux-2.4.20-pre2/drivers/scsi/sym53c8xx_2/sym53c8xx.h
--- linux-2.4.20-pre1/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Mon Aug 12 16:34:16 2002
@@ -119,7 +119,8 @@
 	this_id:		7,					\
 	sg_tablesize:		0,					\
 	cmd_per_lun:		0,					\
-	use_clustering:		DISABLE_CLUSTERING}
+	use_clustering:		DISABLE_CLUSTERING,			\
+	highmem_io:		1}
 
 #endif /* defined(HOSTS_C) || defined(MODULE) */ 
 
diff -urN linux-2.4.20-pre1/drivers/scsi/sym53c8xx_2/sym_glue.c linux-2.4.20-pre2/drivers/scsi/sym53c8xx_2/sym_glue.c
--- linux-2.4.20-pre1/drivers/scsi/sym53c8xx_2/sym_glue.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/drivers/scsi/sym53c8xx_2/sym_glue.c	Mon Aug 12 16:34:16 2002
@@ -125,7 +125,7 @@
  *
  *  The whole SCSI sub-system under Linux is basically single-threaded.
  *  Everything, including low-level driver interrupt routine, happens 
- *  whith the `io_request_lock' held.
+ *  with the `io_request_lock' held.
  *  The sym53c8xx-1.x drivers series ran their interrupt code using a 
  *  spin mutex per controller. This added complexity without improving 
  *  scalability significantly. the sym-2 driver still use a spinlock 
@@ -1890,7 +1890,7 @@
 					sym_name(np));
 		}
 		else {
-			if (!pci_set_dma_mask(np->s.device, 0xffffffffUL))
+			if (pci_set_dma_mask(np->s.device, 0xffffffffUL))
 				goto out_err32;
 		}
 	}
@@ -2140,6 +2140,7 @@
 	instance->max_cmd_len	= 16;
 #endif
 	instance->select_queue_depths = sym53c8xx_select_queue_depths;
+	instance->highmem_io	= 1;
 
 	SYM_UNLOCK_HCB(np, flags);
 
diff -urN linux-2.4.20-pre1/drivers/scsi/sym53c8xx_2/sym_malloc.c linux-2.4.20-pre2/drivers/scsi/sym53c8xx_2/sym_malloc.c
--- linux-2.4.20-pre1/drivers/scsi/sym53c8xx_2/sym_malloc.c	Fri Nov  9 15:22:54 2001
+++ linux-2.4.20-pre2/drivers/scsi/sym53c8xx_2/sym_malloc.c	Mon Aug 12 16:34:16 2002
@@ -143,12 +143,15 @@
 	a = (m_addr_t) ptr;
 
 	while (1) {
-#ifdef SYM_MEM_FREE_UNUSED
 		if (s == SYM_MEM_CLUSTER_SIZE) {
+#ifdef SYM_MEM_FREE_UNUSED
 			M_FREE_MEM_CLUSTER(a);
+#else
+			((m_link_p) a)->next = h[i].next;
+			h[i].next = (m_link_p) a;
+#endif
 			break;
 		}
-#endif
 		b = a ^ s;
 		q = &h[i];
 		while (q->next && q->next != (m_link_p) b) {
diff -urN linux-2.4.20-pre1/drivers/scsi/zalon7xx.c linux-2.4.20-pre2/drivers/scsi/zalon7xx.c
--- linux-2.4.20-pre1/drivers/scsi/zalon7xx.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/scsi/zalon7xx.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,162 @@
+/*
+ * Zalon 53c7xx device driver.
+ * By Richard Hirst (rhirst@linuxcare.com)
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/delay.h>
+#include <asm/gsc.h>
+
+#include "scsi.h"
+#include "hosts.h"
+
+/*
+ * **      Define the BSD style u_int32 and u_int64 type.
+ * **      Are in fact u_int32_t and u_int64_t :-)
+ * */
+typedef u32 u_int32;
+typedef u64 u_int64;
+typedef u_long          vm_offset_t;
+
+#include "zalon7xx.h"
+
+
+/* hosts_* are kluges to pass info between the zalon7xx_detected()
+** and the register_parisc_driver() callbacks.
+*/
+static Scsi_Host_Template *hosts_tptr;
+static int hosts_used=0;
+static int zalon_id = 0;
+
+extern int zalon_attach(Scsi_Host_Template *tpnt,
+			unsigned long base_addr,
+			struct parisc_device *dev,
+			int irq_vector,
+			int unit
+			);
+
+
+#if 0
+/* FIXME:
+ * Is this function dead code? or is someone planning on using it in the
+ * future.  The clock = (int) pdc_result[16] does not look correct to
+ * me ... I think it should be iodc_data[16].  Since this cause a compile
+ * error with the new encapsulated PDC, I'm not compiling in this function.
+ * - RB
+ */
+/* poke SCSI clock out of iodc data */
+
+static u8 iodc_data[32] __attribute__ ((aligned (64)));
+static unsigned long pdc_result[32] __attribute__ ((aligned (16))) ={0,0,0,0};
+
+static int 
+lasi_scsi_clock(void * hpa, int defaultclock)
+{
+	int clock, status;
+
+	status = pdc_iodc_read(&pdc_result, hpa, 0, &iodc_data, 32 );
+	if (status == PDC_RET_OK) {
+		clock = (int) pdc_result[16];
+	} else {
+		printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __FUNCTION__, status);
+		clock = defaultclock; 
+	}
+
+	printk(KERN_DEBUG "%s: SCSI clock %d\n", __FUNCTION__, clock);
+ 	return clock;
+}
+#endif
+
+static int __init
+zalon_scsi_callback(struct parisc_device *dev)
+{
+	struct gsc_irq gsc_irq;
+	u32 zalon_vers;
+	int irq;
+	unsigned long zalon = dev->hpa;
+
+	__raw_writel(CMD_RESET, zalon + IO_MODULE_IO_COMMAND);
+	while (!(__raw_readl(zalon + IO_MODULE_IO_STATUS) & IOSTATUS_RY))
+		;
+	__raw_writel(IOIIDATA_MINT5EN | IOIIDATA_PACKEN | IOIIDATA_PREFETCHEN,
+		zalon + IO_MODULE_II_CDATA);
+
+	/* XXX: Save the Zalon version for bug workarounds? */
+	zalon_vers = __raw_readl(dev->hpa + IO_MODULE_II_CDATA) & 0x07000000;
+	zalon_vers >>= 24;
+
+	/* Setup the interrupts first.
+	** Later on request_irq() will register the handler.
+	*/
+        irq = gsc_alloc_irq(&gsc_irq);
+
+	printk("%s: Zalon vers field is 0x%x, IRQ %d\n", __FUNCTION__,
+		zalon_vers, irq);
+
+	__raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, dev->hpa + IO_MODULE_EIM);
+
+	if ( zalon_vers == 0)
+		printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __FUNCTION__);
+
+	/*
+	**  zalon_attach: returns -1 on failure, 0 on success
+	*/
+	hosts_used = zalon_attach(hosts_tptr, dev->hpa + GSC_SCSI_ZALON_OFFSET,
+			dev, irq, zalon_id);
+
+	if (hosts_used == 0)
+		zalon_id++;
+
+	hosts_used = (hosts_used == 0);
+	return (hosts_used == 0);
+}
+
+static struct parisc_device_id zalon_tbl[] = {
+	{ HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00089 }, 
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, zalon_tbl);
+
+static struct parisc_driver zalon_driver = {
+	name:		"GSC SCSI (Zalon)",
+	id_table:	zalon_tbl,
+	probe:		zalon_scsi_callback,
+};
+
+int zalon7xx_detect(Scsi_Host_Template *tpnt)
+{
+	/* "pass" the parameter to the callback functions */
+	hosts_tptr = tpnt;
+	hosts_used = 0;
+
+	/* claim all zalon cards. */
+	register_parisc_driver(&zalon_driver);
+
+	/* Check if any callbacks actually found/claimed anything. */
+	return (hosts_used != 0);
+}
+
+#ifdef MODULE
+extern int ncr53c8xx_release(struct Scsi_Host *host);
+
+int zalon7xx_release(struct Scsi_Host *host)
+{
+	ncr53c8xx_release(host);
+	unregister_parisc_driver(&zalon_driver);
+	return 1;
+}
+#endif
diff -urN linux-2.4.20-pre1/drivers/scsi/zalon7xx.h linux-2.4.20-pre2/drivers/scsi/zalon7xx.h
--- linux-2.4.20-pre1/drivers/scsi/zalon7xx.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/scsi/zalon7xx.h	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,60 @@
+#ifndef ZALON7XX_H
+#define ZALON7XX_H
+
+#include <linux/types.h>
+
+#include "sym53c8xx_defs.h"
+
+extern int zalon7xx_detect(Scsi_Host_Template *);
+
+#include <scsi/scsicam.h>
+
+extern struct proc_dir_entry proc_scsi_zalon7xx;
+
+/* borrowed from drivers/scsi/ncr53c8xx.h */
+int ncr53c8xx_abort(Scsi_Cmnd *);
+int zalon7xx_detect(Scsi_Host_Template *tpnt);
+const char *ncr53c8xx_info(struct Scsi_Host *host);
+int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int);
+
+#ifdef MODULE
+int zalon7xx_release(struct Scsi_Host *);
+#else
+#define zalon7xx_release NULL
+#endif
+
+#define SCSI_ZALON { proc_name:		"zalon720",	\
+			detect:         zalon7xx_detect,	\
+			release:        zalon7xx_release,	\
+			info:           ncr53c8xx_info, 	\
+			queuecommand:   ncr53c8xx_queue_command,\
+			abort:          ncr53c8xx_abort,	\
+			reset:          ncr53c8xx_reset,	\
+			bios_param:     scsicam_bios_param,	\
+			can_queue:      SCSI_NCR_CAN_QUEUE,	\
+			this_id:        7,			\
+			sg_tablesize:   SCSI_NCR_SG_TABLESIZE,	\
+			cmd_per_lun:    SCSI_NCR_CMD_PER_LUN,	\
+			use_clustering: DISABLE_CLUSTERING} 
+
+
+#define GSC_SCSI_ZALON_OFFSET 0x800
+
+#define IO_MODULE_EIM		(1*4)
+#define IO_MODULE_DC_ADATA	(2*4)
+#define IO_MODULE_II_CDATA	(3*4)
+#define IO_MODULE_IO_COMMAND	(12*4)
+#define IO_MODULE_IO_STATUS	(13*4)
+
+#define IOSTATUS_RY             0x40
+#define IOSTATUS_FE             0x80
+#define IOIIDATA_SMINT5L        0x40000000
+#define IOIIDATA_MINT5EN        0x20000000
+#define IOIIDATA_PACKEN         0x10000000
+#define IOIIDATA_PREFETCHEN     0x08000000
+#define IOIIDATA_IOII           0x00000020
+
+#define CMD_RESET		5
+
+#endif /* ZALON7XX_H */
diff -urN linux-2.4.20-pre1/drivers/sgi/Config.in linux-2.4.20-pre2/drivers/sgi/Config.in
--- linux-2.4.20-pre1/drivers/sgi/Config.in	Sun Jul  9 22:32:58 2000
+++ linux-2.4.20-pre2/drivers/sgi/Config.in	Mon Aug 12 16:34:16 2002
@@ -11,7 +11,7 @@
 bool 'SGI DS1286  RTC support' CONFIG_SGI_DS1286
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then  
-   tristate 'SGI Newport Graphics support' CONFIG_SGI_NEWPORT_GFX
+   tristate 'SGI Newport Graphics support (EXPERIMENTAL)' CONFIG_SGI_NEWPORT_GFX
 fi
 
 endmenu
diff -urN linux-2.4.20-pre1/drivers/sound/Config.in linux-2.4.20-pre2/drivers/sound/Config.in
--- linux-2.4.20-pre1/drivers/sound/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/sound/Config.in	Fri Aug  2 17:39:44 2002
@@ -42,7 +42,7 @@
 dep_tristate '  ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
-dep_tristate '  Intel/AMD integrated audio support' CONFIG_SOUND_ICH $CONFIG_PCI $CONFIG_PCI
+dep_tristate '  Intel ICH (i8xx), SiS 7012, NVidia nForce Audio or AMD 768' CONFIG_SOUND_ICH $CONFIG_PCI
 if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
     dep_tristate '  IT8172G Sound' CONFIG_SOUND_IT8172 $CONFIG_SOUND
 fi
diff -urN linux-2.4.20-pre1/drivers/sound/awe_wave.c linux-2.4.20-pre2/drivers/sound/awe_wave.c
--- linux-2.4.20-pre1/drivers/sound/awe_wave.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.20-pre2/drivers/sound/awe_wave.c	Mon Aug 12 16:34:16 2002
@@ -4773,21 +4773,16 @@
 }
 	
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
-static struct {
-	unsigned short card_vendor, card_device;
-	unsigned short vendor;
-	unsigned short function;
-	char *name;
-} isapnp_awe_list[] __initdata = {
+static struct isapnp_device_id isapnp_awe_list[] __initdata = {
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021),
-		"AWE32 WaveTable" },
+		(unsigned long)"AWE32 WaveTable" },
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022),
-		"AWE64 WaveTable" },
+		(unsigned long)"AWE64 WaveTable" },
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023),
-		"AWE64 Gold WaveTable" },
+		(unsigned long)"AWE64 Gold WaveTable" },
 	{0}
 };
 
@@ -4818,7 +4813,7 @@
 		if (!idev)
 			continue;
 		printk(KERN_INFO "ISAPnP reports %s at i/o %#x\n",
-		       isapnp_awe_list[i].name, *port);
+		       (char*)isapnp_awe_list[i].driver_data, *port);
 		return 0;
 	}
 	return -ENODEV;
diff -urN linux-2.4.20-pre1/drivers/sound/bin2hex.c linux-2.4.20-pre2/drivers/sound/bin2hex.c
--- linux-2.4.20-pre1/drivers/sound/bin2hex.c	Wed Mar 15 10:28:32 2000
+++ linux-2.4.20-pre2/drivers/sound/bin2hex.c	Mon Aug 12 16:34:16 2002
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 int main( int argc, const char * argv [] )
diff -urN linux-2.4.20-pre1/drivers/sound/btaudio.c linux-2.4.20-pre2/drivers/sound/btaudio.c
--- linux-2.4.20-pre1/drivers/sound/btaudio.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/sound/btaudio.c	Mon Aug 12 16:34:16 2002
@@ -144,17 +144,17 @@
 	int sampleshift;
 	int channels;
 	int analog;
+	int rate;
+};
+
+struct cardinfo {
+	char *name;
+	int rate;
 };
 
 static struct btaudio *btaudios = NULL;
-static unsigned int dsp1 = -1;
-static unsigned int dsp2 = -1;
-static unsigned int mixer = -1;
 static unsigned int debug = 0;
 static unsigned int irq_debug = 0;
-static int digital = 1;
-static int analog = 1;
-static int rate = 32000;
 
 /* -------------------------------------------------------------- */
 
@@ -657,7 +657,7 @@
 		if (bta->analog) {
 			return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, (int*)arg);
 		} else {
-			return put_user(rate, (int*)arg);
+			return put_user(bta->rate, (int*)arg);
 		}
 
         case SNDCTL_DSP_STEREO:
@@ -870,11 +870,33 @@
 
 /* -------------------------------------------------------------- */
 
+static unsigned int dsp1 = -1;
+static unsigned int dsp2 = -1;
+static unsigned int mixer = -1;
+static int latency = -1;
+static int digital = 1;
+static int analog = 1;
+static int rate = 0;
+
+#define BTA_OSPREY200 1
+
+static struct cardinfo cards[] = {
+	[0] = {
+		name: "default",
+		rate: 32000,
+	},
+	[BTA_OSPREY200] = {
+		name: "Osprey 200",
+		rate: 44100,
+	},
+};
+
 static int __devinit btaudio_probe(struct pci_dev *pci_dev,
 				   const struct pci_device_id *pci_id)
 {
 	struct btaudio *bta;
-	unsigned char revision,latency;
+	struct cardinfo *card = &cards[pci_id->driver_data];
+	unsigned char revision,lat;
 	int rc = -EBUSY;
 
 	if (pci_enable_device(pci_dev))
@@ -908,16 +930,27 @@
 		bta->sampleshift = 1;
 	}
 
+	/* sample rate */
+	bta->rate = card->rate;
+	if (rate)
+		bta->rate = rate;
+	
 	init_MUTEX(&bta->lock);
         init_waitqueue_head(&bta->readq);
 
+	if (-1 != latency) {
+		printk(KERN_INFO "btaudio: setting pci latency timer to %d\n",
+		       latency);
+		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+	}
         pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
-        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &latency);
+        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat);
         printk(KERN_INFO "btaudio: Bt%x (rev %d) at %02x:%02x.%x, ",
 	       pci_dev->device,revision,pci_dev->bus->number,
 	       PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn));
-        printk("irq: %d, latency: %d, memory: 0x%lx\n",
-	       bta->irq, latency, bta->mem);
+        printk("irq: %d, latency: %d, mmio: 0x%lx\n",
+	       bta->irq, lat, bta->mem);
+	printk("btaudio: using card config \"%s\"\n", card->name);
 
 	/* init hw */
         btwrite(0, REG_GPIO_DMA_CTL);
@@ -926,7 +959,7 @@
 	pci_set_master(pci_dev);
 
 	if ((rc = request_irq(bta->irq, btaudio_irq, SA_SHIRQ|SA_INTERRUPT,
-			       "btaudio",(void *)bta)) < 0) {
+			      "btaudio",(void *)bta)) < 0) {
 		printk(KERN_WARNING
 		       "btaudio: can't request irq (rc=%d)\n",rc);
 		goto fail1;
@@ -1028,11 +1061,25 @@
 /* -------------------------------------------------------------- */
 
 static struct pci_device_id btaudio_pci_tbl[] __devinitdata = {
-        { PCI_VENDOR_ID_BROOKTREE, 0x0878,
-          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-        { PCI_VENDOR_ID_BROOKTREE, 0x0879,
-          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-        {0,}
+        {
+		vendor:       PCI_VENDOR_ID_BROOKTREE,
+		device:       0x0878,
+		subvendor:    0x0070,
+		subdevice:    0xff01,
+		driver_data:  BTA_OSPREY200,
+	},{
+		vendor:       PCI_VENDOR_ID_BROOKTREE,
+		device:       0x0878,
+		subvendor:    PCI_ANY_ID,
+		subdevice:    PCI_ANY_ID,
+	},{
+		vendor:       PCI_VENDOR_ID_BROOKTREE,
+		device:       0x0878,
+		subvendor:    PCI_ANY_ID,
+		subdevice:    PCI_ANY_ID,
+        },{
+		/* --- end of list --- */
+	}
 };
 
 static struct pci_driver btaudio_pci_driver = {
@@ -1044,7 +1091,7 @@
 
 static int btaudio_init_module(void)
 {
-	printk(KERN_INFO "btaudio: driver version 0.6 loaded [%s%s%s]\n",
+	printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",
 	       digital ? "digital" : "",
 	       analog && digital ? "+" : "",
 	       analog ? "analog" : "");
@@ -1068,6 +1115,8 @@
 MODULE_PARM(digital,"i");
 MODULE_PARM(analog,"i");
 MODULE_PARM(rate,"i");
+MODULE_PARM(latency,"i");
+MODULE_PARM_DESC(latency,"pci latency timer");
 
 MODULE_DEVICE_TABLE(pci, btaudio_pci_tbl);
 MODULE_DESCRIPTION("bt878 audio dma driver");
diff -urN linux-2.4.20-pre1/drivers/sound/cs4232.c linux-2.4.20-pre2/drivers/sound/cs4232.c
--- linux-2.4.20-pre1/drivers/sound/cs4232.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/sound/cs4232.c	Mon Aug 12 16:34:16 2002
@@ -158,7 +158,7 @@
 	 * method conflicts with possible PnP support in the OS. For this reason 
 	 * driver is just a temporary kludge.
 	 *
-	 * Also the Cirrus/Crystal method doesnt always work. Try ISA PnP first ;)
+	 * Also the Cirrus/Crystal method doesn't always work. Try ISA PnP first ;)
 	 */
 
 	/*
@@ -444,6 +444,7 @@
 	isapnpcfg->io_base	= dev->resource[0].start;
 	if (probe_cs4232(isapnpcfg,TRUE) == 0) {
 		printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n");
+		kfree(isapnpcfg);
 		return -ENODEV;
 	}
 	attach_cs4232(isapnpcfg);
diff -urN linux-2.4.20-pre1/drivers/sound/pss.c linux-2.4.20-pre2/drivers/sound/pss.c
--- linux-2.4.20-pre1/drivers/sound/pss.c	Mon Feb 25 11:38:06 2002
+++ linux-2.4.20-pre2/drivers/sound/pss.c	Mon Aug 12 16:34:16 2002
@@ -1131,7 +1131,7 @@
 MODULE_PARM(pss_mixer, "b");
 MODULE_PARM_DESC(pss_mixer, "Enable (1) or disable (0) PSS mixer (controlling of output volume, bass, treble, synth volume). The mixer is not available on all PSS cards.");
 MODULE_AUTHOR("Hannu Savolainen, Vladimir Michl");
-MODULE_DESCRIPTION("Module for PSS sound cards (based on AD1848, ADSP-2115 and ESC614). This module includes control of output amplifier and synth volume of the Beethoven ADSP-16 card (this may work with other PSS cards).\n");
+MODULE_DESCRIPTION("Module for PSS sound cards (based on AD1848, ADSP-2115 and ESC614). This module includes control of output amplifier and synth volume of the Beethoven ADSP-16 card (this may work with other PSS cards).");
 MODULE_LICENSE("GPL");
 
 
diff -urN linux-2.4.20-pre1/drivers/usb/CDCEther.c linux-2.4.20-pre2/drivers/usb/CDCEther.c
--- linux-2.4.20-pre1/drivers/usb/CDCEther.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/usb/CDCEther.c	Mon Aug 12 16:34:16 2002
@@ -497,14 +497,14 @@
 static void CDC_SetEthernetPacketFilter (ether_dev_t *ether_dev)
 {
 #if 0
-	devrequest *dr = &ether_dev->ctrl_dr;
+	struct usb_ctrlrequest *dr = &ether_dev->ctrl_dr;
 	int res;
 
-	dr->requesttype = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
-	dr->request = SET_ETHERNET_PACKET_FILTER;
-	dr->value = cpu_to_le16(ether_dev->mode_flags);
-	dr->index = cpu_to_le16((u16)ether_dev->comm_interface);
-	dr->length = 0;
+	dr->bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+	dr->bRequest = SET_ETHERNET_PACKET_FILTER;
+	dr->wValue = cpu_to_le16(ether_dev->mode_flags);
+	dr->wIndex = cpu_to_le16((u16)ether_dev->comm_interface);
+	dr->wLength = 0;
 
 	FILL_CONTROL_URB(&ether_dev->ctrl_urb,
 			ether_dev->usb,
diff -urN linux-2.4.20-pre1/drivers/usb/CDCEther.h linux-2.4.20-pre2/drivers/usb/CDCEther.h
--- linux-2.4.20-pre1/drivers/usb/CDCEther.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/CDCEther.h	Mon Aug 12 16:34:16 2002
@@ -75,7 +75,7 @@
 	__u8			bNumberPowerFilters;
 	__u16			mode_flags;
 	int			intr_interval;
-	devrequest		ctrl_dr;
+	struct usb_ctrlrequest	ctrl_dr;
 	struct urb		rx_urb, tx_urb, intr_urb, ctrl_urb;
 	unsigned char		rx_buff[CDC_ETHER_MAX_MTU] __attribute__((aligned(L1_CACHE_BYTES)));
 	unsigned char		tx_buff[CDC_ETHER_MAX_MTU] __attribute__((aligned(L1_CACHE_BYTES)));
diff -urN linux-2.4.20-pre1/drivers/usb/Config.in linux-2.4.20-pre2/drivers/usb/Config.in
--- linux-2.4.20-pre1/drivers/usb/Config.in	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/Config.in	Mon Aug 12 16:34:16 2002
@@ -33,6 +33,7 @@
    dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
    dep_tristate '    EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO
    dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB MIDI support' CONFIG_USB_MIDI $CONFIG_USB
    if [ "$CONFIG_SCSI" = "n" ]; then
       comment '  SCSI support is needed for USB Storage'
    fi
@@ -59,6 +60,7 @@
       dep_tristate '  USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
       dep_tristate '  USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
    fi
+   dep_tristate '  Aiptek 6000U/8000U tablet support' CONFIG_USB_AIPTEK $CONFIG_USB $CONFIG_INPUT
    dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
 
    comment 'USB Imaging devices'
@@ -101,6 +103,7 @@
    comment 'USB Miscellaneous drivers'
    dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  Texas Instruments Graph Link USB (aka SilverLink) cable support' CONFIG_USB_TIGL $CONFIG_USB
    dep_tristate '  Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
 fi
 endmenu
diff -urN linux-2.4.20-pre1/drivers/usb/Makefile linux-2.4.20-pre2/drivers/usb/Makefile
--- linux-2.4.20-pre1/drivers/usb/Makefile	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/Makefile	Mon Aug 12 16:34:16 2002
@@ -62,6 +62,7 @@
 obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
 obj-$(CONFIG_USB_HID)		+= hid.o
 obj-$(CONFIG_USB_KBD)		+= usbkbd.o
+obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
 
 obj-$(CONFIG_USB_SCANNER)	+= scanner.o
@@ -69,6 +70,7 @@
 obj-$(CONFIG_USB_PRINTER)	+= printer.o
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
 obj-$(CONFIG_USB_EMI26)		+= emi26.o
+obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_IBMCAM)	+= ibmcam.o usbvideo.o ultracam.o
 obj-$(CONFIG_USB_PWC)		+= pwc.o
 obj-$(CONFIG_USB_DC2XX)		+= dc2xx.o
@@ -85,6 +87,7 @@
 obj-$(CONFIG_USB_KAWETH)        += kaweth.o
 obj-$(CONFIG_USB_CDCETHER)	+= CDCEther.o
 obj-$(CONFIG_USB_RIO500)	+= rio500.o
+obj-$(CONFIG_USB_TIGL)          += tiglusb.o
 obj-$(CONFIG_USB_DSBR)		+= dsbr100.o
 obj-$(CONFIG_USB_MICROTEK)	+= microtek.o
 obj-$(CONFIG_USB_HPUSBSCSI)	+= hpusbscsi.o
diff -urN linux-2.4.20-pre1/drivers/usb/acm.c linux-2.4.20-pre2/drivers/usb/acm.c
--- linux-2.4.20-pre1/drivers/usb/acm.c	Fri Oct  5 12:06:08 2001
+++ linux-2.4.20-pre2/drivers/usb/acm.c	Mon Aug 12 16:34:16 2002
@@ -184,7 +184,7 @@
 static void acm_ctrl_irq(struct urb *urb)
 {
 	struct acm *acm = urb->context;
-	devrequest *dr = urb->transfer_buffer;
+	struct usb_ctrlrequest *dr = urb->transfer_buffer;
 	unsigned char *data = (unsigned char *)(dr + 1);
 	int newctrl;
 
@@ -195,7 +195,7 @@
 		return;
 	}
 
-	switch (dr->request) {
+	switch (dr->bRequest) {
 
 		case ACM_IRQ_NETWORK:
 
@@ -223,7 +223,7 @@
 
 		default:
 			dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",
-				dr->request, dr->index, dr->length, data[0], data[1]);
+				dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]);
 			return;
 	}
 }
diff -urN linux-2.4.20-pre1/drivers/usb/aiptek.c linux-2.4.20-pre2/drivers/usb/aiptek.c
--- linux-2.4.20-pre1/drivers/usb/aiptek.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/aiptek.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,332 @@
+/*
+ *  Native support for the Aiptek 8000U
+ *
+ *  Copyright (c) 2001 Chris Atenasio		<chris@crud.net>
+ *
+ *  based on wacom.c by
+ *     Vojtech Pavlik      <vojtech@suse.cz>
+ *     Andreas Bach Aaen   <abach@stofanet.dk>
+ *     Clifford Wolf       <clifford@clifford.at>
+ *     Sam Mosel           <sam.mosel@computer.org>
+ *     James E. Blair      <corvus@gnu.org>
+ *     Daniel Egger        <egger@suse.de>
+ *
+ *
+ *  Many thanks to Oliver Kuechemann for his support.
+ *
+ *  ChangeLog:
+ *      v0.1 - Initial release
+ *      v0.2 - Hack to get around fake event 28's.
+ *      v0.3 - Make URB dynamic (Bryan W. Headley, Jun-8-2002)
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.3"
+#define DRIVER_AUTHOR "Chris Atenasio <chris@crud.net>"
+#define DRIVER_DESC "USB Aiptek 6000U/8000U tablet driver (Linux 2.4.x)"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Aiptek status packet:
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     0     1     0
+ * byte1  X7    X6    X5    X4    X3    X2    X1    X0
+ * byte2  X15   X14   X13   X12   X11   X10   X9    X8
+ * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
+ * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
+ * byte5   *     *     *    BS2   BS1   Tip   DV    IR
+ * byte6  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte7  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * IR: In Range = Proximity on
+ * DV = Data Valid
+ *
+ * 
+ * Command Summary:
+ *
+ * Command/Data    Description     Return Bytes    Return Value
+ * 0x10/0x00       SwitchToMouse       0
+ * 0x10/0x01       SwitchToTablet      0
+ * 0x18/0x04       Resolution500LPI    0
+ * 0x17/0x00       FilterOn            0
+ * 0x12/0xFF       AutoGainOn          0
+ * 0x01/0x00       GetXExtension       2           MaxX
+ * 0x01/0x01       GetYExtension       2           MaxY
+ * 0x02/0x00       GetModelCode        2           ModelCode = LOBYTE
+ * 0x03/0x00       GetODMCode          2           ODMCode
+ * 0x08/0x00       GetPressureLevels   2           =512
+ * 0x04/0x00       GetFirmwareVersion  2           Firmware Version
+ *
+ *
+ * To initialize the tablet:
+ *
+ * (1) Send command Resolution500LPI
+ * (2) Option Commands (GetXExtension, GetYExtension)
+ * (3) Send command SwitchToTablet
+ */
+
+#define USB_VENDOR_ID_AIPTEK   0x08ca
+
+struct aiptek_features {
+	char *name;
+	int pktlen;
+	int x_max;
+	int y_max;
+	int pressure_min;
+	int pressure_max;
+	void (*irq) (struct urb * urb);
+	unsigned long evbit;
+	unsigned long absbit;
+	unsigned long relbit;
+	unsigned long btnbit;
+	unsigned long digibit;
+};
+
+struct aiptek {
+	signed char data[10];
+	struct input_dev dev;
+	struct usb_device *usbdev;
+	struct urb *irq;
+	struct aiptek_features *features;
+	int tool;
+	int open;
+};
+
+static void
+aiptek_irq(struct urb *urb)
+{
+	struct aiptek *aiptek = urb->context;
+	unsigned char *data = aiptek->data;
+	struct input_dev *dev = &aiptek->dev;
+	int x;
+	int y;
+	int pressure;
+	int proximity;
+
+	if (urb->status)
+		return;
+
+	if ((data[0] & 2) == 0) {
+		dbg("received unknown report #%d", data[0]);
+	}
+
+	proximity = data[5] & 0x01;
+	input_report_key(dev, BTN_TOOL_PEN, proximity);
+
+	x = ((__u32) data[1]) | ((__u32) data[2] << 8);
+	y = ((__u32) data[3]) | ((__u32) data[4] << 8);
+	pressure = ((__u32) data[6]) | ((__u32) data[7] << 8);
+	pressure -= aiptek->features->pressure_min;
+
+	if (pressure < 0) {
+		pressure = 0;
+	}
+
+	if (proximity) {
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
+		input_report_abs(dev, ABS_PRESSURE, pressure);
+		input_report_key(dev, BTN_TOUCH, data[5] & 0x04);
+		input_report_key(dev, BTN_STYLUS, data[5] & 0x08);
+		input_report_key(dev, BTN_STYLUS2, data[5] & 0x10);
+	}
+
+}
+
+struct aiptek_features aiptek_features[] = {
+	{"Aiptek 6000U/8000U", 
+	 8, 3000, 2250, 26, 511, aiptek_irq, 0, 0, 0, 0},
+	{NULL, 0}
+};
+
+struct usb_device_id aiptek_ids[] = {
+	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x20), driver_info:0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, aiptek_ids);
+
+static int
+aiptek_open(struct input_dev *dev)
+{
+	struct aiptek *aiptek = dev->private;
+
+	if (aiptek->open++)
+		return 0;
+
+	aiptek->irq->dev = aiptek->usbdev;
+	if (usb_submit_urb(aiptek->irq))
+		return -EIO;
+
+	return 0;
+}
+
+static void
+aiptek_close(struct input_dev *dev)
+{
+	struct aiptek *aiptek = dev->private;
+
+	if (!--aiptek->open)
+		usb_unlink_urb(aiptek->irq);
+}
+
+static void
+aiptek_command(struct usb_device *dev, unsigned int ifnum,
+	       unsigned char command, unsigned char data)
+{
+	__u8 buf[3];
+
+	buf[0] = 4;
+	buf[1] = command;
+	buf[2] = data;
+
+	if (usb_set_report(dev, ifnum, 3, 2, buf, 3) != 3) {
+		dbg("aiptek_command: 0x%x 0x%x\n", command, data);
+	}
+}
+
+static void*
+aiptek_probe(struct usb_device *dev, unsigned int ifnum,
+	     const struct usb_device_id *id)
+{
+	struct usb_endpoint_descriptor *endpoint;
+	struct aiptek *aiptek;
+
+	if (!(aiptek = kmalloc(sizeof (struct aiptek), GFP_KERNEL)))
+		return NULL;
+
+	memset(aiptek, 0, sizeof (struct aiptek));
+
+	aiptek->irq = usb_alloc_urb(0);
+	if (!aiptek->irq) {
+		kfree(aiptek);
+		return NULL;
+	}
+
+	// Resolution500LPI
+	aiptek_command(dev, ifnum, 0x18, 0x04);
+
+	// SwitchToTablet
+	aiptek_command(dev, ifnum, 0x10, 0x01);
+
+	aiptek->features = aiptek_features + id->driver_info;
+
+	aiptek->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC) |
+	    aiptek->features->evbit;
+
+	aiptek->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) |
+	    BIT(ABS_MISC) | aiptek->features->absbit;
+
+	aiptek->dev.relbit[0] |= aiptek->features->relbit;
+
+	aiptek->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
+	    BIT(BTN_MIDDLE) | aiptek->features->btnbit;
+
+	aiptek->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) |
+	    BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOUCH) |
+	    BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | aiptek->features->digibit;
+
+	aiptek->dev.mscbit[0] = BIT(MSC_SERIAL);
+
+	aiptek->dev.absmax[ABS_X] = aiptek->features->x_max;
+	aiptek->dev.absmax[ABS_Y] = aiptek->features->y_max;
+	aiptek->dev.absmax[ABS_PRESSURE] = aiptek->features->pressure_max -
+	    aiptek->features->pressure_min;
+
+	aiptek->dev.absfuzz[ABS_X] = 0;
+	aiptek->dev.absfuzz[ABS_Y] = 0;
+
+	aiptek->dev.private = aiptek;
+	aiptek->dev.open = aiptek_open;
+	aiptek->dev.close = aiptek_close;
+
+	aiptek->dev.name = aiptek->features->name;
+	aiptek->dev.idbus = BUS_USB;
+	aiptek->dev.idvendor = dev->descriptor.idVendor;
+	aiptek->dev.idproduct = dev->descriptor.idProduct;
+	aiptek->dev.idversion = dev->descriptor.bcdDevice;
+	aiptek->usbdev = dev;
+
+	endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+
+	FILL_INT_URB(aiptek->irq,
+		  dev,
+		  usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+		         aiptek->data,
+		  aiptek->features->pktlen,
+		         aiptek->features->irq,
+		  aiptek,
+		  endpoint->bInterval);
+
+	input_register_device(&aiptek->dev);
+
+	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
+	       aiptek->dev.number, aiptek->features->name, dev->bus->busnum,
+	       dev->devnum, ifnum);
+
+	return aiptek;
+}
+
+static void
+aiptek_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct aiptek *aiptek = ptr;
+	usb_unlink_urb(aiptek->irq);
+	input_unregister_device(&aiptek->dev);
+	usb_free_urb(aiptek->irq);
+	kfree(aiptek);
+}
+
+static struct usb_driver aiptek_driver = {
+	name:"aiptek",
+	probe:aiptek_probe,
+	disconnect:aiptek_disconnect,
+	id_table:aiptek_ids,
+};
+
+static int __init
+aiptek_init(void)
+{
+	usb_register(&aiptek_driver);
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+}
+
+static void __exit
+aiptek_exit(void)
+{
+	usb_deregister(&aiptek_driver);
+}
+
+module_init(aiptek_init);
+module_exit(aiptek_exit);
diff -urN linux-2.4.20-pre1/drivers/usb/audio.c linux-2.4.20-pre2/drivers/usb/audio.c
--- linux-2.4.20-pre1/drivers/usb/audio.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/audio.c	Mon Aug 12 16:34:16 2002
@@ -297,13 +297,13 @@
 #define FLG_CONNECTED    32
 
 struct my_data_urb {
-	urb_t urb;
-	iso_packet_descriptor_t isoframe[DESCFRAMES];
+	struct urb urb;
+	struct iso_packet_descriptor isoframe[DESCFRAMES];
 };
 
 struct my_sync_urb {
-	urb_t urb;
-	iso_packet_descriptor_t isoframe[SYNCFRAMES];
+	struct urb urb;
+	struct iso_packet_descriptor isoframe[SYNCFRAMES];
 };
 
 
@@ -833,7 +833,7 @@
 	}
 }		
 
-static int usbin_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i, maxsize, offs;
 
@@ -850,7 +850,7 @@
  * return value: 0 if descriptor should be restarted, -1 otherwise
  * convert sample format on the fly if necessary
  */
-static int usbin_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_retire_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
 	unsigned char *cp;
@@ -930,7 +930,7 @@
 /*
  * we output sync data
  */
-static int usbin_sync_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
 	unsigned int i, offs;
@@ -948,7 +948,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbin_sync_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i;
 	
@@ -996,7 +996,7 @@
 {
 	struct usb_device *dev = as->state->usbdev;
 	struct usbin *u = &as->usbin;
-	purb_t urb;
+	struct urb *urb;
 	unsigned long flags;
 	unsigned int maxsze, bufsz;
 
@@ -1186,7 +1186,7 @@
 	}
 }		
 
-static int usbout_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
 	unsigned char *cp = urb->transfer_buffer;
@@ -1238,7 +1238,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_retire_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i;
 
@@ -1285,7 +1285,7 @@
 	spin_unlock_irqrestore(&as->lock, flags);
 }
 
-static int usbout_sync_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i, offs;
 
@@ -1299,7 +1299,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_sync_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
 	unsigned int f, i;
@@ -1361,7 +1361,7 @@
 {
 	struct usb_device *dev = as->state->usbdev;
 	struct usbout *u = &as->usbout;
-	purb_t urb;
+	struct urb *urb;
 	unsigned long flags;
 	unsigned int maxsze, bufsz;
 
diff -urN linux-2.4.20-pre1/drivers/usb/auerswald.c linux-2.4.20-pre2/drivers/usb/auerswald.c
--- linux-2.4.20-pre1/drivers/usb/auerswald.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/auerswald.c	Mon Aug 12 16:34:16 2002
@@ -176,7 +176,7 @@
 typedef struct
 {
         struct auerchain *chain;        /* pointer to the chain to which this element belongs */
-        urb_t * urbp;                   /* pointer to attached urb */
+        struct urb * urbp;                   /* pointer to attached urb */
         void *context;                  /* saved URB context */
         usb_complete_t complete;        /* saved URB completion function */
         struct list_head list;          /* to include element into a list */
@@ -206,8 +206,8 @@
         char *bufp;                     /* reference to allocated data buffer */
         unsigned int len;               /* number of characters in data buffer */
 	unsigned int retries;		/* for urb retries */
-        devrequest *dr;                 /* for setup data in control messages */
-        urb_t * urbp;                   /* USB urb */
+        struct usb_ctrlrequest *dr;                 /* for setup data in control messages */
+        struct urb * urbp;                   /* USB urb */
         struct auerbufctl *list;        /* pointer to list */
         struct list_head buff_list;     /* reference to next buffer in list */
 } auerbuf_t,*pauerbuf_t;
@@ -244,7 +244,7 @@
 	int			open_count;	    /* count the number of open character channels */
         char 			dev_desc[AUSI_DLEN];/* for storing a textual description */
         unsigned int 		maxControlLength;   /* max. Length of control paket (without header) */
-        urb_t * 		inturbp;            /* interrupt urb */
+        struct urb * 		inturbp;            /* interrupt urb */
         char *			intbufp;            /* data buffer for interrupt urb */
 	unsigned int 		irqsize;	    /* size of interrupt endpoint 1 */
         struct auerchain 	controlchain;  	    /* for chaining of control messages */
@@ -281,7 +281,7 @@
 
 /*-------------------------------------------------------------------*/
 /* Forwards */
-static void auerswald_ctrlread_complete (urb_t * urb);
+static void auerswald_ctrlread_complete (struct urb * urb);
 static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
 
 
@@ -290,7 +290,7 @@
 /* --------------------------                                        */
 
 /* completion function for chained urbs */
-static void auerchain_complete (urb_t * urb)
+static void auerchain_complete (struct urb * urb)
 {
 	unsigned long flags;
         int result;
@@ -357,7 +357,7 @@
    this function may be called from completion context or from user space!
    early = 1 -> submit in front of chain
 */
-static int auerchain_submit_urb_list (pauerchain_t acp, urb_t * urb, int early)
+static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int early)
 {
         int result;
         unsigned long flags;
@@ -431,7 +431,7 @@
 /* submit function for chained urbs
    this function may be called from completion context or from user space!
 */
-static int auerchain_submit_urb (pauerchain_t acp, urb_t * urb)
+static int auerchain_submit_urb (pauerchain_t acp, struct urb * urb)
 {
 	return auerchain_submit_urb_list (acp, urb, 0);
 }
@@ -440,10 +440,10 @@
    the result is 0 if the urb is cancelled, or -EINPROGRESS if
    USB_ASYNC_UNLINK is set and the function is successfully started.
 */
-static int auerchain_unlink_urb (pauerchain_t acp, urb_t * urb)
+static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb)
 {
 	unsigned long flags;
-        urb_t * urbp;
+        struct urb * urbp;
         pauerchainelement_t acep;
         struct list_head *tmp;
 
@@ -499,7 +499,7 @@
 static void auerchain_unlink_all (pauerchain_t acp)
 {
 	unsigned long flags;
-        urb_t * urbp;
+        struct urb * urbp;
         pauerchainelement_t acep;
 
         dbg ("auerchain_unlink_all called");
@@ -605,7 +605,7 @@
 
 
 /* completion handler for synchronous chained URBs */
-static void auerchain_blocking_completion (urb_t *urb)
+static void auerchain_blocking_completion (struct urb *urb)
 {
 	pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context;
 	pchs->done = 1;
@@ -615,7 +615,7 @@
 
 
 /* Starts chained urb and waits for completion or timeout */
-static int auerchain_start_wait_urb (pauerchain_t acp, urb_t *urb, int timeout, int* actual_length)
+static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int timeout, int* actual_length)
 {
 	DECLARE_WAITQUEUE (wait, current);
 	auerchain_chs_t chs;
@@ -690,12 +690,12 @@
 			          __u16 value, __u16 index, void *data, __u16 size, int timeout)
 {
 	int ret;
-	devrequest *dr;
-	urb_t *urb;
+	struct usb_ctrlrequest *dr;
+	struct urb *urb;
         int length;
 
         dbg ("auerchain_control_msg");
-        dr = kmalloc (sizeof (devrequest), GFP_KERNEL);
+        dr = kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
 	if (!dr)
 		return -ENOMEM;
 	urb = usb_alloc_urb (0);
@@ -704,11 +704,11 @@
 		return -ENOMEM;
         }
 
-	dr->requesttype = requesttype;
-	dr->request = request;
-	dr->value  = cpu_to_le16 (value);
-	dr->index  = cpu_to_le16 (index);
-	dr->length = cpu_to_le16 (size);
+	dr->bRequestType = requesttype;
+	dr->bRequest = request;
+	dr->wValue  = cpu_to_le16 (value);
+	dr->wIndex  = cpu_to_le16 (index);
+	dr->wLength = cpu_to_le16 (size);
 
 	FILL_CONTROL_URB (urb, dev, pipe, (unsigned char*)dr, data, size,    /* build urb */
 		          (usb_complete_t)auerchain_blocking_completion,0);
@@ -799,7 +799,7 @@
                 INIT_LIST_HEAD (&bep->buff_list);
                 bep->bufp = (char *) kmalloc (bufsize, GFP_KERNEL);
                 if (!bep->bufp) goto bl_fail;
-                bep->dr = (devrequest *) kmalloc (sizeof (devrequest), GFP_KERNEL);
+                bep->dr = (struct usb_ctrlrequest *) kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
                 if (!bep->dr) goto bl_fail;
                 bep->urbp = usb_alloc_urb (0);
                 if (!bep->urbp) goto bl_fail;
@@ -874,7 +874,7 @@
 }
 
 /* Completion of asynchronous write block */
-static void auerchar_ctrlwrite_complete (urb_t * urb)
+static void auerchar_ctrlwrite_complete (struct urb * urb)
 {
 	pauerbuf_t bp = (pauerbuf_t) urb->context;
 	pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
@@ -887,7 +887,7 @@
 }
 
 /* Completion handler for dummy retry packet */
-static void auerswald_ctrlread_wretcomplete (urb_t * urb)
+static void auerswald_ctrlread_wretcomplete (struct urb * urb)
 {
         pauerbuf_t bp = (pauerbuf_t) urb->context;
         pauerswald_t cp;
@@ -907,13 +907,13 @@
 	}
 
 	/* fill the control message */
-	bp->dr->requesttype = AUT_RREQ;
-	bp->dr->request     = AUV_RBLOCK;
-	bp->dr->length      = bp->dr->value;	/* temporary stored */
-	bp->dr->value       = cpu_to_le16 (1);	/* Retry Flag */
+	bp->dr->bRequestType = AUT_RREQ;
+	bp->dr->bRequest     = AUV_RBLOCK;
+	bp->dr->wLength      = bp->dr->wValue;	/* temporary stored */
+	bp->dr->wValue       = cpu_to_le16 (1);	/* Retry Flag */
 	/* bp->dr->index    = channel id;          remains */
 	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0),
-                          (unsigned char*)bp->dr, bp->bufp, le16_to_cpu (bp->dr->length),
+                          (unsigned char*)bp->dr, bp->bufp, le16_to_cpu (bp->dr->wLength),
 		          (usb_complete_t)auerswald_ctrlread_complete,bp);
 
 	/* submit the control msg as next paket */
@@ -926,7 +926,7 @@
 }
 
 /* completion handler for receiving of control messages */
-static void auerswald_ctrlread_complete (urb_t * urb)
+static void auerswald_ctrlread_complete (struct urb * urb)
 {
         unsigned int  serviceid;
         pauerswald_t  cp;
@@ -955,11 +955,11 @@
 		bp->retries++;
 		dbg ("Retry count = %d", bp->retries);
 		/* send a long dummy control-write-message to allow device firmware to react */
-		bp->dr->requesttype = AUT_WREQ;
-		bp->dr->request     = AUV_DUMMY;
-		bp->dr->value       = bp->dr->length; /* temporary storage */
+		bp->dr->bRequestType = AUT_WREQ;
+		bp->dr->bRequest     = AUV_DUMMY;
+		bp->dr->wValue       = bp->dr->wLength; /* temporary storage */
 		// bp->dr->index    channel ID remains
-		bp->dr->length      = cpu_to_le16 (32); /* >= 8 bytes */
+		bp->dr->wLength      = cpu_to_le16 (32); /* >= 8 bytes */
 		FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0),
   			(unsigned char*)bp->dr, bp->bufp, 32,
 	   		(usb_complete_t)auerswald_ctrlread_wretcomplete,bp);
@@ -972,7 +972,7 @@
                		auerswald_ctrlread_wretcomplete (bp->urbp);
 		}
                 return;
-        }
+	} 
 
         /* get the actual bytecount (incl. headerbyte) */
         bp->len = urb->actual_length;
@@ -998,7 +998,7 @@
    messages from the USB device.
 */
 /* int completion handler. */
-static void auerswald_int_complete (urb_t * urb)
+static void auerswald_int_complete (struct urb * urb)
 {
         unsigned long flags;
         unsigned  int channelid;
@@ -1074,11 +1074,11 @@
         }
 
 	/* fill the control message */
-        bp->dr->requesttype = AUT_RREQ;
-	bp->dr->request     = AUV_RBLOCK;
-	bp->dr->value       = cpu_to_le16 (0);
-	bp->dr->index       = cpu_to_le16 (channelid | AUH_DIRECT | AUH_UNSPLIT);
-	bp->dr->length      = cpu_to_le16 (bytecount);
+        bp->dr->bRequestType = AUT_RREQ;
+	bp->dr->bRequest     = AUV_RBLOCK;
+	bp->dr->wValue       = cpu_to_le16 (0);
+	bp->dr->wIndex       = cpu_to_le16 (channelid | AUH_DIRECT | AUH_UNSPLIT);
+	bp->dr->wLength      = cpu_to_le16 (bytecount);
 	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0),
                           (unsigned char*)bp->dr, bp->bufp, bytecount,
 		          (usb_complete_t)auerswald_ctrlread_complete,bp);
@@ -1813,11 +1813,11 @@
 
 	/* Set the transfer Parameters */
 	bp->len = len+AUH_SIZE;
-        bp->dr->requesttype = AUT_WREQ;
-	bp->dr->request     = AUV_WBLOCK;
-	bp->dr->value       = cpu_to_le16 (0);
-	bp->dr->index       = cpu_to_le16 (ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT);
-	bp->dr->length      = cpu_to_le16 (len+AUH_SIZE);
+        bp->dr->bRequestType = AUT_WREQ;
+	bp->dr->bRequest     = AUV_WBLOCK;
+	bp->dr->wValue       = cpu_to_le16 (0);
+	bp->dr->wIndex       = cpu_to_le16 (ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT);
+	bp->dr->wLength      = cpu_to_le16 (len+AUH_SIZE);
 	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0),
                    (unsigned char*)bp->dr, bp->bufp, len+AUH_SIZE,
 		    auerchar_ctrlwrite_complete, bp);
diff -urN linux-2.4.20-pre1/drivers/usb/bluetooth.c linux-2.4.20-pre2/drivers/usb/bluetooth.c
--- linux-2.4.20-pre1/drivers/usb/bluetooth.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/usb/bluetooth.c	Mon Aug 12 16:34:16 2002
@@ -175,7 +175,7 @@
 	
 	__u8			control_out_bInterfaceNum;
 	struct urb *		control_urb_pool[NUM_CONTROL_URBS];
-	devrequest		dr[NUM_CONTROL_URBS];
+	struct usb_ctrlrequest	dr[NUM_CONTROL_URBS];
 
 	unsigned char *		interrupt_in_buffer;
 	struct urb *		interrupt_in_urb;
@@ -283,7 +283,7 @@
 static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, const unsigned char *buf, int len)
 {
 	struct urb *urb = NULL;
-	devrequest *dr = NULL;
+	struct usb_ctrlrequest *dr = NULL;
 	int i;
 	int status;
 
@@ -320,11 +320,11 @@
 	}
 	memcpy (urb->transfer_buffer, buf, len);
 
-	dr->requesttype = BLUETOOTH_CONTROL_REQUEST_TYPE;
-	dr->request = request;
-	dr->value = cpu_to_le16((u16) value);
-	dr->index = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum);
-	dr->length = cpu_to_le16((u16) len);
+	dr->bRequestType = BLUETOOTH_CONTROL_REQUEST_TYPE;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16((u16) value);
+	dr->wIndex = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum);
+	dr->wLength = cpu_to_le16((u16) len);
 	
 	FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
 			  (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth);
diff -urN linux-2.4.20-pre1/drivers/usb/catc.c linux-2.4.20-pre2/drivers/usb/catc.c
--- linux-2.4.20-pre1/drivers/usb/catc.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/catc.c	Mon Aug 12 16:34:16 2002
@@ -159,7 +159,7 @@
 	u8 rx_buf[RX_MAX_BURST * (PKT_SZ + 2)];
 	u8 irq_buf[2];
 	u8 ctrl_buf[64];
-	devrequest ctrl_dr;
+	struct usb_ctrlrequest ctrl_dr;
 
 	struct timer_list timer;
 	u8 stats_buf[8];
@@ -383,14 +383,14 @@
 	struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail;
 	struct usb_device *usbdev = catc->usbdev;
 	struct urb *urb = &catc->ctrl_urb;
-	devrequest *dr = &catc->ctrl_dr;
+	struct usb_ctrlrequest *dr = &catc->ctrl_dr;
 	int status;
 
-	dr->request = q->request;
-	dr->requesttype = 0x40 | q->dir;
-	dr->value = cpu_to_le16(q->value);
-	dr->index = cpu_to_le16(q->index);
-	dr->length = cpu_to_le16(q->len);
+	dr->bRequest = q->request;
+	dr->bRequestType = 0x40 | q->dir;
+	dr->wValue = cpu_to_le16(q->value);
+	dr->wIndex = cpu_to_le16(q->index);
+	dr->wLength = cpu_to_le16(q->len);
 
         urb->pipe = q->dir ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0);
 	urb->transfer_buffer_length = q->len;
diff -urN linux-2.4.20-pre1/drivers/usb/dabusb.c linux-2.4.20-pre2/drivers/usb/dabusb.c
--- linux-2.4.20-pre1/drivers/usb/dabusb.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/drivers/usb/dabusb.c	Mon Aug 12 16:34:16 2002
@@ -83,7 +83,7 @@
 }
 /*-------------------------------------------------------------------*/
 #ifdef DEBUG 
-static void dump_urb (purb_t purb)
+static void dump_urb (struct urb *purb)
 {
 	dbg("urb                   :%p", purb);
 	dbg("next                  :%p", purb->next);
@@ -167,7 +167,7 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-static void dabusb_iso_complete (purb_t purb)
+static void dabusb_iso_complete (struct urb *purb)
 {
 	pbuff_t b = purb->context;
 	pdabusb_t s = b->s;
@@ -482,7 +482,7 @@
 	int rem;
 	int cnt;
 	pbuff_t b;
-	purb_t purb = NULL;
+	struct urb *purb = NULL;
 
 	dbg("dabusb_read");
 
@@ -605,6 +605,7 @@
 	}
 	if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
 		err("set_interface failed");
+		up(&s->mutex);
 		return -EINVAL;
 	}
 	s->opened = 1;
diff -urN linux-2.4.20-pre1/drivers/usb/dabusb.h linux-2.4.20-pre2/drivers/usb/dabusb.h
--- linux-2.4.20-pre1/drivers/usb/dabusb.h	Tue Oct  3 09:24:40 2000
+++ linux-2.4.20-pre2/drivers/usb/dabusb.h	Mon Aug 12 16:34:16 2002
@@ -38,7 +38,7 @@
 typedef struct 
 {
 	pdabusb_t s;
-	purb_t purb;
+	struct urb *purb;
 	struct list_head buff_list;
 } buff_t,*pbuff_t;
 
diff -urN linux-2.4.20-pre1/drivers/usb/devio.c linux-2.4.20-pre2/drivers/usb/devio.c
--- linux-2.4.20-pre1/drivers/usb/devio.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/devio.c	Mon Aug 12 16:34:16 2002
@@ -52,7 +52,7 @@
 	unsigned int signr;
 	void *userbuffer;
         void *userurb;
-        urb_t urb;
+        struct urb urb;
 };
 
 static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@@ -169,7 +169,7 @@
 
 static struct async *alloc_async(unsigned int numisoframes)
 {
-        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t);
+        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct iso_packet_descriptor);
         struct async *as = kmalloc(assize, GFP_KERNEL);
         if (!as)
                 return NULL;
@@ -245,7 +245,7 @@
         return NULL;
 }
 
-static void async_completed(purb_t urb)
+static void async_completed(struct urb *urb)
 {
         struct async *as = (struct async *)urb->context;
         struct dev_state *ps = as->ps;
@@ -772,7 +772,7 @@
 	struct usbdevfs_iso_packet_desc *isopkt = NULL;
 	struct usb_endpoint_descriptor *ep_desc;
 	struct async *as;
-	devrequest *dr = NULL;
+	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret;
 
@@ -802,23 +802,23 @@
 		/* min 8 byte setup packet, max arbitrary */
 		if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE)
 			return -EINVAL;
-		if (!(dr = kmalloc(sizeof(devrequest), GFP_KERNEL)))
+		if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
 			return -ENOMEM;
 		if (copy_from_user(dr, (unsigned char*)uurb.buffer, 8)) {
 			kfree(dr);
 			return -EFAULT;
 		}
-		if (uurb.buffer_length < (le16_to_cpup(&dr->length) + 8)) {
+		if (uurb.buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
 			kfree(dr);
 			return -EINVAL;
 		}
-		if ((ret = check_ctrlrecip(ps, dr->requesttype, le16_to_cpup(&dr->index)))) {
+		if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) {
 			kfree(dr);
 			return ret;
 		}
-		uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->requesttype & USB_ENDPOINT_DIR_MASK);
+		uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
 		uurb.number_of_packets = 0;
-		uurb.buffer_length = le16_to_cpup(&dr->length);
+		uurb.buffer_length = le16_to_cpup(&dr->wLength);
 		uurb.buffer += 8;
 		if (!access_ok((uurb.endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) {
 			kfree(dr);
diff -urN linux-2.4.20-pre1/drivers/usb/hc_simple.c linux-2.4.20-pre2/drivers/usb/hc_simple.c
--- linux-2.4.20-pre1/drivers/usb/hc_simple.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/hc_simple.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,1072 @@
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * simple generic USB HCD frontend Version 0.9.5 (10/28/2001)
+ * for embedded HCs (SL811HS)
+ * 
+ * USB URB handling, hci_ hcs_
+ * URB queueing, qu_
+ * Transfer scheduling, sh_
+ * 
+ *
+ *-------------------------------------------------------------------------*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ *
+ *-------------------------------------------------------------------------*/
+
+/* main lock for urb access */
+static spinlock_t usb_urb_lock = SPIN_LOCK_UNLOCKED;
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/* URB HCD API function layer
+ * * * */
+
+/***************************************************************************
+ * Function Name : hcs_urb_queue
+ *
+ * This function initializes the urb status and length before queueing the 
+ * urb. 
+ *
+ * Input:  hci = data structure for the host controller
+ *         urb = USB request block data structure 
+ *
+ * Return: 0 
+ **************************************************************************/
+static inline int hcs_urb_queue (hci_t * hci, struct urb * urb)
+{
+	int i;
+
+	DBGFUNC ("enter hcs_urb_queue\n");
+	if (usb_pipeisoc (urb->pipe)) {
+		DBGVERBOSE ("hcs_urb_queue: isoc pipe\n");
+		for (i = 0; i < urb->number_of_packets; i++) {
+			urb->iso_frame_desc[i].actual_length = 0;
+			urb->iso_frame_desc[i].status = -EXDEV;
+		}
+
+		/* urb->next hack : 1 .. resub, 0 .. single shot */
+		/* urb->interval = urb->next ? 1 : 0; */
+	}
+
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	urb->error_count = 0;
+
+	if (usb_pipecontrol (urb->pipe))
+		hc_flush_data_cache (hci, urb->setup_packet, 8);
+	if (usb_pipeout (urb->pipe))
+		hc_flush_data_cache (hci, urb->transfer_buffer,
+				     urb->transfer_buffer_length);
+
+	qu_queue_urb (hci, urb);
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hcs_return_urb
+ *
+ * This function the return path of URB back to the USB core. It calls the
+ * the urb complete function if exist, and also handles the resubmition of
+ * interrupt URBs.
+ *
+ * Input:  hci = data structure for the host controller
+ *         urb = USB request block data structure 
+ *         resub_ok = resubmit flag: 1 = submit urb again, 0 = not submit 
+ *
+ * Return: 0 
+ **************************************************************************/
+static int hcs_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct usb_device *dev = urb->dev;
+	int resubmit = 0;
+
+	DBGFUNC ("enter hcs_return_urb, urb pointer = 0x%x, "
+		 "transferbuffer point = 0x%x, "
+		 " setup packet pointer = 0x%x, context pointer = 0x%x \n",
+		 (__u32 *) urb, (__u32 *) urb->transfer_buffer,
+		 (__u32 *) urb->setup_packet, (__u32 *) urb->context);
+	if (urb_debug)
+		urb_print (urb, "RET", usb_pipeout (urb->pipe));
+
+	resubmit = urb->interval && resub_ok;
+
+	urb->dev = urb->hcpriv = NULL;
+
+	if (urb->complete) {
+		urb->complete (urb);	/* call complete */
+	}
+
+	if (resubmit) {
+		/* requeue the URB */
+		urb->dev = dev;
+		hcs_urb_queue (hci, urb);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_submit_urb
+ *
+ * This function is called by the USB core API when an URB is available to
+ * process.  This function does the following
+ *
+ * 1) Check the validity of the URB
+ * 2) Parse the device number from the URB
+ * 3) Pass the URB to the root hub routine if its intended for the hub, else
+ *    queue the urb for the attached device. 
+ *
+ * Input: urb = USB request block data structure 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_submit_urb (struct urb * urb)
+{
+	hci_t *hci;
+	unsigned int pipe = urb->pipe;
+	unsigned long flags;
+	int ret;
+
+	DBGFUNC ("enter hci_submit_urb, pipe = 0x%x\n", urb->pipe);
+	if (!urb->dev || !urb->dev->bus || urb->hcpriv)
+		return -EINVAL;
+
+	if (usb_endpoint_halted
+	    (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) {
+		printk ("hci_submit_urb: endpoint_halted\n");
+		return -EPIPE;
+	}
+	hci = (hci_t *) urb->dev->bus->hcpriv;
+
+	/* a request to the virtual root hub */
+
+	if (usb_pipedevice (pipe) == hci->rh.devnum) {
+		if (urb_debug > 1)
+			urb_print (urb, "SUB-RH", usb_pipein (pipe));
+
+		return rh_submit_urb (urb);
+	}
+
+	/* queue the URB to its endpoint-queue */
+
+	spin_lock_irqsave (&usb_urb_lock, flags);
+	ret = hcs_urb_queue (hci, urb);
+	if (ret != 0) {
+		/* error on return */
+		DBGERR
+		    ("hci_submit_urb: return err, ret = 0x%x, urb->status = 0x%x\n",
+		     ret, urb->status);
+	}
+
+	spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+	return ret;
+
+}
+
+/***************************************************************************
+ * Function Name : hci_unlink_urb
+ *
+ * This function mark the URB to unlink
+ *
+ * Input: urb = USB request block data structure 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_unlink_urb (struct urb * urb)
+{
+	unsigned long flags;
+	hci_t *hci;
+	DECLARE_WAITQUEUE (wait, current);
+	void *comp = NULL;
+
+	DBGFUNC ("enter hci_unlink_urb\n");
+
+	if (!urb)		/* just to be sure */
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	hci = (hci_t *) urb->dev->bus->hcpriv;
+
+	/* a request to the virtual root hub */
+	if (usb_pipedevice (urb->pipe) == hci->rh.devnum) {
+		return rh_unlink_urb (urb);
+	}
+
+	if (urb_debug)
+		urb_print (urb, "UNLINK", 1);
+
+	spin_lock_irqsave (&usb_urb_lock, flags);
+
+	if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
+		/* URB active? */
+
+		if (urb->
+		    transfer_flags & (USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED)) {
+			/* asynchron with callback */
+
+			list_del (&urb->urb_list);	/* relink the urb to the del list */
+			list_add (&urb->urb_list, &hci->del_list);
+			spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+		} else {
+			/* synchron without callback */
+
+			add_wait_queue (&hci->waitq, &wait);
+
+			set_current_state (TASK_UNINTERRUPTIBLE);
+			comp = urb->complete;
+			urb->complete = NULL;
+
+			list_del (&urb->urb_list);	/* relink the urb to the del list */
+			list_add (&urb->urb_list, &hci->del_list);
+
+			spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+			schedule_timeout (HZ / 50);
+
+			if (!list_empty (&urb->urb_list))
+				list_del (&urb->urb_list);
+
+			urb->complete = comp;
+			urb->hcpriv = NULL;
+			remove_wait_queue (&hci->waitq, &wait);
+		}
+	} else {
+		/* hcd does not own URB but we keep the driver happy anyway */
+		spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+		if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
+			urb->status = -ENOENT;
+			urb->actual_length = 0;
+			urb->complete (urb);
+			urb->status = 0;
+		} else {
+			urb->status = -ENOENT;
+		}
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_alloc_dev
+ *
+ * This function allocates private data space for the usb device and 
+ * initialize the endpoint descriptor heads.
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_alloc_dev (struct usb_device *usb_dev)
+{
+	struct hci_device *dev;
+	int i;
+
+	DBGFUNC ("enter hci_alloc_dev\n");
+	dev = kmalloc (sizeof (*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	memset (dev, 0, sizeof (*dev));
+
+	for (i = 0; i < 32; i++) {
+		INIT_LIST_HEAD (&(dev->ed[i].urb_queue));
+		dev->ed[i].pipe_head = NULL;
+	}
+
+	usb_dev->hcpriv = dev;
+
+	DBGVERBOSE ("USB HC dev alloc %d bytes\n", sizeof (*dev));
+
+	return 0;
+
+}
+
+/***************************************************************************
+ * Function Name : hci_free_dev
+ *
+ * This function de-allocates private data space for the usb devic
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int hci_free_dev (struct usb_device *usb_dev)
+{
+	DBGFUNC ("enter hci_free_dev\n");
+
+	if (usb_dev->hcpriv)
+		kfree (usb_dev->hcpriv);
+
+	usb_dev->hcpriv = NULL;
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_get_current_frame_number
+ *
+ * This function get the current USB frame number
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: frame number  
+ **************************************************************************/
+static int hci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	hci_t *hci = usb_dev->bus->hcpriv;
+	DBGFUNC ("enter hci_get_current_frame_number, frame = 0x%x \r\n",
+		 hci->frame_number);
+
+	return (hci->frame_number);
+}
+
+/***************************************************************************
+ * List of all io-functions 
+ **************************************************************************/
+
+static struct usb_operations hci_device_operations = {
+	allocate:		hci_alloc_dev,
+	deallocate:		hci_free_dev,
+	get_frame_number:	hci_get_current_frame_number,
+	submit_urb:		hci_submit_urb,
+	unlink_urb:		hci_unlink_urb,
+};
+
+/***************************************************************************
+ * URB queueing:
+ * 
+ * For each type of transfer (INTR, BULK, ISO, CTRL) there is a list of 
+ * active URBs.
+ * (hci->intr_list, hci->bulk_list, hci->iso_list, hci->ctrl_list)
+ * For every endpoint the head URB of the queued URBs is linked to one of 
+ * those lists.
+ * 
+ * The rest of the queued URBs of an endpoint are linked into a 
+ * private URB list for each endpoint. (hci_dev->ed [endpoint_io].urb_queue)
+ * hci_dev->ed [endpoint_io].pipe_head .. points to the head URB which is 
+ * in one of the active URB lists.
+ * 
+ * The index of an endpoint consists of its number and its direction.
+ * 
+ * The state of an intr and iso URB is 0. 
+ * For ctrl URBs the states are US_CTRL_SETUP, US_CTRL_DATA, US_CTRL_ACK
+ * Bulk URBs states are US_BULK and US_BULK0 (with 0-len packet)
+ * 
+ **************************************************************************/
+
+/***************************************************************************
+ * Function Name : qu_urb_timeout
+ *
+ * This function is called when the URB timeout. The function unlinks the 
+ * URB. 
+ *
+ * Input: lurb: URB 
+ *
+ * Return: none  
+ **************************************************************************/
+#ifdef HC_URB_TIMEOUT
+static void qu_urb_timeout (unsigned long lurb)
+{
+	struct urb *urb = (struct urb *) lurb;
+
+	DBGFUNC ("enter qu_urb_timeout\n");
+	urb->transfer_flags |= USB_TIMEOUT_KILLED;
+	hci_unlink_urb (urb);
+}
+#endif
+
+/***************************************************************************
+ * Function Name : qu_pipeindex
+ *
+ * This function gets the index of the pipe.   
+ *
+ * Input: pipe: the urb pipe 
+ *
+ * Return: index  
+ **************************************************************************/
+static inline int qu_pipeindex (__u32 pipe)
+{
+	DBGFUNC ("enter qu_pipeindex\n");
+	return (usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe) ? 0 : usb_pipeout (pipe));
+}
+
+/***************************************************************************
+ * Function Name : qu_seturbstate
+ *
+ * This function set the state of the URB.  
+ * 
+ * control pipe: 3 states -- Setup, data, status
+ * interrupt and bulk pipe: 1 state -- data    
+ *
+ * Input: urb = USB request block data structure 
+ *        state = the urb state
+ *
+ * Return: none  
+ **************************************************************************/
+static inline void qu_seturbstate (struct urb * urb, int state)
+{
+	DBGFUNC ("enter qu_seturbstate\n");
+	urb->pipe &= ~0x1f;
+	urb->pipe |= state & 0x1f;
+}
+
+/***************************************************************************
+ * Function Name : qu_urbstate
+ *
+ * This function get the current state of the URB.  
+ * 
+ * Input: urb = USB request block data structure 
+ *
+ * Return: none  
+ **************************************************************************/
+static inline int qu_urbstate (struct urb * urb)
+{
+
+	DBGFUNC ("enter qu_urbstate\n");
+
+	return urb->pipe & 0x1f;
+}
+
+/***************************************************************************
+ * Function Name : qu_queue_active_urb
+ *
+ * This function adds the urb to the appropriate active urb list and set
+ * the urb state.
+ * 
+ * There are four active lists: isochoronous list, interrupt list, 
+ * control list, and bulk list.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        ed = endpoint descriptor
+ *
+ * Return: none  
+ **************************************************************************/
+static inline void qu_queue_active_urb (hci_t * hci, struct urb * urb, epd_t * ed)
+{
+	int urb_state = 0;
+	DBGFUNC ("enter qu_queue_active_urb\n");
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+		list_add (&urb->urb_list, &hci->ctrl_list);
+		urb_state = US_CTRL_SETUP;
+		break;
+
+	case PIPE_BULK:
+		list_add (&urb->urb_list, &hci->bulk_list);
+		if ((urb->transfer_flags & USB_ZERO_PACKET)
+		    && urb->transfer_buffer_length > 0
+		    &&
+		    ((urb->transfer_buffer_length %
+		      usb_maxpacket (urb->dev, urb->pipe,
+				     usb_pipeout (urb->pipe))) == 0)) {
+			urb_state = US_BULK0;
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		urb->start_frame = hci->frame_number;
+		list_add (&urb->urb_list, &hci->intr_list);
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		list_add (&urb->urb_list, &hci->iso_list);
+		break;
+	}
+
+#ifdef HC_URB_TIMEOUT
+	if (urb->timeout) {
+		ed->timeout.data = (unsigned long) urb;
+		ed->timeout.expires = urb->timeout + jiffies;
+		ed->timeout.function = qu_urb_timeout;
+		add_timer (&ed->timeout);
+	}
+#endif
+
+	qu_seturbstate (urb, urb_state);
+}
+
+/***************************************************************************
+ * Function Name : qu_queue_urb
+ *
+ * This function adds the urb to the endpoint descriptor list 
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *
+ * Return: none  
+ **************************************************************************/
+static int qu_queue_urb (hci_t * hci, struct urb * urb)
+{
+	struct hci_device *hci_dev = usb_to_hci (urb->dev);
+	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
+
+	DBGFUNC ("Enter qu_queue_urb\n");
+
+	/* for ISOC transfers calculate start frame index */
+
+	if (usb_pipeisoc (urb->pipe) && urb->transfer_flags & USB_ISO_ASAP) {
+		urb->start_frame = ((ed->pipe_head) ? (ed->last_iso + 1) : hci_get_current_frame_number (urb-> dev) + 1) & 0xffff;
+	}
+
+	if (ed->pipe_head) {
+		__list_add (&urb->urb_list, ed->urb_queue.prev,
+			    &(ed->urb_queue));
+	} else {
+		ed->pipe_head = urb;
+		qu_queue_active_urb (hci, urb, ed);
+		if (++hci->active_urbs == 1)
+			hc_start_int (hci);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : qu_next_urb
+ *
+ * This function removes the URB from the queue and add the next URB to 
+ * active list. 
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        resub_ok = resubmit flag
+ *
+ * Return: pointer to the next urb  
+ **************************************************************************/
+static struct urb *qu_next_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct hci_device *hci_dev = usb_to_hci (urb->dev);
+	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
+
+	DBGFUNC ("enter qu_next_urb\n");
+	list_del (&urb->urb_list);
+	INIT_LIST_HEAD (&urb->urb_list);
+	if (ed->pipe_head == urb) {
+
+#ifdef HC_URB_TIMEOUT
+		if (urb->timeout)
+			del_timer (&ed->timeout);
+#endif
+
+		if (!--hci->active_urbs)
+			hc_stop_int (hci);
+
+		if (!list_empty (&ed->urb_queue)) {
+			urb = list_entry (ed->urb_queue.next, struct urb, urb_list);
+			list_del (&urb->urb_list);
+			INIT_LIST_HEAD (&urb->urb_list);
+			ed->pipe_head = urb;
+			qu_queue_active_urb (hci, urb, ed);
+		} else {
+			ed->pipe_head = NULL;
+			urb = NULL;
+		}
+	}
+	return urb;
+}
+
+/***************************************************************************
+ * Function Name : qu_return_urb
+ *
+ * This function is part of the return path.   
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        resub_ok = resubmit flag
+ *
+ * Return: pointer to the next urb  
+ **************************************************************************/
+static struct urb *qu_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct urb *next_urb;
+
+	DBGFUNC ("enter qu_return_rub\n");
+	next_urb = qu_next_urb (hci, urb, resub_ok);
+	hcs_return_urb (hci, urb, resub_ok);
+	return next_urb;
+}
+
+/***************************************************************************
+ * Function Name : sh_scan_iso_urb_list
+ *
+ * This function goes throught the isochronous urb list and schedule the 
+ * the transfer.   
+ *
+ * Note: This function has not tested yet
+ * 
+ * Input: hci = data structure for the host controller 
+ *        list_lh = pointer to the isochronous list 
+ *        frame_number = the frame number 
+ *
+ * Return: 0 = unsuccessful; 1 = successful  
+ **************************************************************************/
+static int sh_scan_iso_urb_list (hci_t * hci, struct list_head *list_lh,
+				 int frame_number)
+{
+	struct list_head *lh = list_lh->next;
+	struct urb *urb;
+
+	DBGFUNC ("enter sh_scan_iso_urb_list\n");
+	hci->td_array->len = 0;
+
+	while (lh != list_lh) {
+		urb = list_entry (lh, struct urb, urb_list);
+		lh = lh->next;
+		if (((frame_number - urb->start_frame) & 0x7ff) <
+		    urb->number_of_packets) {
+			if (!sh_add_packet (hci, urb)) {
+				return 0;
+			} else {
+				if (((frame_number -
+				      urb->start_frame) & 0x7ff) > 0x400) {
+					if (qu_urbstate (urb) > 0)
+						urb = qu_return_urb (hci, urb, 1);
+					else
+						urb = qu_next_urb (hci, urb, 1);
+
+					if (lh == list_lh && urb)
+						lh = &urb->urb_list;
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+/***************************************************************************
+ * Function Name : sh_scan_urb_list
+ *
+ * This function goes through the urb list and schedule the 
+ * the transaction.   
+ * 
+ * Input: hci = data structure for the host controller 
+ *        list_lh = pointer to the isochronous list 
+ *
+ * Return: 0 = unsuccessful; 1 = successful  
+ **************************************************************************/
+static int sh_scan_urb_list (hci_t * hci, struct list_head *list_lh)
+{
+	struct list_head *lh = NULL;
+	struct urb *urb;
+
+	if (list_lh == NULL) {
+		DBGERR ("sh_scan_urb_list: error, list_lh == NULL\n");
+	}
+
+	DBGFUNC ("enter sh_scan_urb_list: frame# \n");
+
+	list_for_each (lh, list_lh) {
+		urb = list_entry (lh, struct urb, urb_list);
+		if (urb == NULL)
+			return 1;
+		if (!usb_pipeint (urb->pipe)
+		    || (((hci->frame_number - urb->start_frame)
+			 & 0x7ff) >= urb->interval)) {
+			DBGVERBOSE ("sh_scan_urb_list !INT: %d fr_no: %d int: %d pint: %d\n",
+				    urb->start_frame, hci->frame_number, urb->interval,
+				    usb_pipeint (urb->pipe));
+			if (!sh_add_packet (hci, urb)) {
+				return 0;
+			} else {
+				DBGVERBOSE ("INT: start: %d fr_no: %d int: %d pint: %d\n",
+					    urb->start_frame, hci->frame_number,
+					    urb->interval, usb_pipeint (urb->pipe));
+				urb->start_frame = hci->frame_number;
+				return 0;
+
+			}
+		}
+	}
+	return 1;
+}
+
+/***************************************************************************
+ * Function Name : sh_shedule_trans
+ *
+ * This function schedule the USB transaction.
+ * This function will process the endpoint in the following order: 
+ * interrupt, control, and bulk.    
+ * 
+ * Input: hci = data structure for the host controller 
+ *        isSOF = flag indicate if Start Of Frame has occurred 
+ *
+ * Return: 0   
+ **************************************************************************/
+static int sh_schedule_trans (hci_t * hci, int isSOF)
+{
+	int units_left = 1;
+	struct list_head *lh;
+
+	if (hci == NULL) {
+		DBGERR ("sh_schedule_trans: hci == NULL\n");
+		return 0;
+	}
+	if (hci->td_array == NULL) {
+		DBGERR ("sh_schedule_trans: hci->td_array == NULL\n");
+		return 0;
+	}
+
+	if (hci->td_array->len != 0) {
+		DBGERR ("ERROR: schedule, hci->td_array->len = 0x%x, s/b: 0\n",
+			hci->td_array->len);
+	}
+
+	/* schedule the next available interrupt transfer or the next
+	 * stage of the interrupt transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->intr_list)) {
+		units_left = sh_scan_urb_list (hci, &hci->intr_list);
+	}
+
+	/* schedule the next available control transfer or the next
+	 * stage of the control transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->ctrl_list) && units_left > 0) {
+		units_left = sh_scan_urb_list (hci, &hci->ctrl_list);
+	}
+
+	/* schedule the next available bulk transfer or the next
+	 * stage of the bulk transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->bulk_list) && units_left > 0) {
+		sh_scan_urb_list (hci, &hci->bulk_list);
+
+		/* be fair to each BULK URB (move list head around) 
+		 * only when the new SOF happens */
+
+		lh = hci->bulk_list.next;
+		list_del (&hci->bulk_list);
+		list_add (&hci->bulk_list, lh);
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : sh_add_packet
+ *
+ * This function forms the packet and transmit the packet. This function
+ * will handle all endpoint type: isochoronus, interrupt, control, and 
+ * bulk.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *
+ * Return: 0 = unsucessful; 1 = successful   
+ **************************************************************************/
+static int sh_add_packet (hci_t * hci, struct urb * urb)
+{
+	__u8 *data = NULL;
+	int len = 0;
+	int toggle = 0;
+	int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+	int endpoint = usb_pipeendpoint (urb->pipe);
+	int address = usb_pipedevice (urb->pipe);
+	int slow = (((urb->pipe) >> 26) & 1);
+	int out = usb_pipeout (urb->pipe);
+	int pid = 0;
+	int ret;
+	int i = 0;
+	int iso = 0;
+
+	DBGFUNC ("enter sh_add_packet\n");
+	if (maxps == 0)
+		maxps = 8;
+
+	/* calculate len, toggle bit and add the transaction */
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_ISOCHRONOUS:
+		pid = out ? PID_OUT : PID_IN;
+		iso = 1;
+		i = hci->frame_number - urb->start_frame;
+		data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		len = urb->iso_frame_desc[i].length;
+		break;
+
+	case PIPE_BULK:	/* BULK and BULK0 */
+	case PIPE_INTERRUPT:
+		pid = out ? PID_OUT : PID_IN;
+		len = urb->transfer_buffer_length - urb->actual_length;
+		data = urb->transfer_buffer + urb->actual_length;
+		toggle = usb_gettoggle (urb->dev, endpoint, out);
+		break;
+
+	case PIPE_CONTROL:
+		switch (qu_urbstate (urb)) {
+		case US_CTRL_SETUP:
+			len = 8;
+			pid = PID_SETUP;
+			data = urb->setup_packet;
+			toggle = 0;
+			break;
+
+		case US_CTRL_DATA:
+			if (!hci->last_packet_nak) {
+				/* The last packet received is not a nak:
+				 * reset the nak count
+				 */
+
+				hci->nakCnt = 0;
+			}
+			if (urb->transfer_buffer_length != 0) {
+				pid = out ? PID_OUT : PID_IN;
+				len = urb->transfer_buffer_length - urb->actual_length;
+				data = urb->transfer_buffer + urb->actual_length;
+				toggle = (urb->actual_length & maxps) ? 0 : 1;
+				usb_settoggle (urb->dev,
+					       usb_pipeendpoint (urb->pipe),
+					       usb_pipeout (urb->pipe), toggle);
+				break;
+			} else {
+				/* correct state and fall through */
+				qu_seturbstate (urb, US_CTRL_ACK);
+			}
+
+		case US_CTRL_ACK:
+			len = 0;
+
+			/* reply in opposite direction */
+			pid = !out ? PID_OUT : PID_IN;
+			toggle = 1;
+			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+				       usb_pipeout (urb->pipe), toggle);
+			break;
+		}
+	}
+
+	ret =
+	    hc_add_trans (hci, len, data, toggle, maxps, slow, endpoint,
+			  address, pid, iso, qu_urbstate (urb));
+
+	DBGVERBOSE ("transfer_pa: addr:%d ep:%d pid:%x tog:%x iso:%x sl:%x "
+		    "max:%d\n len:%d ret:%d data:%p left:%d\n",
+		    address, endpoint, pid, toggle, iso, slow,
+		    maxps, len, ret, data, hci->hp.units_left);
+
+	if (ret >= 0) {
+		hci->td_array->td[hci->td_array->len].urb = urb;
+		hci->td_array->td[hci->td_array->len].len = ret;
+		hci->td_array->td[hci->td_array->len].iso_index = i;
+		hci->td_array->len++;
+		hci->active_trans = 1;
+		return 1;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : cc_to_error
+ *
+ * This function maps the SL811HS hardware error code to the linux USB error
+ * code.
+ * 
+ * Input: cc = hardware error code 
+ *
+ * Return: USB error code   
+ **************************************************************************/
+static int cc_to_error (int cc)
+{
+	int errCode = 0;
+	if (cc & SL11H_STATMASK_ERROR) {
+		errCode |= -EILSEQ;
+	} else if (cc & SL11H_STATMASK_OVF) {
+		errCode |= -EOVERFLOW;
+	} else if (cc & SL11H_STATMASK_STALL) {
+		errCode |= -EPIPE;
+	}
+	return errCode;
+}
+
+/***************************************************************************
+ * Function Name : sh_done_list
+ *
+ * This function process the packet when it has done finish transfer.
+ * 
+ * 1) It handles hardware error
+ * 2) It updates the URB state
+ * 3) If the USB transaction is complete, it start the return stack path.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        isExcessNak = flag tells if there excess NAK condition occurred 
+ *
+ * Return:  urb_state or -1 if the transaction has complete   
+ **************************************************************************/
+static int sh_done_list (hci_t * hci, int *isExcessNak)
+{
+	int actbytes = 0;
+	int active = 0;
+	void *data = NULL;
+	int cc;
+	int maxps;
+	int toggle;
+	struct urb *urb;
+	int urb_state = 0;
+	int ret = 1;		/* -1 parse abbort, 1 parse ok, 0 last element */
+	int trans = 0;
+	int len;
+	int iso_index = 0;
+	int out;
+	int pid = 0;
+	int debugLen = 0;
+
+	*isExcessNak = 0;
+
+	DBGFUNC ("enter sh_done_list: td_array->len = 0x%x\n",
+		 hci->td_array->len);
+
+	debugLen = hci->td_array->len;
+	if (debugLen > 1)
+		DBGERR ("sh_done_list: td_array->len = 0x%x > 1\n",
+			hci->td_array->len);
+
+	for (trans = 0; ret && trans < hci->td_array->len && trans < MAX_TRANS;
+	     trans++) {
+		urb = hci->td_array->td[trans].urb;
+		len = hci->td_array->td[trans].len;
+		out = usb_pipeout (urb->pipe);
+
+		if (usb_pipeisoc (urb->pipe)) {
+			iso_index = hci->td_array->td[trans].iso_index;
+			data = urb->transfer_buffer + urb->iso_frame_desc[iso_index].offset;
+			toggle = 0;
+		} else {
+			data = urb->transfer_buffer + urb->actual_length;
+			toggle = usb_gettoggle (urb->dev,
+						usb_pipeendpoint (urb->pipe),
+						usb_pipeout (urb->pipe));
+
+		}
+		urb_state = qu_urbstate (urb);
+		pid = out ? PID_OUT : PID_IN;
+		ret = hc_parse_trans (hci, &actbytes, data, &cc, &toggle, len,
+				      pid, urb_state);
+		maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+
+		if (maxps == 0)
+			maxps = 8;
+
+		active = (urb_state != US_CTRL_SETUP) && (actbytes && !(actbytes & (maxps - 1)));
+
+		/* If the transfer is not bulk in, then it is necessary to get all
+		 * data specify by the urb->transfer_len.
+		 */
+
+		if (!(usb_pipebulk (urb->pipe) && usb_pipein (urb->pipe)))
+			active = active && (urb->transfer_buffer_length != urb->actual_length + actbytes);
+
+		if (urb->transfer_buffer_length == urb->actual_length + actbytes)
+			active = 0;
+
+		if ((cc &
+		     (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT |
+		      SL11H_STATMASK_OVF | SL11H_STATMASK_STALL))
+		    && !(cc & SL11H_STATMASK_NAK)) {
+			if (++urb->error_count > 3) {
+				DBGERR ("done_list: excessive error: errcount = 0x%x, cc = 0x%x\n",
+					urb->error_count, cc);
+				urb_state = 0;
+				active = 0;
+			} else {
+				DBGERR ("done_list: packet err, cc = 0x%x, "
+					" urb->length = 0x%x, actual_len = 0x%x,"
+					" urb_state =0x%x\n",
+					cc, urb->transfer_buffer_length,
+					urb->actual_length, urb_state);
+//			if (cc & SL11H_STATMASK_STALL) {
+				/* The USB function is STALLED on a control pipe (0), 
+				 * then it needs to send the SETUP command again to 
+				 * clear the STALL condition
+				 */
+
+//				if (usb_pipeendpoint (urb->pipe) == 0) {
+//					urb_state = 2;  
+//					active = 0;
+//				}
+//			} else   
+				active = 1;
+			}
+		} else {
+			if (cc & SL11H_STATMASK_NAK) {
+				if (hci->nakCnt < 0x10000) {
+					hci->nakCnt++;
+					hci->last_packet_nak = 1;
+					active = 1;
+					*isExcessNak = 0;
+				} else {
+					DBGERR ("done_list: nak count exceed limit\n");
+					active = 0;
+					*isExcessNak = 1;
+					hci->nakCnt = 0;
+				}
+			} else {
+				hci->nakCnt = 0;
+				hci->last_packet_nak = 0;
+			}
+
+			if (urb_state != US_CTRL_SETUP) {
+				/* no error */
+				urb->actual_length += actbytes;
+				usb_settoggle (urb->dev,
+					       usb_pipeendpoint (urb->pipe),
+					       usb_pipeout (urb->pipe), toggle);
+			}
+			if (usb_pipeisoc (urb->pipe)) {
+				urb->iso_frame_desc[iso_index].actual_length = actbytes;
+				urb->iso_frame_desc[iso_index].status = cc_to_error (cc);
+				active = (iso_index < urb->number_of_packets);
+			}
+		}
+		if (!active) {
+			if (!urb_state) {
+				urb->status = cc_to_error (cc);
+				if (urb->status) {
+					DBGERR ("error on received packet: urb->status = 0x%x\n",
+						urb->status);
+				}
+				hci->td_array->len = 0;
+				qu_return_urb (hci, urb, 1);
+				return -1;
+			} else {
+				/* We do not want to decrement the urb_state if exceeded nak,
+				 * because we need to finish the data stage of the control 
+				 * packet 
+				 */
+
+				if (!(*isExcessNak))
+					urb_state--;
+				qu_seturbstate (urb, urb_state);
+			}
+		}
+	}
+
+	if (urb_state < 0)
+		DBGERR ("ERROR: done_list, urb_state = %d, suppose > 0\n",
+			urb_state);
+	if (debugLen != hci->td_array->len) {
+		DBGERR ("ERROR: done_list, debugLen!= td_array->len,"
+			"debugLen = 0x%x, hci->td_array->len = 0x%x\n",
+			debugLen, hci->td_array->len);
+	}
+
+	hci->td_array->len = 0;
+
+	return urb_state;
+}
diff -urN linux-2.4.20-pre1/drivers/usb/hc_simple.h linux-2.4.20-pre2/drivers/usb/hc_simple.h
--- linux-2.4.20-pre1/drivers/usb/hc_simple.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/hc_simple.h	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,231 @@
+/*-------------------------------------------------------------------------*/
+/* list of all controllers using this driver 
+ * */
+
+static LIST_HEAD (hci_hcd_list);
+
+/* URB states (urb_state) */
+/* isoc, interrupt single state */
+
+/* bulk transfer main state and 0-length packet */
+#define US_BULK		0
+#define US_BULK0	1
+/* three setup states */
+#define US_CTRL_SETUP	2
+#define US_CTRL_DATA	1
+#define US_CTRL_ACK	0
+
+/*-------------------------------------------------------------------------*/
+/* HC private part of a device descriptor
+ * */
+
+#define NUM_EDS 32
+
+typedef struct epd {
+	struct urb *pipe_head;
+	struct list_head urb_queue;
+//	int urb_state;
+	struct timer_list timeout;
+	int last_iso;		/* timestamp of last queued ISOC transfer */
+
+} epd_t;
+
+struct hci_device {
+	epd_t ed[NUM_EDS];
+};
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root HUB 
+ */
+
+#define usb_to_hci(usb)	((struct hci_device *)(usb)->hcpriv)
+
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *urb;		/* interrupt URB of root hub */
+	int send;		/* active flag */
+	int interval;		/* intervall of roothub interrupt transfers */
+	struct timer_list rh_int_timer;	/* intervall timer for rh interrupt EP */
+};
+
+#if 1
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h and USB spec) */
+
+/* destination of request */
+#define RH_INTERFACE		0x01
+#define RH_ENDPOINT		0x02
+#define RH_OTHER		0x03
+
+#define RH_CLASS		0x20
+#define RH_VENDOR		0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	0x00
+#define RH_PORT_ENABLE		0x01
+#define RH_PORT_SUSPEND		0x02
+#define RH_PORT_OVER_CURRENT	0x03
+#define RH_PORT_RESET		0x04
+#define RH_PORT_POWER		0x08
+#define RH_PORT_LOW_SPEED	0x09
+
+#define RH_C_PORT_CONNECTION	0x10
+#define RH_C_PORT_ENABLE	0x11
+#define RH_C_PORT_SUSPEND	0x12
+#define RH_C_PORT_OVER_CURRENT	0x13
+#define RH_C_PORT_RESET		0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	0x00
+#define RH_C_HUB_OVER_CURRENT	0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	0x00
+#define RH_ENDPOINT_STALL	0x01
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* struct for each HC 
+ */
+
+#define MAX_TRANS	32
+
+typedef struct td {
+	struct urb *urb;
+	__u16 len;
+	__u16 iso_index;
+} td_t;
+
+typedef struct td_array {
+	int len;
+	td_t td[MAX_TRANS];
+} td_array_t;
+
+typedef struct hci {
+	struct virt_root_hub rh;	/* roothub */
+	wait_queue_head_t waitq;	/* deletion of URBs and devices needs a waitqueue */
+	int active;			/* HC is operating */
+
+	struct list_head ctrl_list;	/* set of ctrl endpoints */
+	struct list_head bulk_list;	/* set of bulk endpoints */
+	struct list_head iso_list;	/* set of isoc endpoints */
+	struct list_head intr_list;	/* ordered (tree) set of int endpoints */
+	struct list_head del_list;	/* set of entpoints to be deleted */
+
+	td_array_t *td_array;
+	td_array_t a_td_array;
+	td_array_t i_td_array[2];
+
+	struct list_head hci_hcd_list;	/* list of all hci_hcd */
+	struct usb_bus *bus;		/* our bus */
+
+//	int trans;			/* number of transactions pending */
+	int active_urbs;
+	int active_trans;
+	int frame_number;		/* frame number */
+	hcipriv_t hp;			/* individual part of hc type */
+	int nakCnt;
+	int last_packet_nak;
+
+} hci_t;
+
+/*-------------------------------------------------------------------------*/
+/* condition (error) CC codes and mapping OHCI like
+ */
+
+#define TD_CC_NOERROR		0x00
+#define TD_CC_CRC		0x01
+#define TD_CC_BITSTUFFING	0x02
+#define TD_CC_DATATOGGLEM	0x03
+#define TD_CC_STALL		0x04
+#define TD_DEVNOTRESP		0x05
+#define TD_PIDCHECKFAIL		0x06
+#define TD_UNEXPECTEDPID	0x07
+#define TD_DATAOVERRUN		0x08
+#define TD_DATAUNDERRUN		0x09
+#define TD_BUFFEROVERRUN	0x0C
+#define TD_BUFFERUNDERRUN	0x0D
+#define TD_NOTACCESSED		0x0F
+
+
+/* urb interface functions */
+static int hci_get_current_frame_number (struct usb_device *usb_dev);
+static int hci_unlink_urb (struct urb * urb);
+
+static int qu_queue_urb (hci_t * hci, struct urb * urb);
+
+/* root hub */
+static int rh_init_int_timer (struct urb * urb);
+static int rh_submit_urb (struct urb * urb);
+static int rh_unlink_urb (struct urb * urb);
+
+/* schedule functions */
+static int sh_add_packet (hci_t * hci, struct urb * urb);
+
+/* hc specific functions */
+static inline void hc_flush_data_cache (hci_t * hci, void *data, int len);
+static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
+				  int *cc, int *toggle, int length, int pid,
+				  int urb_state);
+static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
+				int maxps, int slow, int endpoint, int address,
+				int pid, int format, int urb_state);
+
+static void hc_start_int (hci_t * hci);
+static void hc_stop_int (hci_t * hci);
+static void SL811Write (hci_t * hci, char offset, char data);
+
+/* debug| print the main components of an URB     
+ * small: 0) header + data packets 1) just header */
+
+static void urb_print (struct urb * urb, char *str, int small)
+{
+	unsigned int pipe = urb->pipe;
+	int i, len;
+
+	if (!urb->dev || !urb->dev->bus) {
+		dbg ("%s URB: no dev", str);
+		return;
+	}
+
+	printk ("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)\n",
+		str, hci_get_current_frame_number (urb->dev),
+		usb_pipedevice (pipe), usb_pipeendpoint (pipe),
+		usb_pipeout (pipe) ? 'O' : 'I',
+		usb_pipetype (pipe) < 2 ? (usb_pipeint (pipe) ? "INTR" : "ISOC")
+		: (usb_pipecontrol (pipe) ? "CTRL" : "BULK"), urb->transfer_flags,
+		urb->actual_length, urb->transfer_buffer_length, urb->status,
+		urb->status);
+	if (!small) {
+		if (usb_pipecontrol (pipe)) {
+			printk (__FILE__ ": cmd(8):");
+			for (i = 0; i < 8; i++)
+				printk (" %02x", ((__u8 *) urb->setup_packet)[i]);
+			printk ("\n");
+		}
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printk (__FILE__ ": data(%d/%d):", urb->actual_length,
+				urb->transfer_buffer_length);
+			len = usb_pipeout (pipe) ? urb-> transfer_buffer_length : urb->actual_length;
+			for (i = 0; i < 2096 && i < len; i++)
+				printk (" %02x", ((__u8 *) urb->transfer_buffer)[i]);
+			printk ("%s stat:%d\n", i < len ? "..." : "",
+				urb->status);
+		}
+	}
+}
diff -urN linux-2.4.20-pre1/drivers/usb/hc_sl811.c linux-2.4.20-pre2/drivers/usb/hc_sl811.c
--- linux-2.4.20-pre1/drivers/usb/hc_sl811.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/hc_sl811.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,1358 @@
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * SL811HS USB HCD for Linux Version 0.1 (10/28/2001)
+ * 
+ * requires (includes) hc_simple.[hc] simple generic HCD frontend
+ *  
+ * COPYRIGHT(C) 2001 by CYPRESS SEMICONDUCTOR INC.
+ *
+ *-------------------------------------------------------------------------*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/usb.h>
+#include "../core/hcd.h"
+
+#undef HC_URB_TIMEOUT
+#undef HC_SWITCH_INT
+#undef HC_ENABLE_ISOC
+
+#define SL811_DEBUG_ERR
+
+#ifdef SL811_DEBUG_ERR
+#define DBGERR(fmt, args...) printk(fmt,## args)
+#else
+#define DBGERR(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG
+#define DBG(fmt, args...) printk(fmt,## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_FUNC
+#define DBGFUNC(fmt, args...) printk(fmt,## args)
+#else
+#define DBGFUNC(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_DATA
+#define DBGDATAR(fmt, args...) printk(fmt,## args)
+#define DBGDATAW(fmt, args...) printk(fmt,## args)
+#else
+#define DBGDATAR(fmt, args...)
+#define DBGDATAW(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_VERBOSE
+#define DBGVERBOSE(fmt, args...) printk(fmt,## args)
+#else
+#define DBGVERBOSE(fmt, args...)
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#define HC_SWITCH_INT
+#include "hc_sl811.h"
+#include "hc_simple.h"
+
+static int urb_debug = 0;
+
+#include "hc_simple.c"
+#include "hc_sl811_rh.c"
+
+/* The base_addr, data_reg_addr, and irq number are board specific.
+ * The current values are design to run on the Accelent SA1110 IDP
+ * NOTE: values need to modify for different development boards 
+ */
+
+static int base_addr = 0xd3800000;
+static int data_reg_addr = 0xd3810000;
+static int irq = 34;
+
+/* forware declaration */
+
+int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
+		      int toggle, int slow, int urb_state);
+
+static int sofWaitCnt = 0;
+
+MODULE_PARM (urb_debug, "i");
+MODULE_PARM_DESC (urb_debug, "debug urb messages, default is 0 (no)");
+
+MODULE_PARM (base_addr, "i");
+MODULE_PARM_DESC (base_addr, "sl811 base address 0xd3800000");
+MODULE_PARM (data_reg_addr, "i");
+MODULE_PARM_DESC (data_reg_addr, "sl811 data register address 0xd3810000");
+MODULE_PARM (irq, "i");
+MODULE_PARM_DESC (irq, "IRQ 34 (default)");
+
+static int hc_reset (hci_t * hci);
+
+/***************************************************************************
+ * Function Name : SL811Read
+ *
+ * Read a byte of data from the SL811H/SL11H
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = address of SL811/SL11H register or memory
+ *
+ * Return: data 
+ **************************************************************************/
+char SL811Read (hci_t * hci, char offset)
+{
+	hcipriv_t *hp = &hci->hp;
+	char data;
+	writeb (offset, hp->hcport);
+	wmb ();
+	data = readb (hp->hcport2);
+	rmb ();
+	return (data);
+}
+
+/***************************************************************************
+ * Function Name : SL811Write
+ *
+ * Write a byte of data to the SL811H/SL11H
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = address of SL811/SL11H register or memory
+ *         data  = the data going to write to SL811H
+ *
+ * Return: none 
+ **************************************************************************/
+void SL811Write (hci_t * hci, char offset, char data)
+{
+	hcipriv_t *hp = &hci->hp;
+	writeb (offset, hp->hcport);
+	writeb (data, hp->hcport2);
+	wmb ();
+}
+
+/***************************************************************************
+ * Function Name : SL811BufRead
+ *
+ * Read consecutive bytes of data from the SL811H/SL11H buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = SL811/SL11H register offset
+ *         buf = the buffer where the data will store
+ *         size = number of bytes to read
+ *
+ * Return: none 
+ **************************************************************************/
+void SL811BufRead (hci_t * hci, short offset, char *buf, short size)
+{
+	hcipriv_t *hp = &hci->hp;
+	if (size <= 0)
+		return;
+	writeb ((char) offset, hp->hcport);
+	wmb ();
+	DBGDATAR ("SL811BufRead: offset = 0x%x, data = ", offset);
+	while (size--) {
+		*buf++ = (char) readb (hp->hcport2);
+		DBGDATAR ("0x%x ", *(buf - 1));
+		rmb ();
+	}
+	DBGDATAR ("\n");
+}
+
+/***************************************************************************
+ * Function Name : SL811BufWrite
+ *
+ * Write consecutive bytes of data to the SL811H/SL11H buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = SL811/SL11H register offset
+ *         buf = the data buffer 
+ *         size = number of bytes to write
+ *
+ * Return: none 
+ **************************************************************************/
+void SL811BufWrite (hci_t * hci, short offset, char *buf, short size)
+{
+	hcipriv_t *hp = &hci->hp;
+	if (size <= 0)
+		return;
+	writeb ((char) offset, hp->hcport);
+	wmb ();
+	DBGDATAW ("SL811BufWrite: offset = 0x%x, data = ", offset);
+	while (size--) {
+		DBGDATAW ("0x%x ", *buf);
+		writeb (*buf, hp->hcport2);
+		wmb ();
+		buf++;
+	}
+	DBGDATAW ("\n");
+}
+
+/***************************************************************************
+ * Function Name : regTest
+ *
+ * This routine test the Read/Write functionality of SL811HS registers  
+ *
+ * 1) Store original register value into a buffer
+ * 2) Write to registers with a RAMP pattern. (10, 11, 12, ..., 255)
+ * 3) Read from register
+ * 4) Compare the written value with the read value and make sure they are 
+ *    equivalent
+ * 5) Restore the original register value 
+ *
+ * Input:  hci = data structure for the host controller
+ *   
+ *
+ * Return: TRUE = passed; FALSE = failed 
+ **************************************************************************/
+int regTest (hci_t * hci)
+{
+	int i, data, result = TRUE;
+	char buf[256];
+
+	DBGFUNC ("Enter regTest\n");
+	for (i = 0x10; i < 256; i++) {
+		/* save the original buffer */
+		buf[i] = (char) SL811Read (hci, i);
+
+		/* Write the new data to the buffer */
+		SL811Write (hci, i, i);
+	}
+
+	/* compare the written data */
+	for (i = 0x10; i < 256; i++) {
+		data = SL811Read (hci, i);
+		if (data != i) {
+			DBGERR ("Pattern test failed!! value = 0x%x, s/b 0x%x\n",
+				data, i);
+			result = FALSE;
+		}
+	}
+
+	/* restore the data */
+	for (i = 0x10; i < 256; i++) {
+		SL811Write (hci, i, buf[i]);
+	}
+
+	return (result);
+}
+
+/***************************************************************************
+ * Function Name : regShow
+ *
+ * Display all SL811HS register values
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return: none 
+ **************************************************************************/
+void regShow (hci_t * hci)
+{
+	int i;
+	for (i = 0; i < 256; i++) {
+		printk ("offset %d: 0x%x\n", i, SL811Read (hci, i));
+	}
+}
+
+/************************************************************************
+ * Function Name : USBReset
+ *  
+ * This function resets SL811HS controller and detects the speed of
+ * the connecting device				  
+ *
+ * Input:  hci = data structure for the host controller
+ *                
+ * Return: 0 = no device attached; 1 = USB device attached
+ *                
+ ***********************************************************************/
+static int USBReset (hci_t * hci)
+{
+	int status;
+	hcipriv_t *hp = &hci->hp;
+
+	DBGFUNC ("enter USBReset\n");
+
+	SL811Write (hci, SL11H_CTLREG2, 0xae);
+
+	// setup master and full speed
+
+	SL811Write (hci, SL11H_CTLREG1, 0x08);	// reset USB
+	mdelay (20);		// 20ms                             
+	SL811Write (hci, SL11H_CTLREG1, 0);	// remove SE0        
+
+	for (status = 0; status < 100; status++)
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);	// clear all interrupt bits
+
+	status = SL811Read (hci, SL11H_INTSTATREG);
+
+	if (status & 0x40)	// Check if device is removed
+	{
+		DBG ("USBReset: Device removed\n");
+		SL811Write (hci, SL11H_INTENBLREG,
+			    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+			    SL11H_INTMASK_INSRMV);
+		hp->RHportStatus->portStatus &=
+		    ~(PORT_CONNECT_STAT | PORT_ENABLE_STAT);
+
+		return 0;
+	}
+
+	SL811Write (hci, SL11H_BUFLNTHREG_B, 0);	//zero lenth
+	SL811Write (hci, SL11H_PIDEPREG_B, 0x50);	//send SOF to EP0       
+	SL811Write (hci, SL11H_DEVADDRREG_B, 0x01);	//address0
+	SL811Write (hci, SL11H_SOFLOWREG, 0xe0);
+
+	if (!(status & 0x80)) {
+		/* slow speed device connect directly to root-hub */
+
+		DBG ("USBReset: low speed Device attached\n");
+		SL811Write (hci, SL11H_CTLREG1, 0x8);
+		mdelay (20);
+		SL811Write (hci, SL11H_SOFTMRREG, 0xee);
+		SL811Write (hci, SL11H_CTLREG1, 0x21);
+
+		/* start the SOF or EOP */
+
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01);
+		hp->RHportStatus->portStatus |=
+		    (PORT_CONNECT_STAT | PORT_LOW_SPEED_DEV_ATTACH_STAT);
+
+		/* clear all interrupt bits */
+
+		for (status = 0; status < 20; status++)
+			SL811Write (hci, SL11H_INTSTATREG, 0xff);
+	} else {
+		/* full speed device connect directly to root hub */
+
+		DBG ("USBReset: full speed Device attached\n");
+		SL811Write (hci, SL11H_CTLREG1, 0x8);
+		mdelay (20);
+		SL811Write (hci, SL11H_SOFTMRREG, 0xae);
+		SL811Write (hci, SL11H_CTLREG1, 0x01);
+
+		/* start the SOF or EOP */
+
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01);
+		hp->RHportStatus->portStatus |= (PORT_CONNECT_STAT);
+		hp->RHportStatus->portStatus &= ~PORT_LOW_SPEED_DEV_ATTACH_STAT;
+
+		/* clear all interrupt bits */
+
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);
+
+	}
+
+	/* enable all interrupts */
+	SL811Write (hci, SL11H_INTENBLREG,
+		    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+		    SL11H_INTMASK_INSRMV);
+
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+/* tl functions */
+static inline void hc_mark_last_trans (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u8 *ptd = hp->tl;
+
+	dbg ("enter hc_mark_last_trans\n");
+	if (ptd == NULL) {
+		printk ("hc_mark_last_trans: ptd = null\n");
+		return;
+	}
+	if (hp->xferPktLen > 0)
+		*(ptd + hp->tl_last) |= (1 << 3);
+}
+
+static inline void hc_flush_data_cache (hci_t * hci, void *data, int len)
+{
+}
+
+/************************************************************************
+ * Function Name : hc_add_trans
+ *  
+ * This function sets up the SL811HS register and transmit the USB packets.
+ * 
+ * 1) Determine if enough time within the current frame to send the packet
+ * 2) Load the data into the SL811HS register
+ * 3) Set the appropriate command to the register and trigger the transmit
+ *
+ * Input:  hci = data structure for the host controller
+ *         len = data length
+ *         data = transmitting data
+ *         toggle = USB toggle bit, either 0 or 1
+ *         maxps = maximum packet size for this endpoint
+ *         slow = speed of the device
+ *         endpoint = endpoint number
+ *         address = USB address of the device
+ *         pid = packet ID
+ *         format = 
+ *         urb_state = the current stage of USB transaction
+ *       
+ * Return: 0 = no time left to schedule the transfer
+ *         1 = success 
+ *                
+ ***********************************************************************/
+static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
+				int maxps, int slow, int endpoint, int address,
+				int pid, int format, int urb_state)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u16 speed;
+	int ii, jj, kk;
+
+	DBGFUNC ("enter hc_addr_trans: len =0x%x, toggle:0x%x, endpoing:0x%x,"
+		 " addr:0x%x, pid:0x%x,format:0x%x\n", len, toggle, endpoint,
+		 i address, pid, format);
+
+	if (len > maxps) {
+		len = maxps;
+	}
+
+	speed = hp->RHportStatus->portStatus;
+	if (speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) {
+//      ii = (8*7*8 + 6*3) * len + 800; 
+		ii = 8 * 8 * len + 1024;
+	} else {
+		if (slow) {
+//          ii = (8*7*8 + 6*3) * len + 800; 
+			ii = 8 * 8 * len + 2048;
+		} else
+//          ii = (8*7 + 6*3)*len + 110;
+			ii = 8 * len + 256;
+	}
+
+	ii += 2 * 10 * len;
+
+	jj = SL811Read (hci, SL11H_SOFTMRREG);
+	kk = (jj & 0xFF) * 64 - ii;
+
+	if (kk < 0) {
+		DBGVERBOSE
+		    ("hc_add_trans: no bandwidth for schedule, ii = 0x%x,"
+		     "jj = 0x%x, len =0x%x, active_trans = 0x%x\n", ii, jj, len,
+		     hci->active_trans);
+		return (-1);
+	}
+
+	if (pid != PID_IN) {
+		/* Load data into hc */
+
+		SL811BufWrite (hci, SL11H_DATA_START, (__u8 *) data, len);
+	}
+
+	/* transmit */
+
+	SL11StartXaction (hci, (__u8) address, (__u8) endpoint, (__u8) pid, len,
+			  toggle, slow, urb_state);
+
+	return len;
+}
+
+/************************************************************************
+ * Function Name : hc_parse_trans
+ *  
+ * This function checks the status of the transmitted or received packet
+ * and copy the data from the SL811HS register into a buffer.
+ *
+ * 1) Check the status of the packet 
+ * 2) If successful, and IN packet then copy the data from the SL811HS register
+ *    into a buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         actbytes = pointer to actual number of bytes
+ *         data = data buffer
+ *         cc = packet status
+ *         length = the urb transmit length
+ *         pid = packet ID
+ *         urb_state = the current stage of USB transaction
+ *       
+ * Return: 0 
+ ***********************************************************************/
+static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
+				  int *cc, int *toggle, int length, int pid,
+				  int urb_state)
+{
+	__u8 addr;
+	__u8 len;
+
+	DBGFUNC ("enter hc_parse_trans\n");
+
+	/* get packet status; convert ack rcvd to ack-not-rcvd */
+
+	*cc = (int) SL811Read (hci, SL11H_PKTSTATREG);
+
+	if (*cc &
+	    (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | SL11H_STATMASK_OVF |
+	     SL11H_STATMASK_NAK | SL11H_STATMASK_STALL)) {
+		if (*cc & SL11H_STATMASK_OVF)
+			DBGERR ("parse trans: error recv ack, cc = 0x%x, TX_BASE_Len = "
+				"0x%x, TX_count=0x%x\n", *cc,
+				SL811Read (hci, SL11H_BUFLNTHREG),
+				SL811Read (hci, SL11H_XFERCNTREG));
+
+	} else {
+		DBGVERBOSE ("parse trans: recv ack, cc = 0x%x, len = 0x%x, \n",
+			    *cc, length);
+
+		/* Successful data */
+		if ((pid == PID_IN) && (urb_state != US_CTRL_SETUP)) {
+
+			/* Find the base address */
+			addr = SL811Read (hci, SL11H_BUFADDRREG);
+
+			/* Find the Transmit Length */
+			len = SL811Read (hci, SL11H_BUFLNTHREG);
+
+			/* The actual data length = xmit length reg - xfer count reg */
+			*actbytes = len - SL811Read (hci, SL11H_XFERCNTREG);
+
+			if ((data != NULL) && (*actbytes > 0)) {
+				SL811BufRead (hci, addr, data, *actbytes);
+
+			} else if ((data == NULL) && (*actbytes <= 0)) {
+				DBGERR ("hc_parse_trans: data = NULL or actbyte = 0x%x\n",
+					*actbytes);
+				return 0;
+			}
+		} else if (pid == PID_OUT) {
+			*actbytes = length;
+		} else {
+			// printk ("ERR:parse_trans, pid != IN or OUT, pid = 0x%x\n", pid);
+		}
+		*toggle = !*toggle;
+	}
+
+	return 0;
+}
+
+/************************************************************************
+ * Function Name : hc_start_int
+ *  
+ * This function enables SL811HS interrupts
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+static void hc_start_int (hci_t * hci)
+{
+#ifdef HC_SWITCH_INT
+	int mask =
+	    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+	    SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET;
+	SL811Write (hci, IntEna, mask);
+#endif
+}
+
+/************************************************************************
+ * Function Name : hc_stop_int
+ *  
+ * This function disables SL811HS interrupts
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+static void hc_stop_int (hci_t * hci)
+{
+#ifdef HC_SWITCH_INT
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+//  SL811Write(hci, SL11H_INTENBLREG, SL11H_INTMASK_INSRMV);
+
+#endif
+}
+
+/************************************************************************
+ * Function Name : handleInsRmvIntr
+ *  
+ * This function handles the insertion or removal of device on  SL811HS. 
+ * It resets the controller and updates the port status
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+void handleInsRmvIntr (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	USBReset (hci);
+
+	/* Changes in connection status */
+
+	hp->RHportStatus->portChange |= PORT_CONNECT_CHANGE;
+
+	/* Port Enable or Disable */
+
+	if (hp->RHportStatus->portStatus & PORT_CONNECT_STAT) {
+		/* device is connected to the port:
+		 *    1) Enable port 
+		 *    2) Resume ?? 
+		 */
+//               hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
+
+		/* Over Current is not supported by the SL811 HW ?? */
+
+		/* How about the Port Power ?? */
+
+	} else {
+		/* Device has disconnect:
+		 *    1) Disable port
+		 */
+
+		hp->RHportStatus->portStatus &= ~(PORT_ENABLE_STAT);
+		hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
+
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: SL11StartXaction
+ *  
+ * This functions load the registers with appropriate value and 
+ * transmit the packet.				  
+ *
+ * Input:  hci = data structure for the host controller
+ *         addr = USB address of the device
+ *         epaddr = endpoint number
+ *         pid = packet ID
+ *         len = data length
+ *         toggle = USB toggle bit, either 0 or 1
+ *         slow = speed of the device
+ *         urb_state = the current stage of USB transaction
+ *
+ * Return: 0 = error; 1 = successful
+ *                
+ *****************************************************************/
+int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
+		      int toggle, int slow, int urb_state)
+{
+
+	hcipriv_t *hp = &hci->hp;
+	__u8 cmd = 0;
+	__u8 setup_data[4];
+	__u16 speed;
+
+	speed = hp->RHportStatus->portStatus;
+	if (!(speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) && slow) {
+		cmd |= SL11H_HCTLMASK_PREAMBLE;
+	}
+	switch (pid) {
+	case PID_SETUP:
+		cmd &= SL11H_HCTLMASK_PREAMBLE;
+		cmd |=
+		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
+		     SL11H_HCTLMASK_WRITE);
+		break;
+
+	case PID_OUT:
+		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
+		cmd |=
+		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
+		     SL11H_HCTLMASK_WRITE);
+		if (toggle) {
+			cmd |= SL11H_HCTLMASK_SEQ;
+		}
+		break;
+
+	case PID_IN:
+		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
+		cmd |= (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP);
+		break;
+
+	default:
+		DBGERR ("ERR: SL11StartXaction: unknow pid = 0x%x\n", pid);
+		return 0;
+	}
+	setup_data[0] = SL11H_DATA_START;
+	setup_data[1] = len;
+	setup_data[2] = (((pid & 0x0F) << 4) | (epaddr & 0xF));
+	setup_data[3] = addr & 0x7F;
+
+	SL811BufWrite (hci, SL11H_BUFADDRREG, (__u8 *) & setup_data[0], 4);
+
+	SL811Write (hci, SL11H_HOSTCTLREG, cmd);
+
+#if 0
+	/* The SL811 has a hardware flaw when hub devices sends out
+	 * SE0 between packets. It has been found in a TI chipset and
+	 * cypress hub chipset. It causes the SL811 to hang
+	 * The workaround is to re-issue the preample again.
+	 */
+
+	if ((cmd & SL11H_HCTLMASK_PREAMBLE)) {
+		SL811Write (hci, SL11H_PIDEPREG_B, 0xc0);
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x1);	// send the premable
+	}
+#endif
+	return 1;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_interrupt
+ *
+ * Interrupt service routine. 
+ *
+ * 1) determine the causes of interrupt
+ * 2) clears all interrupts
+ * 3) calls appropriate function to service the interrupt
+ *
+ * Input:  irq = interrupt line associated with the controller 
+ *         hci = data structure for the host controller
+ *         r = holds the snapshot of the processor's context before 
+ *             the processor entered interrupt code. (not used here) 
+ *
+ * Return value  : None.
+ *                
+ *****************************************************************/
+static void hc_interrupt (int irq, void *__hci, struct pt_regs *r)
+{
+	char ii;
+	hci_t *hci = __hci;
+	int isExcessNak = 0;
+	int urb_state = 0;
+	char tmpIrq = 0;
+
+	/* Get value from interrupt status register */
+
+	ii = SL811Read (hci, SL11H_INTSTATREG);
+
+	if (ii & SL11H_INTMASK_INSRMV) {
+		/* Device insertion or removal detected for the USB port */
+
+		SL811Write (hci, SL11H_INTENBLREG, 0);
+		SL811Write (hci, SL11H_CTLREG1, 0);
+		mdelay (100);	// wait for device stable 
+		handleInsRmvIntr (hci);
+		return;
+	}
+
+	/* Clear all interrupts */
+
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+
+	if (ii & SL11H_INTMASK_XFERDONE) {
+		/* USB Done interrupt occurred */
+
+		urb_state = sh_done_list (hci, &isExcessNak);
+#ifdef WARNING
+		if (hci->td_array->len > 0)
+			printk ("WARNING: IRQ, td_array->len = 0x%x, s/b:0\n",
+				hci->td_array->len);
+#endif
+		if (hci->td_array->len == 0 && !isExcessNak
+		    && !(ii & SL11H_INTMASK_SOFINTR) && (urb_state == 0)) {
+			if (urb_state == 0) {
+				/* All urb_state has not been finished yet! 
+				 * continue with the current urb transaction 
+				 */
+
+				if (hci->last_packet_nak == 0) {
+					if (!usb_pipecontrol
+					    (hci->td_array->td[0].urb->pipe))
+						sh_add_packet (hci, hci->td_array-> td[0].urb);
+				}
+			} else {
+				/* The last transaction has completed:
+				 * schedule the next transaction 
+				 */
+
+				sh_schedule_trans (hci, 0);
+			}
+		}
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);
+		return;
+	}
+
+	if (ii & SL11H_INTMASK_SOFINTR) {
+		hci->frame_number = (hci->frame_number + 1) % 2048;
+		if (hci->td_array->len == 0)
+			sh_schedule_trans (hci, 1);
+		else {
+			if (sofWaitCnt++ > 100) {
+				/* The last transaction has not completed.
+				 * Need to retire the current td, and let
+				 * it transmit again later on.
+				 * (THIS NEEDS TO BE WORK ON MORE, IT SHOULD NEVER 
+				 *  GET TO THIS POINT)
+				 */
+
+				DBGERR ("SOF interrupt: td_array->len = 0x%x, s/b: 0\n",
+					hci->td_array->len);
+				urb_print (hci->td_array->td[hci->td_array->len - 1].urb,
+					   "INTERRUPT", 0);
+				sh_done_list (hci, &isExcessNak);
+				SL811Write (hci, SL11H_INTSTATREG, 0xff);
+				hci->td_array->len = 0;
+				sofWaitCnt = 0;
+			}
+		}
+		tmpIrq = SL811Read (hci, SL11H_INTSTATREG) & SL811Read (hci, SL11H_INTENBLREG);
+		if (tmpIrq) {
+			DBG ("IRQ occurred while service SOF: irq = 0x%x\n",
+			     tmpIrq);
+
+			/* If we receive a DONE IRQ after schedule, need to 
+			 * handle DONE IRQ again 
+			 */
+
+			if (tmpIrq & SL11H_INTMASK_XFERDONE) {
+				DBGERR ("IRQ occurred while service SOF: irq = 0x%x\n",
+					tmpIrq);
+				urb_state = sh_done_list (hci, &isExcessNak);
+			}
+			SL811Write (hci, SL11H_INTSTATREG, 0xff);
+		}
+	} else {
+		DBG ("SL811 ISR: unknown, int = 0x%x \n", ii);
+	}
+
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+	return;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_reset
+ *
+ * This function does register test and resets the SL811HS 
+ * controller.
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0
+ *                
+ *****************************************************************/
+static int hc_reset (hci_t * hci)
+{
+	int attachFlag = 0;
+
+	DBGFUNC ("Enter hc_reset\n");
+	regTest (hci);
+	attachFlag = USBReset (hci);
+	if (attachFlag) {
+		setPortChange (hci, PORT_CONNECT_CHANGE);
+	}
+	return (0);
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_alloc_trans_buffer
+ *
+ * This function allocates all transfer buffer  
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0
+ *                
+ *****************************************************************/
+static int hc_alloc_trans_buffer (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	int maxlen;
+
+	hp->itl0_len = 0;
+	hp->itl1_len = 0;
+	hp->atl_len = 0;
+
+	hp->itl_buffer_len = 1024;
+	hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len;	/* 2048 */
+
+	maxlen = (hp->itl_buffer_len > hp->atl_buffer_len) ? hp->itl_buffer_len : hp->atl_buffer_len;
+
+	hp->tl = kmalloc (maxlen, GFP_KERNEL);
+
+	if (!hp->tl)
+		return -ENOMEM;
+
+	memset (hp->tl, 0, maxlen);
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: getPortStatusAndChange
+ *
+ * This function gets the ports status from SL811 and format it 
+ * to a USB request format
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : port status and change
+ *                
+ *****************************************************************/
+static __u32 getPortStatusAndChange (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u32 portstatus;
+
+	DBGFUNC ("enter getPorStatusAndChange\n");
+
+	portstatus = hp->RHportStatus->portChange << 16 | hp->RHportStatus->portStatus;
+
+	return (portstatus);
+}
+
+/*****************************************************************
+ *
+ * Function Name: setPortChange
+ *
+ * This function set the bit position of portChange.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void setPortChange (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	switch (bitPos) {
+	case PORT_CONNECT_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_OVER_CURRENT_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: clrPortChange
+ *
+ * This function clear the bit position of portChange.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void clrPortChange (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_CONNECT_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_ENABLE_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_RESET_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_SUSPEND_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_OVER_CURRENT_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: clrPortStatus
+ *
+ * This function clear the bit position of portStatus.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void clrPortStatus (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: setPortStatus
+ *
+ * This function set the bit position of portStatus.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void setPortStatus (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_start
+ *
+ * This function starts the root hub functionality. 
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static int hc_start (hci_t * hci)
+{
+	DBGFUNC ("Enter hc_start\n");
+
+	rh_connect_rh (hci);
+
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_alloc_hci
+ *
+ * This function allocates all data structure and store in the 
+ * private data structure. 
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static hci_t *__devinit hc_alloc_hci (void)
+{
+	hci_t *hci;
+	hcipriv_t *hp;
+	portstat_t *ps;
+	struct usb_bus *bus;
+
+	DBGFUNC ("Enter hc_alloc_hci\n");
+	hci = (hci_t *) kmalloc (sizeof (hci_t), GFP_KERNEL);
+	if (!hci)
+		return NULL;
+
+	memset (hci, 0, sizeof (hci_t));
+
+	hp = &hci->hp;
+
+	hp->irq = -1;
+	hp->hcport = -1;
+
+	/* setup root hub port status */
+
+	ps = (portstat_t *) kmalloc (sizeof (portstat_t), GFP_KERNEL);
+
+	if (!ps)
+		return NULL;
+	ps->portStatus = PORT_STAT_DEFAULT;
+	ps->portChange = PORT_CHANGE_DEFAULT;
+	hp->RHportStatus = ps;
+
+	hci->nakCnt = 0;
+	hci->last_packet_nak = 0;
+
+	hci->a_td_array.len = 0;
+	hci->i_td_array[0].len = 0;
+	hci->i_td_array[1].len = 0;
+	hci->td_array = &hci->a_td_array;
+	hci->active_urbs = 0;
+	hci->active_trans = 0;
+	INIT_LIST_HEAD (&hci->hci_hcd_list);
+	list_add (&hci->hci_hcd_list, &hci_hcd_list);
+	init_waitqueue_head (&hci->waitq);
+
+	INIT_LIST_HEAD (&hci->ctrl_list);
+	INIT_LIST_HEAD (&hci->bulk_list);
+	INIT_LIST_HEAD (&hci->iso_list);
+	INIT_LIST_HEAD (&hci->intr_list);
+	INIT_LIST_HEAD (&hci->del_list);
+
+	bus = usb_alloc_bus (&hci_device_operations);
+	if (!bus) {
+		kfree (hci);
+		return NULL;
+	}
+
+	hci->bus = bus;
+	bus->hcpriv = (void *) hci;
+
+	return hci;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_release_hci
+ *
+ * This function De-allocate all resources  
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static void hc_release_hci (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	DBGFUNC ("Enter hc_release_hci\n");
+
+	/* disconnect all devices */
+	if (hci->bus->root_hub)
+		usb_disconnect (&hci->bus->root_hub);
+
+	hc_reset (hci);
+
+	if (hp->tl)
+		kfree (hp->tl);
+
+	if (hp->hcport > 0) {
+		release_region (hp->hcport, 2);
+		hp->hcport = 0;
+	}
+
+	if (hp->irq >= 0) {
+		free_irq (hp->irq, hci);
+		hp->irq = -1;
+	}
+
+	usb_deregister_bus (hci->bus);
+	usb_free_bus (hci->bus);
+
+	list_del (&hci->hci_hcd_list);
+	INIT_LIST_HEAD (&hci->hci_hcd_list);
+
+	kfree (hci);
+}
+
+/*****************************************************************
+ *
+ * Function Name: init_irq
+ *
+ * This function is board specific.  It sets up the interrupt to 
+ * be an edge trigger and trigger on the rising edge  
+ *
+ * Input: none 
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+void init_irq (void)
+{
+	GPDR &= ~(1 << 13);
+	set_GPIO_IRQ_edge (1 << 13, GPIO_RISING_EDGE);
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_found_hci
+ *
+ * This function request IO memory regions, request IRQ, and
+ * allocate all other resources. 
+ *
+ * Input: addr = first IO address
+ *        addr2 = second IO address
+ *        irq = interrupt number 
+ *
+ * Return: 0 = success or error condition 
+ *                
+ *****************************************************************/
+static int __devinit hc_found_hci (int addr, int addr2, int irq)
+{
+	hci_t *hci;
+	hcipriv_t *hp;
+
+	DBGFUNC ("Enter hc_found_hci\n");
+	hci = hc_alloc_hci ();
+	if (!hci) {
+		return -ENOMEM;
+	}
+
+	init_irq ();
+	hp = &hci->hp;
+
+	if (!request_region (addr, 256, "SL811 USB HOST")) {
+		DBGERR ("request address %d failed", addr);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->hcport = addr;
+	if (!hp->hcport) {
+		DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport);
+	}
+
+	if (!request_region (addr2, 256, "SL811 USB HOST")) {
+		DBGERR ("request address %d failed", addr2);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->hcport2 = addr2;
+	if (!hp->hcport2) {
+		DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport2);
+	}
+
+	if (hc_alloc_trans_buffer (hci)) {
+		hc_release_hci (hci);
+		return -ENOMEM;
+	}
+
+	usb_register_bus (hci->bus);
+
+	if (request_irq (irq, hc_interrupt, 0, "SL811", hci) != 0) {
+		DBGERR ("request interrupt %d failed", irq);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->irq = irq;
+
+	printk (KERN_INFO __FILE__ ": USB SL811 at %x, addr2 = %x, IRQ %d\n",
+		addr, addr2, irq);
+	hc_reset (hci);
+
+	if (hc_start (hci) < 0) {
+		DBGERR ("can't start usb-%x", addr);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hci_hcd_init
+ *
+ * This is an init function, and it is the first function being called
+ *
+ * Input: none 
+ *
+ * Return: 0 = success or error condition 
+ *                
+ *****************************************************************/
+static int __init hci_hcd_init (void)
+{
+	int ret;
+
+	DBGFUNC ("Enter hci_hcd_init\n");
+	ret = hc_found_hci (base_addr, data_reg_addr, irq);
+
+	return ret;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hci_hcd_cleanup
+ *
+ * This is a cleanup function, and it is called when module is 
+ * unloaded. 
+ *
+ * Input: none 
+ *
+ * Return: none 
+ *                
+ *****************************************************************/
+static void __exit hci_hcd_cleanup (void)
+{
+	struct list_head *hci_l;
+	hci_t *hci;
+
+	DBGFUNC ("Enter hci_hcd_cleanup\n");
+	for (hci_l = hci_hcd_list.next; hci_l != &hci_hcd_list;) {
+		hci = list_entry (hci_l, hci_t, hci_hcd_list);
+		hci_l = hci_l->next;
+		hc_release_hci (hci);
+	}
+}
+
+module_init (hci_hcd_init);
+module_exit (hci_hcd_cleanup);
+
+MODULE_AUTHOR ("Pei Liu <pbl@cypress.com>");
+MODULE_DESCRIPTION ("USB SL811HS Host Controller Driver");
diff -urN linux-2.4.20-pre1/drivers/usb/hc_sl811.h linux-2.4.20-pre2/drivers/usb/hc_sl811.h
--- linux-2.4.20-pre1/drivers/usb/hc_sl811.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/hc_sl811.h	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,385 @@
+/*
+ * SL811HS HCD (Host Controller Driver) for USB.
+ * 
+ * COPYRIGHT (C) by CYPRESS SEMICONDUCTOR INC 
+ * 
+ *
+ */
+
+#define GET_FRAME_NUMBER(hci)	READ_REG32 (hci, HcFmNumber)
+
+/*
+ * Maximum number of root hub ports
+ */
+#define MAX_ROOT_PORTS		15	/* maximum OHCI root hub ports */
+
+/* control and status registers */
+#define HcRevision		0x00
+#define HcControl		0x01
+#define HcCommandStatus		0x02
+#define HcInterruptStatus	0x03
+#define HcInterruptEnable	0x04
+#define HcInterruptDisable	0x05
+#define HcFmInterval		0x0D
+#define HcFmRemaining		0x0E
+#define HcFmNumber		0x0F
+#define HcLSThreshold		0x11
+#define HcRhDescriptorA		0x12
+#define HcRhDescriptorB		0x13
+#define HcRhStatus		0x14
+#define HcRhPortStatus		0x15
+
+#define HcHardwareConfiguration 0x20
+#define HcDMAConfiguration	0x21
+#define HcTransferCounter	0x22
+#define HcuPInterrupt		0x24
+#define HcuPInterruptEnable	0x25
+#define HcChipID		0x27
+#define HcScratch		0x28
+#define HcSoftwareReset		0x29
+#define HcITLBufferLength	0x2A
+#define HcATLBufferLength	0x2B
+#define HcBufferStatus		0x2C
+#define HcReadBackITL0Length	0x2D
+#define HcReadBackITL1Length	0x2E
+#define HcITLBufferPort		0x40
+#define HcATLBufferPort		0x41
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_HCFS		(3 << 6)	/* BUS state mask */
+#define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE		(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#define OHCI_USB_RESET		(0 << 6)
+#define OHCI_USB_RESUME		(1 << 6)
+#define OHCI_USB_OPER		(2 << 6)
+#define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_SO		(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_ATD	(1 << 7)	/* scheduling overrun */
+
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+/*
+ * HcHardwareConfiguration
+ */
+#define InterruptPinEnable	(1 << 0)
+#define InterruptPinTrigger	(1 << 1)
+#define InterruptOutputPolarity	(1 << 2)
+#define DataBusWidth16		(1 << 3)
+#define DREQOutputPolarity	(1 << 5)
+#define DACKInputPolarity	(1 << 6)
+#define EOTInputPolarity	(1 << 7)
+#define DACKMode		(1 << 8)
+#define AnalogOCEnable		(1 << 10)
+#define SuspendClkNotStop	(1 << 11)
+#define DownstreamPort15KRSel	(1 << 12)
+
+/* 
+ * HcDMAConfiguration
+ */
+#define DMAReadWriteSelect 	(1 << 0)
+#define ITL_ATL_DataSelect	(1 << 1)
+#define DMACounterSelect	(1 << 2)
+#define DMAEnable		(1 << 4)
+#define BurstLen_1		0
+#define BurstLen_4		(1 << 5)
+#define BurstLen_8		(2 << 5)
+
+/*
+ * HcuPInterrupt
+ */
+#define SOFITLInt		(1 << 0)
+#define ATLInt			(1 << 1)
+#define AllEOTInterrupt		(1 << 2)
+#define OPR_Reg			(1 << 4)
+#define HCSuspended		(1 << 5)
+#define ClkReady		(1 << 6)
+
+/*
+ * HcBufferStatus
+ */
+#define ITL0BufferFull		(1 << 0)
+#define ITL1BufferFull		(1 << 1)
+#define ATLBufferFull		(1 << 2)
+#define ITL0BufferDone		(1 << 3)
+#define ITL1BufferDone		(1 << 4)
+#define ATLBufferDone		(1 << 5)
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS            0x00000001	/* current connect status */
+#define RH_PS_PES            0x00000002	/* port enable status */
+#define RH_PS_PSS            0x00000004	/* port suspend status */
+#define RH_PS_POCI           0x00000008	/* port over current indicator */
+#define RH_PS_PRS            0x00000010	/* port reset status */
+#define RH_PS_PPS            0x00000100	/* port power status */
+#define RH_PS_LSDA           0x00000200	/* low speed device attached */
+#define RH_PS_CSC            0x00010000	/* connect status change */
+#define RH_PS_PESC           0x00020000	/* port enable status change */
+#define RH_PS_PSSC           0x00040000	/* port suspend status change */
+#define RH_PS_OCIC           0x00080000	/* over current indicator change */
+#define RH_PS_PRSC           0x00100000	/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS		0x00000001	/* local power status */
+#define RH_HS_OCI		0x00000002	/* over current indicator */
+#define RH_HS_DRWE		0x00008000	/* device remote wakeup enable */
+#define RH_HS_LPSC		0x00010000	/* local power status change */
+#define RH_HS_OCIC		0x00020000	/* over current indicator change */
+#define RH_HS_CRWE		0x80000000	/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR			0x0000ffff	/* device removable flags */
+#define RH_B_PPCM		0xffff0000	/* port power control mask */
+
+/* roothub.a masks */
+#define	RH_A_NDP		(0xff << 0)	/* number of downstream ports */
+#define	RH_A_PSM		(1 << 8)	/* power switching mode */
+#define	RH_A_NPS		(1 << 9)	/* no power switching */
+#define	RH_A_DT			(1 << 10)	/* device type (mbz) */
+#define	RH_A_OCPM		(1 << 11)	/* over current protection mode */
+#define	RH_A_NOCP		(1 << 12)	/* no over current protection */
+#define	RH_A_POTPGT		(0xff << 24)	/* power on to power good time */
+
+#define URB_DEL 1
+
+#define PORT_STAT_DEFAULT		0x0100
+#define PORT_CONNECT_STAT  		0x1
+#define PORT_ENABLE_STAT		0x2
+#define PORT_SUSPEND_STAT		0x4
+#define PORT_OVER_CURRENT_STAT		0x8
+#define PORT_RESET_STAT			0x10
+#define PORT_POWER_STAT			0x100
+#define PORT_LOW_SPEED_DEV_ATTACH_STAT	0x200
+
+#define PORT_CHANGE_DEFAULT		0x0
+#define PORT_CONNECT_CHANGE		0x1
+#define PORT_ENABLE_CHANGE		0x2
+#define PORT_SUSPEND_CHANGE		0x4
+#define PORT_OVER_CURRENT_CHANGE	0x8
+#define PORT_RESET_CHANGE		0x10
+
+/* Port Status Request info */
+
+typedef struct portstat {
+	__u16 portChange;
+	__u16 portStatus;
+} portstat_t;
+
+typedef struct hcipriv {
+	int irq;
+	int disabled;		/* e.g. got a UE, we're hung */
+	atomic_t resume_count;	/* defending against multiple resumes */
+	struct ohci_regs *regs;	/* OHCI controller's memory */
+	int hcport;		/* I/O base address */
+	int hcport2;		/* I/O data reg addr */
+
+	struct portstat *RHportStatus;	/* root hub port status */
+
+	int intrstatus;
+	__u32 hc_control;	/* copy of the hc control reg */
+
+	int frame;
+
+	__u8 *tl;
+	int xferPktLen;
+	int atl_len;
+	int atl_buffer_len;
+	int itl0_len;
+	int itl1_len;
+	int itl_buffer_len;
+	int itl_index;
+	int tl_last;
+	int units_left;
+
+} hcipriv_t;
+struct hci;
+
+#define cClt        0		// Control
+#define cISO        1		// ISO
+#define cBULK       2		// BULK
+#define cInt        3		// Interrupt
+#define ISO_BIT     0x10
+
+/*-------------------------------------------------------------------------
+ * EP0 use for configuration and Vendor Specific command interface
+ *------------------------------------------------------------------------*/
+#define cMemStart       0x10
+#define EP0Buf          0x40	/* SL11H/SL811H memory start at 0x40 */
+#define EP0Len          0x40	/* Length of config buffer EP0Buf */
+#define EP1Buf          0x60
+#define EP1Len          0x40
+
+/*-------------------------------------------------------------------------
+ * SL11H/SL811H memory from 80h-ffh use as ping-pong buffer.
+ *------------------------------------------------------------------------*/
+#define uBufA           0x80	/* buffer A address for DATA0 */
+#define uBufB           0xc0	/* buffer B address for DATA1 */
+#define uXferLen        0x40	/* xfer length */
+#define sMemSize        0xc0	/* Total SL11 memory size */
+#define cMemEnd         256
+
+/*-------------------------------------------------------------------------
+ * SL811H Register Control memory map
+ * --Note: 
+ *      --SL11H only has one control register set from 0x00-0x04
+ *      --SL811H has two control register set from 0x00-0x04 and 0x08-0x0c
+ *------------------------------------------------------------------------*/
+
+#define EP0Control      0x00
+#define EP0Address      0x01
+#define EP0XferLen      0x02
+#define EP0Status       0x03
+#define EP0Counter      0x04
+
+#define EP1Control      0x08
+#define EP1Address      0x09
+#define EP1XferLen      0x0a
+#define EP1Status       0x0b
+#define EP1Counter      0x0c
+
+#define CtrlReg         0x05
+#define IntEna          0x06
+			 // 0x07 is reserved
+#define IntStatus       0x0d
+#define cDATASet        0x0e
+#define cSOFcnt         0x0f
+#define IntMask         0x57	/* Reset|DMA|EP0|EP2|EP1 for IntEna */
+#define HostMask        0x47	/* Host request command  for IntStatus */
+#define ReadMask        0xd7	/* Read mask interrupt   for IntStatus */
+
+/*-------------------------------------------------------------------------
+ * Standard Chapter 9 definition
+ *-------------------------------------------------------------------------
+ */
+#define GET_STATUS      0x00
+#define CLEAR_FEATURE   0x01
+#define SET_FEATURE     0x03
+#define SET_ADDRESS     0x05
+#define GET_DESCRIPTOR  0x06
+#define SET_DESCRIPTOR  0x07
+#define GET_CONFIG      0x08
+#define SET_CONFIG      0x09
+#define GET_INTERFACE   0x0a
+#define SET_INTERFACE   0x0b
+#define SYNCH_FRAME     0x0c
+
+#define DEVICE          0x01
+#define CONFIGURATION   0x02
+#define STRING          0x03
+#define INTERFACE       0x04
+#define ENDPOINT        0x05
+
+/*-------------------------------------------------------------------------
+ * SL11H/SL811H definition
+ *-------------------------------------------------------------------------
+ */
+#define DATA0_WR	0x07	// (Arm+Enable+tranmist to Host+DATA0)
+#define DATA1_WR	0x47	// (Arm+Enable+tranmist to Host on DATA1)
+#define ZDATA0_WR	0x05	// (Arm+Transaction Ignored+tranmist to Host+DATA0)
+#define ZDATA1_WR	0x45	// (Arm+Transaction Ignored+tranmist to Host+DATA1)
+#define DATA0_RD	0x03	// (Arm+Enable+received from Host+DATA0)
+#define DATA1_RD	0x43	// (Arm+Enable+received from Host+DATA1)
+
+#define PID_SETUP	0x2d	// USB Specification 1.1 Standard Definition
+#define PID_SOF		0xA5
+#define PID_IN		0x69
+#define PID_OUT		0xe1
+
+#define MAX_RETRY	0xffff
+#define TIMEOUT		5		/* 2 mseconds */
+
+#define SL11H_HOSTCTLREG	0
+#define SL11H_BUFADDRREG	1
+#define SL11H_BUFLNTHREG	2
+#define SL11H_PKTSTATREG	3	/* read */
+#define SL11H_PIDEPREG		3	/* write */
+#define SL11H_XFERCNTREG	4	/* read */
+#define SL11H_DEVADDRREG	4	/* write */
+#define SL11H_CTLREG1		5
+#define SL11H_INTENBLREG	6
+
+#define SL11H_HOSTCTLREG_B	8
+#define SL11H_BUFADDRREG_B	9
+#define SL11H_BUFLNTHREG_B	0x0A
+#define SL11H_PKTSTATREG_B	0x0B	/* read */
+#define SL11H_PIDEPREG_B	0x0B	/* write */
+#define SL11H_XFERCNTREG_B	0x0C	/* read */
+#define SL11H_DEVADDRREG_B	0x0C	/* write */
+
+#define SL11H_INTSTATREG	0x0D	/* write clears bitwise */
+#define SL11H_HWREVREG		0x0E	/* read */
+#define SL11H_SOFLOWREG		0x0E	/* write */
+#define SL11H_SOFTMRREG		0x0F	/* read */
+#define SL11H_CTLREG2		0x0F	/* write */
+#define SL11H_DATA_START	0x10
+
+/* Host control register bits (addr 0) */
+#define SL11H_HCTLMASK_ARM	1
+#define SL11H_HCTLMASK_ENBLEP	2
+#define SL11H_HCTLMASK_WRITE	4
+#define SL11H_HCTLMASK_ISOCH	0x10
+#define SL11H_HCTLMASK_AFTERSOF	0x20
+#define SL11H_HCTLMASK_SEQ	0x40
+#define SL11H_HCTLMASK_PREAMBLE	0x80
+
+/* Packet status register bits (addr 3) */
+#define SL11H_STATMASK_ACK	1
+#define SL11H_STATMASK_ERROR	2
+#define SL11H_STATMASK_TMOUT	4
+#define SL11H_STATMASK_SEQ	8
+#define SL11H_STATMASK_SETUP	0x10
+#define SL11H_STATMASK_OVF	0x20
+#define SL11H_STATMASK_NAK	0x40
+#define SL11H_STATMASK_STALL	0x80
+
+/* Control register 1 bits (addr 5) */
+#define SL11H_CTL1MASK_DSBLSOF	1
+#define SL11H_CTL1MASK_NOTXEOF2	4
+#define SL11H_CTL1MASK_DSTATE	0x18
+#define SL11H_CTL1MASK_NSPD	0x20
+#define SL11H_CTL1MASK_SUSPEND	0x40
+#define SL11H_CTL1MASK_CLK12	0x80
+
+#define SL11H_CTL1VAL_RESET	8
+
+/* Interrut enable (addr 6) and interrupt status register bits (addr 0xD) */
+#define SL11H_INTMASK_XFERDONE	1
+#define SL11H_INTMASK_SOFINTR	0x10
+#define SL11H_INTMASK_INSRMV	0x20
+#define SL11H_INTMASK_USBRESET	0x40
+#define SL11H_INTMASK_DSTATE	0x80	/* only in status reg */
+
+/* HW rev and SOF lo register bits (addr 0xE) */
+#define SL11H_HWRMASK_HWREV	0xF0
+
+/* SOF counter and control reg 2 (addr 0xF) */
+#define SL11H_CTL2MASK_SOFHI	0x3F
+#define SL11H_CTL2MASK_DSWAP	0x40
+#define SL11H_CTL2MASK_HOSTMODE	0xae
+
diff -urN linux-2.4.20-pre1/drivers/usb/hc_sl811_rh.c linux-2.4.20-pre2/drivers/usb/hc_sl811_rh.c
--- linux-2.4.20-pre1/drivers/usb/hc_sl811_rh.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/hc_sl811_rh.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,526 @@
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * SL811HS virtual root hub
+ *  
+ * based on usb-ohci.c by R. Weissgaerber et al.
+ *-------------------------------------------------------------------------*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ *
+ *-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#undef DEBUG
+#endif
+static __u32 getPortStatusAndChange (hci_t * hci);
+static void setPortStatus (hci_t * hci, __u16 bitPos);
+static void setPortChange (hci_t * hci, __u16 bitPos);
+static void clrPortStatus (hci_t * hci, __u16 bitPos);
+static void clrPortChange (hci_t * hci, __u16 bitPos);
+static int USBReset (hci_t * hci);
+static int cc_to_error (int cc);
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub 
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] = {
+	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x10,			/*  __u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] = {
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes; 
+				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 
+				   4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+	/* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x02,			/*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+	0x00,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+/***************************************************************************
+ * Function Name : rh_send_irq
+ * 
+ * This function examine the port change in the virtual root hub.
+ * 
+ * Note: This function assumes only one port exist in the root hub.
+ *
+ * Input:  hci = data structure for the host controller
+ *         rh_data = The pointer to port change data
+ *         rh_len = length of the data in bytes
+ *
+ * Return: length of data  
+ **************************************************************************/
+static int rh_send_irq (hci_t * hci, void *rh_data, int rh_len)
+{
+	int num_ports;
+	int i;
+	int ret;
+	int len;
+	__u8 data[8];
+
+	DBGFUNC ("enter rh_send_irq: \n");
+
+	/* Assuming the root hub has one port.  This value need to change if
+	 * there are more than one port for the root hub
+	 */
+
+	num_ports = 1;
+
+	/* The root hub status is not implemented, it basically has two fields:
+	 *     -- Local Power Status
+	 *     -- Over Current Indicator
+	 *     -- Local Power Change
+	 *     -- Over Current Indicator
+	 *
+	 * Right now, It is assume the power is good and no changes 
+	 */
+
+	*(__u8 *) data = 0;
+
+	ret = *(__u8 *) data;
+
+	/* Has the port status change within the root hub: It checks for
+	 *      -- Port Connect Status change
+	 *      -- Port Enable Change
+	 */
+
+	for (i = 0; i < num_ports; i++) {
+		*(__u8 *) (data + (i + 1) / 8) |=
+		    (((getPortStatusAndChange (hci) >> 16) & (PORT_CONNECT_STAT | PORT_ENABLE_STAT)) ? 1 : 0) << ((i + 1) % 8);
+		ret += *(__u8 *) (data + (i + 1) / 8);
+
+		/* After the port change is read, it should be reset so the next time 
+		 * is it doesn't trigger a change again */
+
+	}
+	len = i / 8 + 1;
+
+	if (ret > 0) {
+		memcpy (rh_data, data, min (len, min (rh_len, (int)sizeof (data))));
+		return len;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_int_timer_do
+ * 
+ * This function is called when the timer expires.  It gets the the port 
+ * change data and pass along to the upper protocol.
+ * 
+ * Note:  The virtual root hub interrupt pipe are polled by the timer
+ *        every "interval" ms
+ *
+ * Input:  ptr = ptr to the urb
+ *
+ * Return: none  
+ **************************************************************************/
+static void rh_int_timer_do (unsigned long ptr)
+{
+	int len;
+	struct urb *urb = (struct urb *) ptr;
+	hci_t *hci = urb->dev->bus->hcpriv;
+
+	DBGFUNC ("enter rh_int_timer_do\n");
+
+	if (hci->rh.send) {
+		len = rh_send_irq (hci, urb->transfer_buffer,
+				   urb->transfer_buffer_length);
+		if (len > 0) {
+			urb->actual_length = len;
+			if (urb_debug == 2)
+				urb_print (urb, "RET-t(rh)",
+					   usb_pipeout (urb->pipe));
+
+			if (urb->complete) {
+				urb->complete (urb);
+			}
+		}
+	}
+
+	/* re-activate the timer */
+	rh_init_int_timer (urb);
+}
+
+/***************************************************************************
+ * Function Name : rh_init_int_timer
+ * 
+ * This function creates a timer that act as interrupt pipe in the
+ * virtual hub.   
+ * 
+ * Note:  The virtual root hub's interrupt pipe are polled by the timer
+ *        every "interval" ms
+ *
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_init_int_timer (struct urb * urb)
+{
+	hci_t *hci = urb->dev->bus->hcpriv;
+	hci->rh.interval = urb->interval;
+
+	init_timer (&hci->rh.rh_int_timer);
+	hci->rh.rh_int_timer.function = rh_int_timer_do;
+	hci->rh.rh_int_timer.data = (unsigned long) urb;
+	hci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+	add_timer (&hci->rh.rh_int_timer);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* helper macro */
+#define OK(x) 			len = (x); break
+
+/***************************************************************************
+ * Function Name : rh_submit_urb
+ * 
+ * This function handles all USB request to the the virtual root hub
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_submit_urb (struct urb * urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	hci_t *hci = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = TD_CC_NOERROR;
+	__u32 datab[4];
+	__u8 *data_buf = (__u8 *) datab;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	DBGFUNC ("enter rh_submit_urb\n");
+	if (usb_pipeint (pipe)) {
+		hci->rh.urb = urb;
+		hci->rh.send = 1;
+		hci->rh.interval = urb->interval;
+		rh_init_int_timer (urb);
+		urb->status = cc_to_error (TD_CC_NOERROR);
+
+		return 0;
+	}
+
+	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue = le16_to_cpu (cmd->wValue);
+	wIndex = le16_to_cpu (cmd->wIndex);
+	wLength = le16_to_cpu (cmd->wLength);
+
+	DBG ("rh_submit_urb, req = %d(%x) len=%d",
+	     bmRType_bReq, bmRType_bReq, wLength);
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device, 
+		   RH_INTERFACE: interface, 
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here, 
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+		 */
+
+	case RH_GET_STATUS:
+		*(__u16 *) data_buf = cpu_to_le16 (1);
+		OK (2);
+
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *) data_buf = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *) data_buf = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *) data_buf = cpu_to_le32 (0);
+		OK (4);
+
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		*(__u32 *) data_buf =
+		    cpu_to_le32 (getPortStatusAndChange (hci));
+		OK (4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case (RH_ENDPOINT_STALL):
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case RH_C_HUB_LOCAL_POWER:
+			OK (0);
+
+		case (RH_C_HUB_OVER_CURRENT):
+			/* Over Current Not Implemented */
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):
+			clrPortStatus (hci, PORT_ENABLE_STAT);
+			OK (0);
+
+		case (RH_PORT_SUSPEND):
+			clrPortStatus (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_PORT_POWER):
+			clrPortStatus (hci, PORT_POWER_STAT);
+			OK (0);
+
+		case (RH_C_PORT_CONNECTION):
+			clrPortChange (hci, PORT_CONNECT_STAT);
+			OK (0);
+
+		case (RH_C_PORT_ENABLE):
+			clrPortChange (hci, PORT_ENABLE_STAT);
+			OK (0);
+
+		case (RH_C_PORT_SUSPEND):
+			clrPortChange (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_C_PORT_OVER_CURRENT):
+			clrPortChange (hci, PORT_OVER_CURRENT_STAT);
+			OK (0);
+
+		case (RH_C_PORT_RESET):
+			clrPortChange (hci, PORT_RESET_STAT);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			setPortStatus (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_PORT_RESET):
+			setPortStatus (hci, PORT_RESET_STAT);
+			// USBReset(hci);
+			clrPortChange (hci,
+				       PORT_CONNECT_CHANGE | PORT_ENABLE_CHANGE
+				       | PORT_SUSPEND_CHANGE |
+				       PORT_OVER_CURRENT_CHANGE);
+			setPortChange (hci, PORT_RESET_CHANGE);
+			clrPortStatus (hci, PORT_RESET_STAT);
+			setPortStatus (hci, PORT_ENABLE_STAT);
+
+			OK (0);
+
+		case (RH_PORT_POWER):
+			setPortStatus (hci, PORT_POWER_STAT);
+			OK (0);
+
+		case (RH_PORT_ENABLE):
+			setPortStatus (hci, PORT_ENABLE_STAT);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		hci->rh.devnum = wValue;
+		OK (0);
+
+	case RH_GET_DESCRIPTOR:
+		DBGVERBOSE ("rh_submit_urb: RH_GET_DESCRIPTOR, wValue = 0x%x\n", wValue);
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01):	/* device descriptor */
+			len = min (leni, min ((__u16)sizeof (root_hub_dev_des), wLength));
+			data_buf = root_hub_dev_des;
+			OK (len);
+
+		case (0x02):	/* configuration descriptor */
+			len = min (leni, min ((__u16)sizeof (root_hub_config_des), wLength));
+			data_buf = root_hub_config_des;
+			OK (len);
+
+		case (0x03):	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff, (int) (long) 0,
+						   "SL811HS", data, wLength);
+			if (len > 0) {
+				data_buf = data;
+				OK (min (leni, len));
+			}
+
+		default:
+			status = SL11H_STATMASK_STALL;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		data_buf[0] = 9;	// min length;
+		data_buf[1] = 0x29;
+		data_buf[2] = 1;	// # of downstream port
+		data_buf[3] = 0;
+		datab[1] = 0;
+		data_buf[5] = 50;	// 100 ms for port reset
+		data_buf[7] = 0xfc;	// which port is attachable
+		if (data_buf[2] < 7) {
+			data_buf[8] = 0xff;
+		} else {
+		}
+
+		len = min (leni, min ((__u16)data_buf[0], wLength));
+		OK (len);
+
+	case RH_GET_CONFIGURATION:
+		*(__u8 *) data_buf = 0x01;
+		OK (1);
+
+	case RH_SET_CONFIGURATION:
+		OK (0);
+
+	default:
+		DBGERR ("unsupported root hub command");
+		status = SL11H_STATMASK_STALL;
+	}
+
+	len = min (len, leni);
+	if (data != data_buf)
+		memcpy (data, data_buf, len);
+	urb->actual_length = len;
+	urb->status = cc_to_error (status);
+
+	urb->hcpriv = NULL;
+	urb->dev = NULL;
+	if (urb->complete) {
+		urb->complete (urb);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_unlink_urb
+ * 
+ * This function unlinks the URB 
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_unlink_urb (struct urb * urb)
+{
+	hci_t *hci = urb->dev->bus->hcpriv;
+
+	DBGFUNC ("enter rh_unlink_urb\n");
+	if (hci->rh.urb == urb) {
+		hci->rh.send = 0;
+		del_timer (&hci->rh.rh_int_timer);
+		hci->rh.urb = NULL;
+
+		urb->hcpriv = NULL;
+		usb_put_dev (urb->dev);
+		urb->dev = NULL;
+		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+			urb->status = -ECONNRESET;
+			if (urb->complete) {
+				urb->complete (urb);
+			}
+		} else
+			urb->status = -ENOENT;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_connect_rh
+ * 
+ * This function connect the virtual root hub to the USB stack 
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_connect_rh (hci_t * hci)
+{
+	struct usb_device *usb_dev;
+
+	hci->rh.devnum = 0;
+	usb_dev = usb_alloc_dev (NULL, hci->bus);
+	if (!usb_dev)
+		return -ENOMEM;
+
+	hci->bus->root_hub = usb_dev;
+	usb_connect (usb_dev);
+	if (usb_new_device (usb_dev) != 0) {
+		usb_free_dev (usb_dev);
+		return -ENODEV;
+	}
+
+	return 0;
+}
diff -urN linux-2.4.20-pre1/drivers/usb/hcd/ehci-q.c linux-2.4.20-pre2/drivers/usb/hcd/ehci-q.c
--- linux-2.4.20-pre1/drivers/usb/hcd/ehci-q.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/hcd/ehci-q.c	Mon Aug 12 16:34:16 2002
@@ -368,7 +368,7 @@
 		/* SETUP for control urb? */
 		if (unlikely (QTD_PID (token) == 2))
 			pci_unmap_single (ehci->hcd.pdev,
-				qtd->buf_dma, sizeof (devrequest),
+				qtd->buf_dma, sizeof (struct usb_ctrlrequest),
 				PCI_DMA_TODEVICE);
 	}
 
@@ -419,7 +419,7 @@
 			 */
 			if (!unmapped++ && usb_pipecontrol (urb->pipe)) {
 				direction = PCI_DMA_TODEVICE;
-				size = sizeof (devrequest);
+				size = sizeof (struct usb_ctrlrequest);
 			} else {
 				direction = usb_pipein (urb->pipe)
 					? PCI_DMA_FROMDEVICE
@@ -470,13 +470,13 @@
 		qtd->buf_dma = pci_map_single (
 					ehci->hcd.pdev,
 					urb->setup_packet,
-					sizeof (devrequest),
+					sizeof (struct usb_ctrlrequest),
 					PCI_DMA_TODEVICE);
 		if (unlikely (!qtd->buf_dma))
 			goto cleanup;
 
 		/* SETUP pid */
-		qtd_fill (qtd, qtd->buf_dma, sizeof (devrequest),
+		qtd_fill (qtd, qtd->buf_dma, sizeof (struct usb_ctrlrequest),
 			token | (2 /* "setup" */ << 8));
 
 		/* ... and always at least one more pid */
diff -urN linux-2.4.20-pre1/drivers/usb/hcd/ehci-sched.c linux-2.4.20-pre2/drivers/usb/hcd/ehci-sched.c
--- linux-2.4.20-pre1/drivers/usb/hcd/ehci-sched.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/hcd/ehci-sched.c	Mon Aug 12 16:34:16 2002
@@ -881,7 +881,7 @@
 	unsigned long	flags
 ) {
 	struct urb				*urb = itd->urb;
-	iso_packet_descriptor_t			*desc;
+	struct iso_packet_descriptor		*desc;
 	u32					t;
 
 	/* update status for this uframe's transfers */
diff -urN linux-2.4.20-pre1/drivers/usb/hcd.c linux-2.4.20-pre2/drivers/usb/hcd.c
--- linux-2.4.20-pre1/drivers/usb/hcd.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/hcd.c	Mon Aug 12 16:34:16 2002
@@ -316,16 +316,16 @@
 /* Root hub control transfers execute synchronously */
 static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 {
-	devrequest	*cmd = (devrequest *) urb->setup_packet;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
  	u16		typeReq, wValue, wIndex, wLength;
 	const u8	*bufp = 0;
 	u8		*ubuf = urb->transfer_buffer;
 	int		len = 0;
 
-	typeReq  = (cmd->requesttype << 8) | cmd->request;
-	wValue   = le16_to_cpu (cmd->value);
-	wIndex   = le16_to_cpu (cmd->index);
-	wLength  = le16_to_cpu (cmd->length);
+	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
+	wValue   = le16_to_cpu (cmd->wValue);
+	wIndex   = le16_to_cpu (cmd->wIndex);
+	wLength  = le16_to_cpu (cmd->wLength);
 
 	if (wLength > urb->transfer_buffer_length)
 		goto error;
diff -urN linux-2.4.20-pre1/drivers/usb/hid-core.c linux-2.4.20-pre2/drivers/usb/hid-core.c
--- linux-2.4.20-pre1/drivers/usb/hid-core.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/hid-core.c	Mon Aug 12 16:34:16 2002
@@ -988,7 +988,7 @@
 
 static int hid_submit_out(struct hid_device *hid)
 {
-	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length);
+	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.wLength);
 	hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;
 	hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
 	hid->urbout.dev = hid->dev;
@@ -1018,8 +1018,8 @@
 {
 	hid_output_report(report, hid->out[hid->outhead].buffer);
 
-	hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | report->id);
-	hid->out[hid->outhead].dr.length = cpu_to_le16((report->size + 7) >> 3);
+	hid->out[hid->outhead].dr.wValue = cpu_to_le16(0x200 | report->id);
+	hid->out[hid->outhead].dr.wLength = cpu_to_le16((report->size + 7) >> 3);
 
 	hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
 
@@ -1204,9 +1204,9 @@
 	hid->ifnum = interface->bInterfaceNumber;
 
 	for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {
-		hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-		hid->out[n].dr.request = USB_REQ_SET_REPORT;
-		hid->out[n].dr.index = cpu_to_le16(hid->ifnum);
+		hid->out[n].dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+		hid->out[n].dr.bRequest = USB_REQ_SET_REPORT;
+		hid->out[n].dr.wIndex = cpu_to_le16(hid->ifnum);
 	}
 
 	hid->name[0] = 0;
diff -urN linux-2.4.20-pre1/drivers/usb/hid.h linux-2.4.20-pre2/drivers/usb/hid.h
--- linux-2.4.20-pre1/drivers/usb/hid.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-pre2/drivers/usb/hid.h	Mon Aug 12 16:34:16 2002
@@ -287,7 +287,7 @@
 #define HID_CONTROL_FIFO_SIZE	8
 
 struct hid_control_fifo {
-	devrequest dr;
+	struct usb_ctrlrequest dr;
 	char buffer[HID_BUFFER_SIZE];
 };
 
diff -urN linux-2.4.20-pre1/drivers/usb/kaweth.c linux-2.4.20-pre2/drivers/usb/kaweth.c
--- linux-2.4.20-pre1/drivers/usb/kaweth.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/kaweth.c	Mon Aug 12 16:34:16 2002
@@ -110,7 +110,7 @@
 	);
 static void kaweth_disconnect(struct usb_device *dev, void *ptr);
 int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
-				devrequest *cmd, void *data, int len,
+				struct usb_ctrlrequest *cmd, void *data, int len,
 				int timeout);
 
 /****************************************************************
@@ -230,7 +230,7 @@
 			  __u16 size, 
 			  int timeout)
 {
-	devrequest *dr;
+	struct usb_ctrlrequest *dr;
 
 	kaweth_dbg("kaweth_control()");
 
@@ -239,7 +239,7 @@
 		return -EBUSY;
 	}
 
-	dr = kmalloc(sizeof(devrequest), GFP_ATOMIC);
+	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
 
 	if(!dr)
 	{
@@ -247,11 +247,11 @@
 		return -ENOMEM;
 	}
 	
-	dr->requesttype = requesttype;
-	dr->request = request;
-	dr->value = cpu_to_le16p(&value);
-	dr->index = cpu_to_le16p(&index);
-	dr->length = cpu_to_le16p(&size);
+	dr->bRequestType = requesttype;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16p(&value);
+	dr->wIndex = cpu_to_le16p(&index);
+	dr->wLength = cpu_to_le16p(&size);
 
 	return kaweth_internal_control_msg(kaweth->dev,
 					pipe,
@@ -948,7 +948,7 @@
 /*-------------------------------------------------------------------*
  * completion handler for compatibility wrappers (sync control/bulk) *
  *-------------------------------------------------------------------*/
-static void usb_api_blocking_completion(urb_t *urb)
+static void usb_api_blocking_completion(struct urb *urb)
 {
         struct usb_api_data *awd = (struct usb_api_data *)urb->context;
 
@@ -961,7 +961,7 @@
  *-------------------------------------------------------------------*/
 
 // Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
 {
         DECLARE_WAITQUEUE(wait, current);
 	struct usb_api_data awd;
@@ -1009,9 +1009,9 @@
 /*-------------------------------------------------------------------*/
 // returns status (negative) or length (positive)
 int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
-                            devrequest *cmd,  void *data, int len, int timeout)
+                            struct usb_ctrlrequest *cmd,  void *data, int len, int timeout)
 {
-        urb_t *urb;
+        struct urb *urb;
         int retv;
         int length;
 
diff -urN linux-2.4.20-pre1/drivers/usb/mdc800.c linux-2.4.20-pre2/drivers/usb/mdc800.c
--- linux-2.4.20-pre1/drivers/usb/mdc800.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.20-pre2/drivers/usb/mdc800.c	Mon Aug 12 16:34:16 2002
@@ -140,7 +140,7 @@
 
 	unsigned int		endpoint [4];
 
-	purb_t			irq_urb;
+	struct urb *		irq_urb;
 	wait_queue_head_t	irq_wait;
 	int                     irq_woken;
 	char*			irq_urb_buffer;
@@ -149,13 +149,13 @@
 	int 			camera_request_ready; // Status to synchronize with irq
 	char 			camera_response [8];  // last Bytes send after busy
 
-	purb_t   		write_urb;
+	struct urb *   		write_urb;
 	char*			write_urb_buffer;
 	wait_queue_head_t	write_wait;
 	int                     written;
 
 
-	purb_t	   		download_urb;
+	struct urb *		download_urb;
 	char*			download_urb_buffer;
 	wait_queue_head_t	download_wait;
 	int                     downloaded;
diff -urN linux-2.4.20-pre1/drivers/usb/pegasus.c linux-2.4.20-pre2/drivers/usb/pegasus.c
--- linux-2.4.20-pre1/drivers/usb/pegasus.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/pegasus.c	Mon Aug 12 16:34:16 2002
@@ -149,11 +149,11 @@
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
-	pegasus->dr.requesttype = PEGASUS_REQT_READ;
-	pegasus->dr.request = PEGASUS_REQ_GET_REGS;
-	pegasus->dr.value = cpu_to_le16 (0);
-	pegasus->dr.index = cpu_to_le16p(&indx);
-	pegasus->dr.length = cpu_to_le16p(&size);
+	pegasus->dr.bRequestType = PEGASUS_REQT_READ;
+	pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS;
+	pegasus->dr.wValue = cpu_to_le16 (0);
+	pegasus->dr.wIndex = cpu_to_le16p(&indx);
+	pegasus->dr.wLength = cpu_to_le16p(&size);
 	pegasus->ctrl_urb->transfer_buffer_length = size;
 
 	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
@@ -199,11 +199,11 @@
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
-	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
-	pegasus->dr.request = PEGASUS_REQ_SET_REGS;
-	pegasus->dr.value = cpu_to_le16 (0);
-	pegasus->dr.index = cpu_to_le16p( &indx );
-	pegasus->dr.length = cpu_to_le16p( &size );
+	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
+	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
+	pegasus->dr.wValue = cpu_to_le16 (0);
+	pegasus->dr.wIndex = cpu_to_le16p( &indx );
+	pegasus->dr.wLength = cpu_to_le16p( &size );
 	pegasus->ctrl_urb->transfer_buffer_length = size;
 
 	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
@@ -249,11 +249,11 @@
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_RUNNING);
 
-	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
-	pegasus->dr.request = PEGASUS_REQ_SET_REG;
-	pegasus->dr.value = cpu_to_le16p( &dat);
-	pegasus->dr.index = cpu_to_le16p( &indx );
-	pegasus->dr.length = cpu_to_le16( 1 );
+	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
+	pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
+	pegasus->dr.wValue = cpu_to_le16p( &dat);
+	pegasus->dr.wIndex = cpu_to_le16p( &indx );
+	pegasus->dr.wLength = cpu_to_le16( 1 );
 	pegasus->ctrl_urb->transfer_buffer_length = 1;
 
 	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
@@ -282,11 +282,11 @@
 {
 	int	ret;
 
-	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
-	pegasus->dr.request = PEGASUS_REQ_SET_REGS;
-	pegasus->dr.value = 0;
-	pegasus->dr.index =  cpu_to_le16(EthCtrl0);
-	pegasus->dr.length = cpu_to_le16(3);
+	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
+	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
+	pegasus->dr.wValue = 0;
+	pegasus->dr.wIndex =  cpu_to_le16(EthCtrl0);
+	pegasus->dr.wLength = cpu_to_le16(3);
 	pegasus->ctrl_urb->transfer_buffer_length = 3;
 
 	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
diff -urN linux-2.4.20-pre1/drivers/usb/pegasus.h linux-2.4.20-pre2/drivers/usb/pegasus.h
--- linux-2.4.20-pre1/drivers/usb/pegasus.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/pegasus.h	Mon Aug 12 16:34:16 2002
@@ -99,7 +99,7 @@
 	int			dev_index;
 	int			intr_interval;
 	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
-	devrequest		dr;
+	struct usb_ctrlrequest	dr;
 	wait_queue_head_t	ctrl_wait;
 	struct semaphore	sem;
 	unsigned char		rx_buff[PEGASUS_MAX_MTU];
diff -urN linux-2.4.20-pre1/drivers/usb/rtl8150.c linux-2.4.20-pre2/drivers/usb/rtl8150.c
--- linux-2.4.20-pre1/drivers/usb/rtl8150.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/rtl8150.c	Mon Aug 12 16:34:16 2002
@@ -91,7 +91,7 @@
 	struct net_device_stats	stats;
 	struct net_device	*netdev;
 	struct urb		*rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
-	devrequest		dr;
+	struct usb_ctrlrequest	dr;
 	int			intr_interval;
 	u16			rx_creg;
 	u8			rx_buff[RTL8150_MAX_MTU];
@@ -169,11 +169,11 @@
 	if (test_bit(RX_REG_SET, &dev->flags))
 		return -EAGAIN;
 	
-	dev->dr.requesttype = RTL8150_REQT_WRITE;
-	dev->dr.request = RTL8150_REQ_SET_REGS;
-	dev->dr.value = cpu_to_le16(indx);
-	dev->dr.index = 0;
-	dev->dr.length = cpu_to_le16(2);
+	dev->dr.bRequestType = RTL8150_REQT_WRITE;
+	dev->dr.bRequest = RTL8150_REQ_SET_REGS;
+	dev->dr.wValue = cpu_to_le16(indx);
+	dev->dr.wIndex = 0;
+	dev->dr.wLength = cpu_to_le16(2);
 	dev->ctrl_urb->transfer_buffer_length = 2;
 	FILL_CONTROL_URB(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev,0),
 	                 (char*)&dev->dr, &dev->rx_creg, 2, ctrl_callback, dev);
diff -urN linux-2.4.20-pre1/drivers/usb/scanner.c linux-2.4.20-pre2/drivers/usb/scanner.c
--- linux-2.4.20-pre1/drivers/usb/scanner.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/drivers/usb/scanner.c	Mon Aug 12 16:34:16 2002
@@ -747,7 +747,7 @@
  	case SCANNER_IOCTL_CTRLMSG:
  	{
  		struct ctrlmsg_ioctl {
- 			devrequest	req;
+ 			struct usb_ctrlrequest	req;
  			void		*data;
  		} cmsg;
  		int pipe, nb, ret;
@@ -756,12 +756,12 @@
  		if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
  			return -EFAULT;
 
- 		nb = le16_to_cpup(&cmsg.req.length);
+ 		nb = le16_to_cpup(&cmsg.req.wLength);
 
  		if (nb > sizeof(buf))
  			return -EINVAL;
 
- 		if ((cmsg.req.requesttype & 0x80) == 0) {
+ 		if ((cmsg.req.bRequestType & 0x80) == 0) {
  			pipe = usb_sndctrlpipe(dev, 0);
  			if (nb > 0 && copy_from_user(buf, cmsg.data, nb))
  				return -EFAULT;
@@ -769,10 +769,10 @@
  			pipe = usb_rcvctrlpipe(dev, 0);
 		}
 
- 		ret = usb_control_msg(dev, pipe, cmsg.req.request,
- 				      cmsg.req.requesttype,
- 				      le16_to_cpup(&cmsg.req.value),
- 				      le16_to_cpup(&cmsg.req.index),
+ 		ret = usb_control_msg(dev, pipe, cmsg.req.bRequest,
+ 				      cmsg.req.bRequestType,
+ 				      le16_to_cpup(&cmsg.req.wValue),
+ 				      le16_to_cpup(&cmsg.req.wIndex),
  				      buf, nb, HZ);
 
  		if (ret < 0) {
@@ -780,7 +780,7 @@
  			return -EIO;
  		}
 
- 		if (nb > 0 && (cmsg.req.requesttype & 0x80) && copy_to_user(cmsg.data, buf, nb))
+ 		if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
  			return -EFAULT;
 
  		return 0;
diff -urN linux-2.4.20-pre1/drivers/usb/scanner.h linux-2.4.20-pre2/drivers/usb/scanner.h
--- linux-2.4.20-pre1/drivers/usb/scanner.h	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/drivers/usb/scanner.h	Mon Aug 12 16:34:16 2002
@@ -230,7 +230,7 @@
 #define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
 #define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
 /* send/recv a control message to the scanner */
-#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, devrequest )
+#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest )
 
 
 #define SCN_MAX_MNR 16		/* We're allocated 16 minors */
diff -urN linux-2.4.20-pre1/drivers/usb/se401.c linux-2.4.20-pre2/drivers/usb/se401.c
--- linux-2.4.20-pre1/drivers/usb/se401.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/se401.c	Mon Aug 12 16:34:16 2002
@@ -610,7 +610,7 @@
 */
 static int se401_start_stream(struct usb_se401 *se401)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int err=0, i;
 	se401->streaming=1;
 
diff -urN linux-2.4.20-pre1/drivers/usb/se401.h linux-2.4.20-pre2/drivers/usb/se401.h
--- linux-2.4.20-pre1/drivers/usb/se401.h	Fri Sep  7 10:59:04 2001
+++ linux-2.4.20-pre2/drivers/usb/se401.h	Mon Aug 12 16:34:16 2002
@@ -197,8 +197,8 @@
 
 	char *fbuf;		/* Videodev buffer area */
 
-	urb_t *urb[SE401_NUMSBUF];
-	urb_t *inturb;
+	struct urb *urb[SE401_NUMSBUF];
+	struct urb *inturb;
 	
 	int button;
 	int buttonpressed;
diff -urN linux-2.4.20-pre1/drivers/usb/serial/Config.in linux-2.4.20-pre2/drivers/usb/serial/Config.in
--- linux-2.4.20-pre1/drivers/usb/serial/Config.in	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/serial/Config.in	Mon Aug 12 16:34:16 2002
@@ -18,6 +18,7 @@
 dep_tristate '  USB Compaq iPAQ / HP Jornada / Casio EM500 Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
 dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Inside Out Edgeport Serial Driver (TI devices)' CONFIG_USB_SERIAL_EDGEPORT_TI $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
    dep_mbool '    USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28 $CONFIG_USB_SERIAL_KEYSPAN
diff -urN linux-2.4.20-pre1/drivers/usb/serial/Makefile linux-2.4.20-pre2/drivers/usb/serial/Makefile
--- linux-2.4.20-pre1/drivers/usb/serial/Makefile	Mon Feb 25 11:38:07 2002
+++ linux-2.4.20-pre2/drivers/usb/serial/Makefile	Mon Aug 12 16:34:16 2002
@@ -20,6 +20,7 @@
 obj-$(CONFIG_USB_SERIAL_EMPEG)			+= empeg.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
 obj-$(CONFIG_USB_SERIAL_EDGEPORT)		+= io_edgeport.o
+obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI)		+= io_ti.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
diff -urN linux-2.4.20-pre1/drivers/usb/serial/io_edgeport.c linux-2.4.20-pre2/drivers/usb/serial/io_edgeport.c
--- linux-2.4.20-pre1/drivers/usb/serial/io_edgeport.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/serial/io_edgeport.c	Mon Aug 12 16:34:16 2002
@@ -2472,7 +2472,7 @@
 {
 	struct edgeport_serial *edge_serial = (struct edgeport_serial *)edge_port->port->serial->private;
 	int status = 0;
-	urb_t *urb;
+	struct urb *urb;
 	int timeout;
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
diff -urN linux-2.4.20-pre1/drivers/usb/serial/io_fw_down3.h linux-2.4.20-pre2/drivers/usb/serial/io_fw_down3.h
--- linux-2.4.20-pre1/drivers/usb/serial/io_fw_down3.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/serial/io_fw_down3.h	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,799 @@
+//**************************************************************
+//* Edgeport Binary Image (for TI based products)
+//* Generated by TIBin2C v1.00
+//* Copyright(c) 2001 Inside Out Networks, All rights reserved.
+//**************************************************************
+
+
+static int IMAGE_SIZE = 12166;
+
+typedef struct _EDGE_FIRMWARE_VERSION_INFO
+{
+	unsigned char   MajorVersion;
+	unsigned char   MinorVersion;
+	unsigned short  BuildNumber;
+} EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO;
+
+static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME =
+{
+	4, 1, 0		// Major, Minor, Build
+
+};
+
+static unsigned char IMAGE_ARRAY_NAME[] = 
+{
+//  struct ImageHdr
+//  {
+//      WORD    Length;
+//      BYTE    CheckSum;
+//  };
+0x83, 0x2f, 
+0x33, 
+
+0x02, 0x24, 0x84, 0x02, 0x1f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x1a, 0x85, 0x45, 
+0x8c, 0x85, 0x46, 0x8a, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 
+0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xe5, 0x44, 
+0x24, 0x08, 0xf8, 0xe6, 0x60, 0x2b, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0xa6, 0x81, 0xe5, 0x44, 0x75, 
+0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0x78, 0x92, 0xe5, 0x81, 
+0x04, 0xc3, 0x98, 0xf9, 0x94, 0x22, 0x40, 0x03, 0x02, 0x11, 0x1a, 0xe6, 0xf0, 0x08, 0xa3, 0xd9, 
+0xfa, 0x74, 0x08, 0x25, 0x44, 0xf8, 0x05, 0x44, 0x08, 0xe6, 0x54, 0x80, 0x70, 0x0c, 0xe5, 0x44, 
+0xb4, 0x07, 0xf3, 0x78, 0x08, 0x75, 0x44, 0x00, 0x80, 0xef, 0xe5, 0x44, 0x24, 0x10, 0xf8, 0x86, 
+0x81, 0xe5, 0x44, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 
+0x78, 0x92, 0xe5, 0x81, 0x04, 0xc3, 0x98, 0xf9, 0xe0, 0xf6, 0x08, 0xa3, 0xd9, 0xfa, 0xd0, 0x07, 
+0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 
+0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x30, 0x01, 0x4d, 0x30, 0xb4, 0x48, 0x10, 
+0x00, 0x45, 0x90, 0xff, 0x08, 0xe0, 0x54, 0x20, 0xf8, 0x90, 0xff, 0x48, 0xe0, 0x54, 0x20, 0xf9, 
+0x90, 0xff, 0x10, 0xe0, 0x54, 0x20, 0xfa, 0x90, 0xff, 0x50, 0xe0, 0x54, 0x20, 0xfb, 0x74, 0x00, 
+0xf5, 0x82, 0x74, 0xf8, 0xf5, 0x83, 0xe0, 0xc8, 0xf0, 0x68, 0x60, 0x02, 0x7e, 0x04, 0xa3, 0xe0, 
+0xc9, 0xf0, 0x69, 0x60, 0x02, 0x7e, 0x04, 0xa3, 0xe0, 0xca, 0xf0, 0x6a, 0x60, 0x02, 0x7e, 0x04, 
+0xa3, 0xe0, 0xcb, 0xf0, 0x6b, 0x60, 0x02, 0x7e, 0x04, 0x22, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 
+0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 
+0xc0, 0x06, 0xc0, 0x07, 0x90, 0xff, 0x93, 0x74, 0x01, 0xf0, 0xe5, 0x81, 0x94, 0xfd, 0x40, 0x03, 
+0x02, 0x11, 0x1a, 0x85, 0x47, 0x8d, 0x85, 0x48, 0x8b, 0x74, 0xae, 0xf5, 0x82, 0x74, 0xfa, 0xf5, 
+0x83, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x4a, 0xe0, 0x30, 0xe7, 0x2c, 
+0x90, 0xff, 0x4e, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, 
+0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, 
+0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, 
+0xa3, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x52, 0xe0, 0x30, 0xe7, 0x2c, 
+0x90, 0xff, 0x56, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, 
+0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x25, 
+0x13, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, 
+0x20, 0x02, 0x03, 0x30, 0x01, 0x7b, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x14, 
+0xfc, 0xf0, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0x64, 0x04, 0x70, 0x0f, 0xec, 0x70, 0x62, 0x7e, 
+0x01, 0x12, 0x00, 0xc9, 0x7c, 0x0a, 0x7d, 0xfa, 0x02, 0x02, 0x22, 0x12, 0x00, 0xc9, 0xee, 0x64, 
+0x04, 0x60, 0x1d, 0xec, 0x70, 0x4b, 0x7c, 0x0a, 0xed, 0x14, 0xfd, 0x70, 0x15, 0xee, 0x64, 0x02, 
+0x60, 0x07, 0x7e, 0x02, 0x7d, 0x32, 0x02, 0x02, 0x22, 0x7e, 0x01, 0x7d, 0xfa, 0x02, 0x02, 0x22, 
+0x7c, 0x0a, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 
+0xee, 0xf0, 0x14, 0x60, 0x18, 0x20, 0xe1, 0x0f, 0x20, 0x01, 0x06, 0xd2, 0xb1, 0xc2, 0xb0, 0x80, 
+0x10, 0xc2, 0xb1, 0xd2, 0xb0, 0x80, 0x0a, 0xc2, 0xb1, 0xc2, 0xb0, 0x80, 0x04, 0xd2, 0xb0, 0xd2, 
+0xb1, 0x78, 0x19, 0x79, 0x09, 0x7a, 0x07, 0xe7, 0x70, 0x04, 0xa6, 0x00, 0x80, 0x0b, 0xe6, 0x60, 
+0x08, 0x16, 0xe6, 0x70, 0x04, 0xe7, 0x44, 0x80, 0xf7, 0x08, 0x09, 0xda, 0xea, 0xe5, 0x43, 0x60, 
+0x13, 0x14, 0xf5, 0x43, 0x70, 0x0e, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x10, 0x95, 
+0xd2, 0x8c, 0xd2, 0x8d, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 
+0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x90, 
+0xff, 0x04, 0xe0, 0x90, 0xfa, 0xb5, 0xf0, 0x90, 0xff, 0x06, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, 
+0xff, 0xea, 0xfe, 0xef, 0xc3, 0x94, 0x08, 0xee, 0x94, 0x01, 0x50, 0x02, 0x80, 0x04, 0x7e, 0x01, 
+0x7f, 0x08, 0x8e, 0x34, 0x8f, 0x35, 0x90, 0xff, 0x02, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, 0xff, 
+0xea, 0x90, 0xfa, 0xb9, 0xf0, 0xef, 0xa3, 0xf0, 0x12, 0x18, 0x49, 0x78, 0x24, 0x7c, 0x00, 0x7d, 
+0x00, 0x12, 0x19, 0x6c, 0x7e, 0x00, 0x7f, 0x05, 0x12, 0x13, 0x8f, 0xe4, 0xf5, 0x53, 0xe5, 0x53, 
+0xc3, 0x94, 0x02, 0x50, 0x0f, 0x12, 0x18, 0x2a, 0xe4, 0x12, 0x13, 0xfb, 0x05, 0x53, 0x04, 0x12, 
+0x18, 0x1b, 0x80, 0xea, 0x12, 0x18, 0x49, 0x90, 0xff, 0x00, 0xe0, 0xff, 0x54, 0x60, 0x24, 0xc0, 
+0x70, 0x03, 0x02, 0x08, 0xb8, 0x24, 0x40, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 
+0xfe, 0x54, 0x0f, 0xf5, 0x53, 0xee, 0x30, 0xe7, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0a, 0x90, 
+0xff, 0x01, 0xe0, 0x12, 0x15, 0x0f, 0x03, 0x55, 0x00, 0x04, 0x28, 0x01, 0x05, 0x2f, 0x03, 0x05, 
+0xf6, 0x05, 0x06, 0x38, 0x06, 0x07, 0x9a, 0x08, 0x07, 0xe2, 0x09, 0x08, 0x3e, 0x0a, 0x08, 0x7e, 
+0x0b, 0x00, 0x00, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 
+0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x02, 0x45, 0x34, 
+0x60, 0x03, 0x02, 0x0e, 0xac, 0xef, 0x54, 0x1f, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x47, 0x24, 0x02, 
+0x60, 0x03, 0x02, 0x0e, 0xac, 0xee, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0x2a, 0x74, 0x01, 
+0x12, 0x13, 0xfb, 0x78, 0x6d, 0xe6, 0x30, 0xe0, 0x08, 0x12, 0x18, 0x2a, 0x74, 0x02, 0x12, 0x13, 
+0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x09, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 
+0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 
+0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x0e, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x60, 
+0x07, 0x64, 0x80, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, 
+0xe5, 0x53, 0x70, 0x19, 0x30, 0x0a, 0x0b, 0x90, 0xff, 0x80, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, 
+0x80, 0x24, 0x90, 0xff, 0x82, 0x12, 0x18, 0x27, 0x12, 0x13, 0xfb, 0x80, 0x19, 0x15, 0x53, 0x30, 
+0x0a, 0x0b, 0x12, 0x18, 0xbd, 0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x80, 0x09, 0x12, 0x18, 0xcb, 
+0x12, 0x18, 0x25, 0x12, 0x13, 0xfb, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0x60, 0x05, 0x74, 0x01, 
+0x12, 0x13, 0xfb, 0x7f, 0x02, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 
+0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, 
+0x60, 0x59, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, 
+0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 
+0xac, 0x78, 0x6d, 0xe6, 0x54, 0xfe, 0xf6, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 
+0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x09, 0x90, 0xfa, 0xb5, 0xe0, 
+0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0c, 0x90, 0xfa, 0xb5, 0xe0, 0xd3, 0x94, 
+0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 
+0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0f, 0x38, 0x40, 0x03, 0x02, 0x0e, 0xac, 
+0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe0, 0x07, 
+0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x0f, 0x90, 0xff, 0x82, 0xe0, 0x54, 
+0xf7, 0xf0, 0x90, 0xff, 0x80, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0xe5, 0x53, 0x24, 0xfe, 0x60, 0x1b, 
+0x04, 0x70, 0x2e, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, 
+0x80, 0x1f, 0xe4, 0xfd, 0x7f, 0x03, 0x12, 0x2a, 0xce, 0x80, 0x16, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 
+0xe4, 0x33, 0xfd, 0x7f, 0x04, 0x12, 0x2a, 0xce, 0x80, 0x07, 0xe4, 0xfd, 0x7f, 0x04, 0x12, 0x2a, 
+0xce, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x80, 
+0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 
+0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 
+0x12, 0x18, 0xd9, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x55, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 
+0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 
+0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x78, 0x6d, 0xe6, 0x44, 0x01, 0xf6, 0xe4, 0xff, 
+0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 
+0x30, 0xe0, 0x07, 0xe5, 0x53, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x0a, 0xe5, 
+0x53, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xfa, 
+0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 
+0x12, 0x2f, 0x3b, 0x40, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 
+0x02, 0x0e, 0xac, 0xe5, 0x53, 0x70, 0x09, 0x30, 0x0a, 0x03, 0x02, 0x19, 0x7a, 0x02, 0x19, 0x3e, 
+0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x15, 0x53, 0x30, 0x0a, 0x0b, 0x12, 0x18, 0xbd, 
+0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0x80, 0x09, 0x12, 0x18, 0xcb, 0xf5, 0x83, 0xe0, 0x44, 0x08, 
+0xf0, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 
+0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 
+0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x30, 0xe1, 0x03, 0x02, 0x0e, 0xac, 
+0x90, 0xfa, 0xba, 0xe0, 0x90, 0xff, 0xff, 0xf0, 0xe0, 0x60, 0x05, 0x43, 0x2c, 0x01, 0x80, 0x03, 
+0x53, 0x2c, 0xfe, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 
+0xe5, 0x35, 0x45, 0x34, 0x70, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 
+0xac, 0x90, 0xfa, 0xb9, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0x24, 0xfe, 0x60, 0x3a, 0x14, 0x60, 
+0x75, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xed, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 
+0x49, 0x12, 0x19, 0x73, 0x7d, 0x03, 0x12, 0x0e, 0xf3, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, 
+0xb0, 0x90, 0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, 
+0x04, 0xae, 0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x18, 0x49, 0x90, 0xf9, 0x65, 0xe0, 0x30, 
+0xe4, 0x0d, 0x12, 0x19, 0x73, 0x7d, 0x14, 0x12, 0x0e, 0xf3, 0x60, 0x10, 0x02, 0x0e, 0xac, 0x12, 
+0x19, 0x73, 0x7d, 0x04, 0x12, 0x0f, 0x47, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x0e, 0xb0, 0x90, 
+0xfa, 0xb2, 0xe0, 0xfd, 0xa3, 0x12, 0x18, 0x93, 0x12, 0x0f, 0x0f, 0x50, 0x02, 0x80, 0x04, 0xae, 
+0x34, 0xaf, 0x35, 0x02, 0x0f, 0x40, 0x12, 0x19, 0x73, 0x7d, 0x05, 0x12, 0x0f, 0x47, 0x60, 0x03, 
+0x02, 0x0e, 0xac, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x12, 0x18, 0x90, 0x7d, 0x01, 0x12, 0x23, 
+0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xba, 0xe0, 0x90, 
+0xfa, 0xb1, 0xf0, 0xe4, 0xf5, 0x52, 0x90, 0xfa, 0xb1, 0xe0, 0xff, 0xe5, 0x52, 0xc3, 0x9f, 0x50, 
+0x24, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0xff, 0xfd, 0x90, 0xfa, 0xb3, 0xe4, 0x8d, 0xf0, 0x12, 
+0x14, 0x2f, 0x90, 0xfa, 0xb2, 0xe0, 0xc3, 0x9f, 0xf0, 0xd3, 0x94, 0x00, 0x50, 0x03, 0x02, 0x0e, 
+0xac, 0x05, 0x52, 0x80, 0xd1, 0x12, 0x18, 0x8a, 0x12, 0x0f, 0x52, 0x24, 0xfe, 0xff, 0x90, 0xfa, 
+0xb2, 0xf0, 0xfd, 0xa3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0x7a, 0xf9, 0x79, 0x6e, 0x7b, 
+0x01, 0x8b, 0x2d, 0x8a, 0x2e, 0x89, 0x2f, 0xe9, 0x24, 0x02, 0xf9, 0xe4, 0x3a, 0xfa, 0x12, 0x18, 
+0x90, 0x12, 0x23, 0xee, 0x8f, 0x52, 0x05, 0x52, 0x05, 0x52, 0x12, 0x18, 0x2a, 0xe5, 0x52, 0x12, 
+0x13, 0xfb, 0x12, 0x18, 0x2a, 0x90, 0x00, 0x01, 0x74, 0x03, 0x12, 0x14, 0x0d, 0xaf, 0x52, 0x7e, 
+0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x50, 0x02, 0x80, 0x04, 0xae, 0x34, 0xaf, 0x35, 
+0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe7, 0x03, 0x02, 
+0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 
+0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 
+0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, 
+0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x75, 0x2d, 0x00, 0x75, 0x2e, 0x00, 0x75, 0x2f, 0x29, 0x02, 
+0x0f, 0x2f, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 
+0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, 0x90, 0xfa, 0xba, 
+0xe0, 0x94, 0x01, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 
+0xd9, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0e, 
+0xac, 0x90, 0xfa, 0xba, 0xe0, 0xf5, 0x29, 0xe5, 0x29, 0x70, 0x08, 0x43, 0x2c, 0x01, 0x53, 0x2c, 
+0xfd, 0x80, 0x06, 0x53, 0x2c, 0xfe, 0x43, 0x2c, 0x02, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 
+0x20, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x64, 0x01, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 
+0xac, 0x90, 0xfa, 0xb5, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x90, 0xfa, 0xb9, 0xe0, 0x70, 0x02, 
+0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0e, 0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 
+0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, 0x02, 0x0e, 0xac, 0x7f, 0x01, 0x02, 0x2f, 0x6a, 0xe5, 0x2c, 
+0x30, 0xe7, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x35, 0x45, 0x34, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xd3, 
+0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x90, 0xfa, 0xb9, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0e, 
+0xac, 0x12, 0x18, 0xd9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0e, 0xac, 0xe5, 0x2c, 0x20, 0xe1, 0x03, 
+0x02, 0x0e, 0xac, 0xe4, 0xff, 0x02, 0x2f, 0x6a, 0x90, 0xff, 0x01, 0x12, 0x19, 0x8a, 0xef, 0x12, 
+0x13, 0xfb, 0x90, 0xfa, 0xb5, 0x12, 0x19, 0x8a, 0x90, 0x00, 0x01, 0xef, 0x12, 0x14, 0x0d, 0x90, 
+0x00, 0x02, 0xe4, 0x12, 0x14, 0x0d, 0x74, 0x03, 0x12, 0x18, 0x1b, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 
+0xa3, 0xe0, 0x85, 0x2f, 0x82, 0x85, 0x2e, 0x83, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xff, 0x01, 
+0xe0, 0x12, 0x15, 0x0f, 0x09, 0x3d, 0x02, 0x09, 0x5f, 0x04, 0x09, 0x81, 0x05, 0x09, 0xad, 0x06, 
+0x09, 0xcb, 0x07, 0x09, 0xe9, 0x08, 0x0a, 0x07, 0x09, 0x0a, 0x25, 0x0b, 0x0a, 0xda, 0x80, 0x0c, 
+0xfa, 0x81, 0x0d, 0x1c, 0x82, 0x0b, 0x21, 0x83, 0x0b, 0x6a, 0x84, 0x0b, 0x89, 0x85, 0x0b, 0xc5, 
+0x86, 0x0c, 0x07, 0x87, 0x0c, 0x95, 0x88, 0x0c, 0xd0, 0x89, 0x0a, 0x43, 0x92, 0x0a, 0x43, 0x93, 
+0x0d, 0xcf, 0xc0, 0x0e, 0x00, 0xc1, 0x0e, 0x11, 0xc2, 0x00, 0x00, 0x0e, 0x9b, 0xe5, 0x2c, 0x20, 
+0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 
+0xfd, 0x7c, 0x00, 0x7f, 0x07, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, 0xc0, 0xe5, 
+0x2c, 0x20, 0xe7, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 
+0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0c, 0x02, 0x10, 0x9c, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2c, 
+0xc0, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x19, 0x99, 0x50, 0x06, 0xe5, 0x35, 
+0x45, 0x34, 0x70, 0x05, 0x7f, 0x02, 0x02, 0x2e, 0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x24, 0xfe, 0x24, 
+0xfd, 0x50, 0x02, 0x80, 0x03, 0x02, 0x2f, 0x28, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 
+0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 
+0x00, 0x7f, 0x08, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 
+0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 
+0x09, 0x02, 0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 
+0xaf, 0x12, 0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0a, 0x02, 
+0x10, 0x9c, 0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 
+0x18, 0xe0, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0b, 0x02, 0x10, 0x9c, 
+0x7f, 0x07, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x03, 0x02, 0x0e, 0xaf, 0x12, 0x18, 0xe0, 
+0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0e, 0x02, 0x10, 0x9c, 0x7f, 0x07, 
+0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x56, 0x12, 0x18, 0xd9, 0x70, 0x4a, 0x90, 0xff, 0x02, 
+0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, 0x80, 0x12, 0xe5, 0x52, 0xb4, 
+0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, 0xf0, 0x04, 0xf5, 0x52, 0x12, 
+0x17, 0x8b, 0x12, 0x19, 0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x05, 
+0x12, 0x2f, 0x76, 0x80, 0x06, 0x85, 0x2a, 0x30, 0x85, 0x2b, 0x31, 0x75, 0x2d, 0x01, 0x75, 0x2e, 
+0xf9, 0x75, 0x2f, 0x71, 0x02, 0x29, 0x2d, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x12, 0x18, 
+0xd9, 0x60, 0x05, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x19, 0x99, 0x40, 0x05, 0x7f, 0x03, 0x02, 
+0x2e, 0xa5, 0x90, 0xff, 0x02, 0xe0, 0xf5, 0x52, 0xe5, 0x52, 0xb4, 0x82, 0x05, 0x75, 0x52, 0x61, 
+0x80, 0x12, 0xe5, 0x52, 0xb4, 0x83, 0x05, 0x75, 0x52, 0x62, 0x80, 0x08, 0xe5, 0x52, 0xc4, 0x54, 
+0xf0, 0x04, 0xf5, 0x52, 0x12, 0x17, 0x8b, 0x02, 0x2f, 0x28, 0x12, 0x19, 0xa3, 0x12, 0x27, 0x19, 
+0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x78, 
+0x6e, 0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0xf2, 0x90, 0x00, 0x02, 
+0xe4, 0x12, 0x14, 0x0d, 0x90, 0xfa, 0xb6, 0xe0, 0x44, 0x80, 0xff, 0xf0, 0x78, 0x82, 0xe6, 0xfc, 
+0x08, 0xe6, 0x8c, 0x83, 0x12, 0x18, 0xa3, 0xef, 0xf0, 0x12, 0x2f, 0x80, 0xe4, 0xff, 0x02, 0x2e, 
+0xa5, 0x90, 0xfa, 0xb5, 0xe0, 0x64, 0x01, 0x70, 0x1f, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, 
+0x70, 0x06, 0xa3, 0xe0, 0xf5, 0x90, 0x80, 0x2d, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0x90, 0x90, 0xfa, 
+0xba, 0xe0, 0x42, 0x90, 0xd2, 0xaf, 0x80, 0x1d, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e, 0x00, 0x70, 
+0x06, 0xa3, 0xe0, 0xf5, 0xb0, 0x80, 0x0e, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0xb0, 0x90, 0xfa, 0xba, 
+0xe0, 0x42, 0xb0, 0xd2, 0xaf, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x49, 0x90, 0xfa, 0xb5, 
+0xe0, 0xb4, 0x01, 0x0a, 0x12, 0x18, 0x2a, 0xe5, 0x90, 0x12, 0x13, 0xfb, 0x80, 0x08, 0x12, 0x18, 
+0x2a, 0xe5, 0xb0, 0x12, 0x13, 0xfb, 0x02, 0x0f, 0x2f, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x30, 
+0x12, 0x18, 0x53, 0x60, 0x18, 0x04, 0x70, 0x28, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 
+0xa4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x19, 0x12, 0x19, 0xad, 0xf0, 0x80, 0x13, 0x90, 0xfa, 0xb6, 
+0xe0, 0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x04, 0x12, 0x19, 0xb4, 0xf0, 
+0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe1, 0x36, 0x12, 0x18, 0x53, 0x60, 
+0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 
+0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, 
+0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 
+0xdf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x46, 0x04, 0x60, 0x03, 0x02, 
+0x0c, 0x90, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x04, 0xf0, 0x90, 
+0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x6a, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x61, 0x90, 
+0xff, 0xa4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x53, 0x30, 0x95, 0x09, 
+0x90, 0xff, 0xa4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x47, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 
+0x80, 0x3e, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x17, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x04, 0xf0, 0x90, 
+0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x2a, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x21, 0x90, 
+0xff, 0xb4, 0xe0, 0x54, 0xfb, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe1, 0x13, 0x30, 0x93, 0x09, 
+0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xfd, 0xf0, 
+0xe4, 0xff, 0x02, 0x2e, 0xa5, 0x12, 0x18, 0x53, 0x60, 0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb6, 
+0xe0, 0x60, 0x09, 0x90, 0xff, 0xa2, 0xe0, 0x44, 0x40, 0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa2, 0xe0, 
+0x54, 0xbf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xb2, 0xe0, 0x44, 
+0x40, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb2, 0xe0, 0x54, 0xbf, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 
+0x12, 0x18, 0x49, 0x12, 0x18, 0x5b, 0x60, 0x0f, 0x04, 0x70, 0x16, 0x90, 0xff, 0xa4, 0xe0, 0x12, 
+0x18, 0x2a, 0x12, 0x13, 0xfb, 0x80, 0x0a, 0x90, 0xff, 0xb4, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, 
+0xfb, 0x75, 0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x12, 
+0x19, 0x46, 0x7f, 0x03, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0xff, 
+0x7e, 0x00, 0x12, 0x2d, 0xee, 0xc2, 0x90, 0xc2, 0xaf, 0x00, 0x80, 0xfd, 0xe4, 0xf5, 0x54, 0xf5, 
+0x55, 0x90, 0xfa, 0xbb, 0x74, 0x3e, 0xf0, 0xa3, 0xe4, 0xf0, 0x90, 0xfa, 0xb3, 0xf0, 0xa3, 0x74, 
+0x15, 0xf0, 0xe0, 0x54, 0x3f, 0xff, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0xfa, 0xb8, 0xf0, 0xd3, 0x94, 
+0x00, 0xe4, 0x94, 0x3e, 0x40, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, 
+0xd6, 0xe5, 0x23, 0x45, 0x22, 0x70, 0x73, 0x12, 0x18, 0x62, 0x90, 0xfa, 0xbb, 0x12, 0x19, 0x65, 
+0x60, 0x27, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x08, 0x90, 0xfa, 0xb8, 0x74, 0x40, 
+0xf0, 0x80, 0x08, 0x90, 0xfa, 0xbc, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x12, 0x0e, 0xd6, 0xe5, 0x23, 
+0x45, 0x22, 0x70, 0x46, 0x12, 0x18, 0x62, 0x80, 0xd1, 0x75, 0x52, 0x02, 0x90, 0xfa, 0xbb, 0xe4, 
+0xf0, 0xa3, 0x04, 0xf0, 0x90, 0xfa, 0xb3, 0xe4, 0xf0, 0xa3, 0x74, 0x0f, 0xf0, 0x7b, 0x00, 0x7a, 
+0x00, 0x79, 0x52, 0x90, 0xfa, 0xbc, 0xe0, 0xf5, 0x50, 0x7d, 0x0f, 0x7c, 0x00, 0x12, 0x26, 0x25, 
+0x75, 0x22, 0x00, 0x8f, 0x23, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x52, 0xe4, 0xf5, 0x40, 0xf5, 0x41, 
+0x7d, 0x01, 0x12, 0x23, 0xee, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0xaf, 0x23, 0x02, 0x2e, 0xa5, 0x90, 
+0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x30, 0xe7, 0x10, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x62, 
+0xf0, 0xd3, 0x94, 0x00, 0x40, 0x15, 0xc2, 0x95, 0x80, 0x11, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0f, 
+0x90, 0xf9, 0x61, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x02, 0xc2, 0x94, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 
+0x12, 0x19, 0xa3, 0xbf, 0x01, 0x04, 0xd2, 0x93, 0x80, 0x02, 0xc2, 0x93, 0xe4, 0xff, 0x02, 0x2e, 
+0xa5, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x54, 0x03, 0x14, 0x60, 0x0a, 0x14, 0x60, 
+0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x91, 0x80, 0x27, 0xc2, 0x91, 0x80, 0x23, 
+0x12, 0x19, 0xad, 0x12, 0x0e, 0xfe, 0x60, 0x04, 0xd2, 0x91, 0x80, 0x17, 0x90, 0xff, 0xa4, 0xe0, 
+0x44, 0x10, 0x12, 0x0e, 0xfe, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x91, 0x80, 0x02, 0xd2, 0x91, 0x12, 
+0x19, 0xad, 0xf0, 0x90, 0xfa, 0xb6, 0xe0, 0x54, 0x0c, 0xff, 0x13, 0x13, 0x54, 0x3f, 0x14, 0x60, 
+0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x92, 0x80, 0x27, 0xc2, 
+0x92, 0x80, 0x23, 0x12, 0x19, 0xb4, 0x12, 0x0f, 0x1e, 0x60, 0x04, 0xd2, 0x92, 0x80, 0x17, 0x90, 
+0xff, 0xb4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0x1e, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x92, 0x80, 0x02, 
+0xd2, 0x92, 0x12, 0x19, 0xb4, 0xf0, 0xe4, 0xff, 0x02, 0x2e, 0xa5, 0xe5, 0x2c, 0x30, 0xe7, 0x07, 
+0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2c, 0xc0, 0x7f, 0x05, 0x02, 0x2e, 0xa5, 0x12, 0x2f, 0x76, 0x22, 
+0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb2, 0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 
+0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb3, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0xab, 
+0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x22, 0xaa, 0x54, 0xa9, 0x55, 0x7b, 0xff, 0x90, 0xfa, 0xb3, 0xe0, 
+0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xb8, 0xe0, 0xf5, 0x50, 0x12, 0x26, 0x25, 0x75, 0x22, 0x00, 
+0x8f, 0x23, 0x22, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, 0xef, 0x22, 0xf0, 0x7f, 
+0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x12, 
+0x23, 0xee, 0x8f, 0x52, 0x7e, 0x00, 0xc3, 0xef, 0x95, 0x35, 0xee, 0x95, 0x34, 0x22, 0xf0, 0x7f, 
+0x01, 0x12, 0x11, 0x9f, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x54, 0xa0, 0x22, 0x75, 
+0x30, 0x00, 0x75, 0x31, 0x01, 0x02, 0x29, 0x2d, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x02, 0x2f, 0x3b, 
+0x8e, 0x30, 0x8f, 0x31, 0x02, 0x29, 0x2d, 0x12, 0x20, 0xc5, 0x7e, 0x00, 0x8e, 0x22, 0x8f, 0x23, 
+0xef, 0x22, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xb0, 0xe0, 0x22, 0xef, 0x90, 0xf8, 0x04, 
+0xf0, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0xee, 0x60, 0x0a, 0xc0, 0x05, 0x7d, 0x7f, 0xdd, 0xfe, 0xde, 
+0xfa, 0xd0, 0x05, 0xef, 0xc3, 0x94, 0x15, 0x50, 0x03, 0xd0, 0xa8, 0x22, 0x13, 0x70, 0x03, 0xd0, 
+0xa8, 0x22, 0xff, 0xd5, 0x07, 0xfd, 0xd0, 0xa8, 0x22, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 
+0x04, 0xc0, 0x05, 0xe5, 0x44, 0x24, 0x08, 0xf8, 0x86, 0x05, 0x53, 0x05, 0x7f, 0x7c, 0xff, 0x12, 
+0x0f, 0xfe, 0x7f, 0x00, 0x7e, 0x00, 0xe5, 0x49, 0x60, 0x46, 0xfc, 0x90, 0xf9, 0x19, 0xe0, 0x54, 
+0x7f, 0x6d, 0x70, 0x0f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xa3, 0x15, 
+0x49, 0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xdc, 0xe6, 0x80, 0x26, 0xdc, 0x06, 0xd0, 0x82, 0xd0, 0x83, 
+0x80, 0x1e, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 
+0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 
+0x12, 0x10, 0x95, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x85, 0xa8, 
+0x4a, 0x75, 0xa8, 0x88, 0xec, 0x70, 0x02, 0x7c, 0x3f, 0x8c, 0x43, 0x22, 0xe5, 0x44, 0x24, 0x08, 
+0xf8, 0x76, 0x00, 0x12, 0x10, 0xec, 0x80, 0xfb, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, 
+0xc0, 0x06, 0x7c, 0xff, 0x12, 0x0f, 0xfe, 0xe5, 0x49, 0x60, 0x42, 0xfe, 0x90, 0xf9, 0x19, 0xe0, 
+0x54, 0x7f, 0x6f, 0x70, 0x0b, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x15, 0x49, 0x80, 0x07, 
+0xa3, 0xa3, 0xa3, 0xde, 0xea, 0x80, 0x26, 0xde, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0xd8, 0xe0, 
+0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, 
+0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x78, 0x08, 0x08, 
+0x79, 0x18, 0x09, 0x7c, 0x01, 0xe6, 0x54, 0x7f, 0x6f, 0x70, 0x06, 0x76, 0x00, 0x77, 0x00, 0x80, 
+0x06, 0x08, 0x09, 0x0c, 0xbc, 0x08, 0xee, 0x12, 0x10, 0x95, 0xd0, 0x06, 0xd0, 0x04, 0xd0, 0x02, 
+0xd0, 0x01, 0xd0, 0x00, 0x22, 0x75, 0x43, 0x00, 0x85, 0x4a, 0xa8, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 
+0xc0, 0x83, 0xc3, 0xe5, 0x49, 0x24, 0xe8, 0x50, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf4, 0xef, 0x60, 
+0x31, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9f, 0x40, 0x2f, 0xc0, 0x04, 0x7c, 0xff, 0x12, 0x0f, 
+0xfe, 0xd0, 0x04, 0x43, 0x07, 0x80, 0xe5, 0x49, 0x75, 0xf0, 0x03, 0xa4, 0x24, 0x19, 0xf5, 0x82, 
+0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xef, 0xf0, 0xec, 0xa3, 0xf0, 0xed, 0xa3, 0xf0, 0x05, 0x49, 0x12, 
+0x10, 0x95, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x02, 0x11, 0x1a, 0xc0, 0x04, 0x7c, 0x20, 
+0xd2, 0x8c, 0xd2, 0x8d, 0xd5, 0x04, 0xfd, 0xd0, 0x04, 0x22, 0x75, 0xa8, 0x00, 0x75, 0x88, 0x00, 
+0x75, 0xb8, 0x00, 0x75, 0xf0, 0x00, 0x75, 0xd0, 0x00, 0xe4, 0xf8, 0x90, 0xf8, 0x04, 0xf0, 0x90, 
+0x00, 0x00, 0xf6, 0x08, 0xb8, 0x00, 0xfb, 0x02, 0x00, 0x00, 0xc2, 0xaf, 0xe4, 0x90, 0xff, 0x48, 
+0xf0, 0x90, 0xff, 0x50, 0xf0, 0x90, 0xff, 0x08, 0xf0, 0x90, 0xff, 0x10, 0xf0, 0x90, 0xff, 0x80, 
+0xf0, 0xa3, 0xa3, 0xf0, 0xd2, 0xb1, 0xc2, 0xb0, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 
+0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0xd2, 0xb0, 0xd2, 
+0xb1, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x7e, 
+0xff, 0x7f, 0xff, 0x12, 0x0f, 0x62, 0x80, 0xcc, 0xc3, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x03, 
+0x7f, 0xe8, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x48, 0x8e, 
+0x47, 0x22, 0xc3, 0xef, 0x94, 0xbc, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x07, 0x7f, 0xd0, 0xef, 
+0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x46, 0x8e, 0x45, 0x22, 0xef, 
+0x70, 0x01, 0x22, 0xc0, 0x00, 0xe5, 0x44, 0x24, 0x18, 0xf8, 0xa6, 0x07, 0xe5, 0x44, 0x24, 0x08, 
+0xf8, 0xc6, 0x54, 0x7f, 0xf6, 0xe6, 0x30, 0xe7, 0x03, 0xd0, 0x00, 0x22, 0x12, 0x10, 0xec, 0x80, 
+0xf4, 0xc0, 0x00, 0x7f, 0x01, 0xef, 0x24, 0x08, 0xf8, 0xe6, 0x60, 0x09, 0x0f, 0xbf, 0x08, 0xf5, 
+0x12, 0x10, 0xec, 0x80, 0xee, 0xd0, 0x00, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 
+0xc0, 0x06, 0xc0, 0x04, 0xed, 0x24, 0x10, 0xf8, 0x76, 0xa0, 0xed, 0x75, 0xf0, 0x21, 0xa4, 0x24, 
+0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0xc0, 0x82, 0xc0, 0x83, 0xa3, 0xa3, 0xe4, 0x78, 
+0x0d, 0xf0, 0xa3, 0xd8, 0xfc, 0xef, 0x54, 0x7f, 0x75, 0xf0, 0x02, 0xa4, 0x24, 0x0e, 0xf5, 0x82, 
+0xe5, 0xf0, 0x34, 0x2e, 0xf5, 0x83, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xfc, 0xd0, 0x83, 0xd0, 
+0x82, 0xec, 0xf0, 0xa3, 0xee, 0xf0, 0xed, 0x24, 0x08, 0xf8, 0xef, 0x44, 0x80, 0xf6, 0xd0, 0x04, 
+0xd0, 0x06, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x75, 0x44, 0x00, 0x75, 0x49, 
+0x00, 0x7a, 0x08, 0x79, 0x18, 0x78, 0x08, 0x76, 0x00, 0x77, 0x00, 0x08, 0x09, 0xda, 0xf8, 0x90, 
+0xf8, 0x04, 0xe0, 0xfc, 0x90, 0x2e, 0x2c, 0xe4, 0x93, 0xc3, 0x9c, 0x50, 0x05, 0xe4, 0x90, 0xf8, 
+0x04, 0xf0, 0x78, 0x08, 0x74, 0x80, 0x44, 0x7f, 0xf6, 0x74, 0x01, 0x44, 0x10, 0xf5, 0x89, 0x75, 
+0xb8, 0x00, 0xd2, 0xab, 0xd2, 0xa9, 0x22, 0x75, 0x81, 0x91, 0xd2, 0x8e, 0xd2, 0x8c, 0xd2, 0xaf, 
+0xe5, 0x49, 0x60, 0x36, 0xff, 0x90, 0xf9, 0x19, 0xe0, 0x54, 0x80, 0x60, 0x28, 0x78, 0x08, 0x79, 
+0x08, 0xe0, 0x54, 0x7f, 0xfa, 0x7b, 0x00, 0xe6, 0x54, 0x7f, 0xb5, 0x02, 0x02, 0x7b, 0xff, 0x08, 
+0xd9, 0xf5, 0xeb, 0x70, 0x10, 0xea, 0xf0, 0xc0, 0x07, 0x12, 0x11, 0xc1, 0xad, 0x07, 0xaf, 0x02, 
+0x12, 0x11, 0xd8, 0xd0, 0x07, 0xa3, 0xa3, 0xa3, 0xdf, 0xce, 0x12, 0x10, 0xec, 0x80, 0xc1, 0xe7, 
+0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e, 0x88, 
+0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08, 0xdf, 
+0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83, 0xe3, 
+0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08, 0xdf, 
+0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c, 0x80, 
+0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10, 0x80, 
+0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33, 0x89, 
+0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 
+0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0x0d, 
+0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0, 0xed, 
+0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 
+0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde, 0xe8, 
+0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc, 0x88, 
+0xf0, 0xef, 0x60, 0x01, 0x0e, 0x4e, 0x60, 0xc3, 0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 
+0x50, 0xb9, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xaf, 0x23, 0x23, 0x45, 0x82, 
+0x23, 0x90, 0x13, 0x0f, 0x73, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 
+0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 
+0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 
+0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 
+0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 
+0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xf8, 0xbb, 0x01, 
+0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0, 0x22, 0x50, 0x06, 
+0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0x22, 0xc5, 
+0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 
+0x83, 0xe0, 0x38, 0xf0, 0x22, 0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 
+0x82, 0x70, 0x02, 0x15, 0x83, 0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22, 0xbb, 0x01, 0x10, 0xe5, 0x82, 
+0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0, 0xa3, 0xe0, 0x22, 0x50, 0x09, 
+0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe, 0x0a, 0xe9, 0x25, 0x82, 0xf8, 
+0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83, 0xe9, 0x93, 0xf5, 0xf0, 0xa3, 
+0xe9, 0x93, 0x22, 0xbb, 0x01, 0x0a, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, 
+0x50, 0x06, 0xf7, 0x09, 0xa7, 0xf0, 0x19, 0x22, 0xbb, 0xfe, 0x06, 0xf3, 0xe5, 0xf0, 0x09, 0xf3, 
+0x19, 0x22, 0xf8, 0xbb, 0x01, 0x11, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 
+0xe8, 0xf0, 0xe5, 0xf0, 0xa3, 0xf0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x08, 0xa6, 
+0xf0, 0x22, 0xbb, 0xfe, 0x09, 0xe9, 0x25, 0x82, 0xc8, 0xf2, 0xe5, 0xf0, 0x08, 0xf2, 0x22, 0xa4, 
+0x25, 0x82, 0xf5, 0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xe6, 0xfb, 0x08, 0xe6, 0xfa, 
+0x08, 0xe6, 0xf9, 0x22, 0xeb, 0xf6, 0x08, 0xea, 0xf6, 0x08, 0xe9, 0xf6, 0x22, 0xe0, 0xfb, 0xa3, 
+0xe0, 0xfa, 0xa3, 0xe0, 0xf9, 0x22, 0xeb, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xe9, 0xf0, 0x22, 0xd0, 
+0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 
+0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 
+0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0xff, 0xfa, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x16, 0xf0, 0x90, 
+0xff, 0xf9, 0x74, 0x02, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0b, 0xf0, 0x7b, 0x00, 
+0x7a, 0x00, 0x79, 0x37, 0x75, 0x40, 0x00, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0xe5, 0x37, 
+0x24, 0x80, 0x90, 0xff, 0xf8, 0xf0, 0xe5, 0x37, 0x64, 0x07, 0x60, 0x0b, 0xe5, 0x37, 0x64, 0x06, 
+0x60, 0x05, 0xe5, 0x37, 0xb4, 0x14, 0x1b, 0xd2, 0x94, 0xd2, 0x95, 0xd2, 0x92, 0xd2, 0x93, 0xe5, 
+0x37, 0xb4, 0x07, 0x08, 0x90, 0xf9, 0x65, 0x74, 0x02, 0xf0, 0x80, 0x06, 0x90, 0xf9, 0x65, 0x74, 
+0x01, 0xf0, 0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x0d, 0xf0, 0x12, 0x17, 0x71, 0x90, 0xff, 
+0xf5, 0xe5, 0x37, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, 
+0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x14, 0x2f, 0x12, 0x17, 0x71, 0xe5, 0x37, 0x30, 0xe7, 
+0x02, 0xd2, 0x02, 0xe4, 0xf5, 0x2c, 0xf5, 0x2a, 0xf5, 0x2b, 0xf5, 0x29, 0x12, 0x19, 0x92, 0x12, 
+0x18, 0x49, 0x12, 0x19, 0x6c, 0x90, 0xf9, 0x66, 0x12, 0x15, 0x06, 0x90, 0xf9, 0x6b, 0x12, 0x15, 
+0x06, 0x90, 0xff, 0xff, 0xe4, 0xf0, 0x90, 0xff, 0x83, 0xe0, 0xe4, 0xf0, 0x90, 0xff, 0x81, 0x74, 
+0x80, 0xf0, 0xa3, 0x74, 0x84, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xe4, 0xf5, 0x37, 0xe5, 0x37, 0x12, 
+0x18, 0xbf, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x37, 0x12, 0x18, 0xcd, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 
+0x37, 0xe5, 0x37, 0xb4, 0x07, 0xe7, 0x78, 0x80, 0x76, 0xfe, 0x08, 0x76, 0xf0, 0x90, 0x2f, 0x06, 
+0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xad, 0x07, 0x90, 0x2f, 0x13, 0xe4, 0x93, 0xff, 0x08, 
+0xf6, 0xff, 0xed, 0x54, 0x0f, 0xfd, 0x12, 0x18, 0xaf, 0x74, 0x84, 0xf0, 0xed, 0x75, 0xf0, 0x08, 
+0xa4, 0x24, 0x47, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xc3, 0x74, 0xf0, 0x9f, 
+0x78, 0x81, 0xf6, 0x74, 0xfe, 0x94, 0x00, 0x18, 0x12, 0x18, 0x41, 0xce, 0xc3, 0x13, 0xce, 0x13, 
+0xd8, 0xf9, 0xff, 0xed, 0x12, 0x19, 0x07, 0xef, 0xf0, 0xed, 0x12, 0x19, 0x2d, 0xe4, 0xf5, 0x37, 
+0xe5, 0x37, 0x90, 0x2f, 0x00, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0xfd, 0xe5, 0x37, 0x25, 0xe0, 0x24, 
+0x07, 0xf5, 0x82, 0xe4, 0x34, 0x2f, 0xf5, 0x83, 0xe4, 0x93, 0x08, 0xf6, 0xed, 0x30, 0xe7, 0x53, 
+0x18, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xaf, 0x12, 0x19, 0x15, 0x24, 0x47, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0xe9, 0x12, 0x19, 
+0x07, 0xef, 0xf0, 0x12, 0x18, 0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, 
+0x24, 0x45, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x12, 0x19, 0x2d, 0xe9, 
+0x75, 0xf0, 0x08, 0xa4, 0x24, 0x46, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 
+0x02, 0x17, 0x46, 0x78, 0x7e, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x18, 0xf9, 0x12, 0x19, 0x15, 0x24, 
+0x07, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x12, 0x18, 0x31, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 
+0x12, 0x19, 0x1a, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x18, 
+0x38, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x19, 0x1a, 0x24, 0x05, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x37, 0xe5, 0x37, 0x64, 0x04, 0x60, 0x03, 0x02, 0x16, 
+0x70, 0x90, 0x2f, 0x05, 0xe4, 0x93, 0xff, 0x78, 0x7e, 0xf6, 0x12, 0x18, 0xf7, 0xe4, 0xf0, 0x90, 
+0x2f, 0x04, 0x93, 0xff, 0xf6, 0x12, 0x18, 0xad, 0xe4, 0xf0, 0x90, 0xff, 0xfd, 0x74, 0x05, 0xf0, 
+0x22, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 
+0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 
+0x2f, 0xe5, 0x52, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 
+0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0x74, 0x11, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 
+0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x06, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 
+0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0xab, 0x2d, 
+0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 
+0x2e, 0xab, 0x2d, 0xfa, 0xa9, 0x2f, 0xe4, 0x12, 0x13, 0xfb, 0x04, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 
+0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x04, 0xe0, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, 
+0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 0x35, 0x2e, 0xf5, 0x2e, 0x90, 0xff, 0x05, 0xe0, 
+0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 0x12, 0x13, 0xfb, 0x74, 0x01, 0x25, 0x2f, 0xf5, 0x2f, 0xe4, 
+0x35, 0x2e, 0xf5, 0x2e, 0x22, 0xf5, 0x83, 0xe0, 0x54, 0x08, 0xab, 0x2d, 0xaa, 0x2e, 0xa9, 0x2f, 
+0x22, 0xf5, 0x83, 0xef, 0xf0, 0xfd, 0x7c, 0x00, 0xc3, 0x78, 0x81, 0xe6, 0x9d, 0xf6, 0x18, 0xe6, 
+0x9c, 0xf6, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x03, 0x22, 0x75, 0x2d, 0x01, 0x75, 0x2e, 0xf9, 0x75, 
+0x2f, 0x6e, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x90, 0xfa, 0xb5, 0xe0, 0x24, 
+0xfc, 0x22, 0x90, 0xfa, 0xb8, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xbc, 0xe0, 0x9f, 0xf0, 
+0x90, 0xfa, 0xbb, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xb3, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, 
+0x25, 0x55, 0xf5, 0x55, 0xee, 0x35, 0x54, 0xf5, 0x54, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb0, 
+0x90, 0xfa, 0xb3, 0xe0, 0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x22, 0x78, 0x82, 0xe6, 0xfe, 0x08, 
+0xe6, 0x8e, 0x83, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x54, 0x0f, 0x75, 
+0xf0, 0x08, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0xe5, 0x53, 0x75, 
+0xf0, 0x08, 0xa4, 0x24, 0x48, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0xe5, 0x53, 0x75, 0xf0, 0x08, 
+0xa4, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x22, 0x90, 0xff, 0x00, 0xe0, 0x54, 0x1f, 0x22, 
+0x90, 0xfa, 0xb5, 0xe0, 0xff, 0x24, 0xfc, 0x22, 0x75, 0x2a, 0x00, 0x8f, 0x2b, 0x90, 0xf9, 0x6b, 
+0x12, 0x14, 0xfd, 0x90, 0x00, 0x02, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 
+0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x41, 0xf5, 0x82, 0xe4, 
+0x34, 0xff, 0xf5, 0x83, 0x22, 0x74, 0x80, 0xf0, 0x08, 0xe6, 0xff, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 
+0x22, 0x74, 0xae, 0x25, 0x36, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 
+0xa4, 0x24, 0x42, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x22, 0x90, 0xff, 
+0x82, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x03, 0xf0, 0x90, 0xff, 0xfc, 
+0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x78, 0x6d, 0xe6, 0x54, 0xfd, 0xf6, 0x90, 0xff, 0xfd, 0x74, 0x65, 
+0xf0, 0x22, 0x12, 0x14, 0xdf, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x22, 0x7b, 0x01, 0x7a, 0xf9, 
+0x79, 0x6e, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, 0x22, 0x90, 0xff, 0x80, 0xe0, 0x44, 0x08, 
+0xf0, 0x22, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe0, 0xff, 0x90, 0xf9, 0x66, 0x02, 
+0x14, 0xfd, 0x75, 0x30, 0x01, 0x75, 0x31, 0x09, 0x22, 0xd3, 0xe5, 0x35, 0x94, 0x08, 0xe5, 0x34, 
+0x94, 0x01, 0x22, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x90, 0xfa, 0xb6, 0xf0, 0x22, 0x90, 0xff, 0xa4, 
+0xe0, 0x54, 0xef, 0x22, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xef, 0x22, 0x8f, 0x38, 0x12, 0x27, 0x19, 
+0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xe0, 0xfd, 
+0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x12, 0x20, 0x7c, 0x24, 
+0x07, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x12, 0x20, 0xbe, 0x24, 0x09, 0x12, 0x20, 0x25, 0xef, 0xf0, 
+0x90, 0xf9, 0x65, 0xe0, 0x30, 0xe4, 0x20, 0x08, 0x12, 0x20, 0x2f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 
+0xe0, 0x25, 0xe0, 0xff, 0x05, 0x82, 0xd5, 0x82, 0x02, 0x15, 0x83, 0x15, 0x82, 0xe0, 0x33, 0xd0, 
+0x82, 0xd0, 0x83, 0xf0, 0xa3, 0xef, 0xf0, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xe0, 0xfc, 0xa3, 0xe0, 
+0xfd, 0xec, 0xff, 0x12, 0x20, 0xa6, 0x8a, 0x83, 0x24, 0x08, 0x12, 0x20, 0x25, 0xef, 0xf0, 0xed, 
+0x12, 0x20, 0xbe, 0x24, 0x07, 0x12, 0x20, 0x25, 0xed, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 
+0xe0, 0xff, 0x53, 0x07, 0xc7, 0x08, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x20, 0x69, 0xa3, 0xe0, 
+0x30, 0xe3, 0x12, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, 
+0x2f, 0x4d, 0x93, 0x42, 0x07, 0x53, 0x07, 0xfb, 0x12, 0x20, 0xae, 0x24, 0x06, 0x12, 0x20, 0x25, 
+0xe0, 0x60, 0x03, 0x43, 0x07, 0x04, 0x53, 0x07, 0xfc, 0x78, 0x86, 0x12, 0x20, 0x96, 0x24, 0x04, 
+0x12, 0x20, 0x25, 0xe0, 0x42, 0x07, 0x43, 0x07, 0x80, 0x12, 0x20, 0xa6, 0xf5, 0x82, 0x8a, 0x83, 
+0xa3, 0xa3, 0xef, 0xf0, 0x12, 0x20, 0xbe, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xff, 0x8d, 0x82, 
+0x8c, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe1, 0x05, 0x53, 0x07, 0xdf, 0x80, 
+0x03, 0x43, 0x07, 0x20, 0xec, 0x30, 0xe4, 0x05, 0x53, 0x07, 0xef, 0x80, 0x03, 0x43, 0x07, 0x10, 
+0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, 0x4c, 0x53, 0x07, 0xdf, 0xee, 0x30, 0xe1, 0x42, 
+0x12, 0x20, 0xae, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, 0x60, 0x31, 0x14, 0x60, 0x29, 0x14, 
+0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, 0x38, 0xb4, 0x03, 0x0d, 0x30, 0x95, 
+0x05, 0x43, 0x07, 0x02, 0x80, 0x1f, 0x53, 0x07, 0xfd, 0x80, 0x1a, 0x30, 0x93, 0x05, 0x43, 0x07, 
+0x02, 0x80, 0x12, 0x53, 0x07, 0xfd, 0x80, 0x0d, 0x43, 0x07, 0x02, 0x80, 0x08, 0x53, 0x07, 0xfd, 
+0x80, 0x03, 0x53, 0x07, 0xfd, 0x12, 0x20, 0x94, 0x24, 0x04, 0x12, 0x20, 0x25, 0xef, 0xf0, 0x8d, 
+0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xff, 0x90, 0xf9, 0x65, 0xe0, 0xfe, 0x54, 0x03, 0x60, 
+0x4a, 0xee, 0x30, 0xe1, 0x43, 0x08, 0x12, 0x20, 0xb0, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0x14, 
+0x60, 0x2c, 0x14, 0x60, 0x2e, 0x14, 0x60, 0x26, 0x14, 0x60, 0x28, 0x24, 0x04, 0x70, 0x2c, 0xe5, 
+0x38, 0xb4, 0x03, 0x0d, 0x30, 0x94, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x1f, 0x43, 0x07, 0x80, 0x80, 
+0x1a, 0x30, 0x92, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x12, 0x43, 0x07, 0x80, 0x80, 0x0d, 0x53, 0x07, 
+0x7f, 0x80, 0x08, 0x43, 0x07, 0x80, 0x80, 0x03, 0x53, 0x07, 0x7f, 0x78, 0x86, 0x12, 0x20, 0x65, 
+0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x20, 0x80, 0x03, 0x53, 0x07, 0xdf, 
+0xec, 0x30, 0xe3, 0x05, 0x43, 0x07, 0x40, 0x80, 0x03, 0x53, 0x07, 0xbf, 0xec, 0x30, 0xe0, 0x05, 
+0x43, 0x07, 0x10, 0x80, 0x03, 0x53, 0x07, 0xef, 0xed, 0x30, 0xe4, 0x05, 0x43, 0x07, 0x08, 0x80, 
+0x03, 0x53, 0x07, 0xf7, 0xed, 0x30, 0xe5, 0x05, 0x43, 0x07, 0x04, 0x80, 0x03, 0x53, 0x07, 0xfb, 
+0xed, 0x30, 0xe6, 0x05, 0x43, 0x07, 0x01, 0x80, 0x03, 0x53, 0x07, 0xfe, 0xed, 0x30, 0xe7, 0x05, 
+0x43, 0x07, 0x02, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x78, 0x84, 0x12, 0x20, 0x65, 0xa3, 0xef, 0xf0, 
+0x12, 0x2f, 0x80, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x8e, 0xef, 0xf6, 0x12, 0x27, 0x19, 
+0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x09, 0x12, 0x20, 0x25, 0xe0, 0xfd, 0x12, 0x20, 0x53, 0x90, 
+0x00, 0x0a, 0x12, 0x20, 0x78, 0x24, 0x0a, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x0b, 0x12, 0x14, 
+0x0d, 0x12, 0x20, 0x70, 0xf5, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x59, 0x12, 0x20, 
+0x7c, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0xf5, 0x5a, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 
+0xf5, 0x5b, 0xe5, 0x59, 0xc4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x78, 0x8e, 0xf6, 0xd3, 0x94, 0x00, 
+0x40, 0x06, 0xe5, 0x5a, 0x30, 0xe1, 0x01, 0x06, 0x78, 0x8e, 0xe6, 0x12, 0x20, 0x52, 0x90, 0x00, 
+0x0c, 0xef, 0x12, 0x14, 0x0d, 0x78, 0x86, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 
+0xff, 0x53, 0x07, 0x0c, 0x53, 0x06, 0xe6, 0xe5, 0x59, 0x30, 0xe5, 0x03, 0x43, 0x07, 0x01, 0xe5, 
+0x5a, 0x20, 0xe5, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, 0x20, 0xe7, 0x03, 0x43, 
+0x07, 0x02, 0xe5, 0x59, 0x30, 0xe3, 0x03, 0x43, 0x07, 0x10, 0xe5, 0x59, 0x30, 0xe2, 0x03, 0x43, 
+0x07, 0x20, 0xe5, 0x59, 0x54, 0x03, 0x60, 0x03, 0x43, 0x07, 0x40, 0xe5, 0x59, 0x30, 0xe1, 0x03, 
+0x43, 0x07, 0x80, 0xe5, 0x59, 0x30, 0xe4, 0x03, 0x43, 0x06, 0x01, 0xe5, 0x59, 0x30, 0xe6, 0x03, 
+0x43, 0x06, 0x08, 0xe5, 0x5a, 0x20, 0xe4, 0x0e, 0xe5, 0x59, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x59, 
+0x20, 0xe7, 0x03, 0x43, 0x06, 0x10, 0x53, 0x07, 0xfb, 0x53, 0x06, 0x79, 0x90, 0x00, 0x05, 0xee, 
+0x8f, 0xf0, 0x12, 0x14, 0xb2, 0xe5, 0x5b, 0x30, 0xe3, 0x12, 0x54, 0x30, 0xff, 0xc4, 0x54, 0x0f, 
+0x12, 0x20, 0x52, 0x90, 0x00, 0x08, 0xef, 0x12, 0x14, 0x0d, 0x80, 0x0a, 0x12, 0x20, 0x53, 0x90, 
+0x00, 0x08, 0xe4, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x03, 0x12, 0x20, 0x52, 0x90, 0x00, 0x07, 
+0xef, 0x12, 0x14, 0x0d, 0xe5, 0x5b, 0x54, 0x04, 0xff, 0xc3, 0x13, 0x90, 0x00, 0x09, 0x12, 0x14, 
+0x0d, 0x90, 0x00, 0x07, 0x12, 0x13, 0xce, 0x70, 0x13, 0x12, 0x20, 0x53, 0xe9, 0x24, 0x09, 0xf9, 
+0xe4, 0x3a, 0xfa, 0x12, 0x13, 0xb5, 0xff, 0xc3, 0x13, 0x12, 0x13, 0xfb, 0x12, 0x20, 0x94, 0x24, 
+0x08, 0x12, 0x20, 0x25, 0xe0, 0xfe, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x07, 0x12, 0x20, 
+0x25, 0xe0, 0xfd, 0xee, 0xed, 0x12, 0x20, 0x52, 0x90, 0x00, 0x03, 0xee, 0x8f, 0xf0, 0x12, 0x14, 
+0xb2, 0x12, 0x2f, 0x80, 0x7d, 0x0a, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, 0x90, 0xfa, 
+0xe2, 0xe0, 0xb4, 0x03, 0x06, 0x7e, 0x00, 0x7f, 0x40, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x08, 0x90, 
+0xfa, 0xd6, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xff, 0x7e, 0x00, 
+0x90, 0xfa, 0xd2, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x70, 0x03, 0x7f, 0x08, 0x22, 0x90, 0x00, 0x08, 
+0x12, 0x14, 0x5b, 0xff, 0x90, 0xfa, 0xd4, 0xe5, 0xf0, 0xf0, 0xa3, 0xef, 0xf0, 0xae, 0x02, 0xaf, 
+0x01, 0x8e, 0x56, 0x8f, 0x57, 0x74, 0x0a, 0x25, 0x57, 0xf5, 0x57, 0xe4, 0x35, 0x56, 0xf5, 0x56, 
+0x90, 0xfa, 0xd7, 0xe0, 0xff, 0x14, 0xfe, 0x90, 0xfa, 0xd5, 0xe0, 0x5e, 0xfe, 0xc3, 0xef, 0x9e, 
+0xff, 0x90, 0xfa, 0xd9, 0xf0, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0x90, 0xfa, 0xd2, 0xe0, 0x94, 
+0x00, 0x50, 0x06, 0xa3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, 0x60, 0x03, 0xe0, 0xff, 
+0x22, 0x12, 0x2a, 0x80, 0x90, 0xfa, 0xd2, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x60, 0x2b, 0x90, 
+0xfa, 0xd6, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x40, 0x07, 0xe0, 0x90, 
+0xfa, 0xd9, 0xf0, 0x80, 0x08, 0x90, 0xfa, 0xd3, 0xe0, 0x90, 0xfa, 0xd9, 0xf0, 0x12, 0x1e, 0x2d, 
+0x60, 0x03, 0xe0, 0xff, 0x22, 0x12, 0x2a, 0x80, 0x80, 0xca, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x58, 
+0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7f, 0x00, 0x22, 0xaa, 0x56, 0xa9, 
+0x57, 0x7b, 0x01, 0x90, 0xfa, 0xd4, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xd9, 0xe0, 0xf5, 
+0x50, 0x12, 0x26, 0x25, 0x90, 0xfa, 0xd8, 0xef, 0xf0, 0x22, 0xef, 0x24, 0xae, 0x60, 0x52, 0x24, 
+0xfe, 0x60, 0x2e, 0x24, 0xfe, 0x70, 0x03, 0x02, 0x1e, 0xed, 0x24, 0x06, 0x60, 0x03, 0x02, 0x1f, 
+0x35, 0x78, 0x77, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xa5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, 
+0x74, 0x33, 0x90, 0xfa, 0x90, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xae, 0x74, 0x01, 0xf0, 
+0x22, 0x78, 0x78, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xb5, 0xe0, 0xf5, 0x36, 0x44, 0x0f, 0xf0, 
+0x74, 0x43, 0x90, 0xfa, 0x92, 0xf0, 0xe5, 0x36, 0xa3, 0xf0, 0x90, 0xfa, 0xaf, 0x74, 0x01, 0xf0, 
+0x22, 0x90, 0xfa, 0x9c, 0xe0, 0xa3, 0x20, 0xe5, 0x03, 0x02, 0x1f, 0x35, 0x90, 0xff, 0xa6, 0xe0, 
+0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 
+0x90, 0xff, 0xa6, 0x12, 0x20, 0x83, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, 
+0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x34, 0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x57, 0x90, 0xfa, 
+0xca, 0xe0, 0xff, 0x74, 0x34, 0x90, 0xfa, 0x94, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0x90, 0xfa, 0xa6, 
+0xe0, 0xa3, 0x30, 0xe5, 0x40, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0xa3, 0xf0, 0x90, 
+0xfa, 0xc9, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xb6, 0x12, 0x20, 0x83, 0x90, 
+0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xc9, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, 
+0xfe, 0x12, 0x29, 0xda, 0xef, 0x70, 0x0e, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x74, 0x44, 0x90, 0xfa, 
+0x96, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 
+0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 
+0x06, 0xc0, 0x07, 0x90, 0xff, 0x92, 0xe0, 0xff, 0x90, 0xfa, 0xc8, 0xf0, 0x90, 0xff, 0x92, 0xe4, 
+0xf0, 0xef, 0x12, 0x15, 0x0f, 0x1f, 0xed, 0x26, 0x1f, 0xed, 0x2e, 0x1f, 0x90, 0x30, 0x1f, 0x90, 
+0x32, 0x1f, 0x9e, 0x38, 0x1f, 0xb0, 0x3a, 0x1f, 0xe2, 0x3e, 0x1f, 0xcd, 0x44, 0x1f, 0xc2, 0x46, 
+0x1f, 0xd8, 0x50, 0x1f, 0xd8, 0x52, 0x1f, 0xd8, 0x54, 0x1f, 0xd8, 0x56, 0x00, 0x00, 0x1f, 0xf2, 
+0x90, 0xfa, 0xc8, 0xe0, 0xfd, 0x7c, 0x00, 0x7f, 0x01, 0x12, 0x10, 0x9c, 0x80, 0x62, 0x7c, 0x00, 
+0x7d, 0x01, 0x7f, 0x03, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x50, 
+0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x02, 0x12, 0x10, 0x9c, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x40, 0xf0, 
+0x80, 0x3e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x05, 0x12, 0x10, 0x9c, 0x80, 0x33, 0x7c, 0x00, 0x7d, 
+0x01, 0x7f, 0x06, 0x12, 0x10, 0x9c, 0x80, 0x28, 0x90, 0xfa, 0xc8, 0xe0, 0xff, 0x12, 0x1e, 0x4a, 
+0x80, 0x1e, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x04, 0x12, 0x10, 0x9c, 0x80, 0x13, 0x12, 0x25, 0x13, 
+0x80, 0x0e, 0x90, 0xfa, 0xc8, 0xe0, 0x24, 0x00, 0xff, 0xe4, 0x34, 0xff, 0xfe, 0x12, 0x29, 0xda, 
+0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 
+0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x78, 0x82, 0xe6, 0xfe, 0x08, 
+0xe6, 0x24, 0x04, 0x8e, 0x83, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x78, 0x82, 0xe6, 
+0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0x22, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 0xaa, 0x06, 
+0xf8, 0xac, 0x02, 0x7d, 0x01, 0x7b, 0xff, 0x7a, 0x2f, 0x79, 0x52, 0x7e, 0x00, 0x7f, 0x0a, 0x02, 
+0x13, 0x8f, 0xff, 0x90, 0xf9, 0x6b, 0x02, 0x14, 0xfd, 0x90, 0xf9, 0x66, 0x12, 0x14, 0xfd, 0x90, 
+0x00, 0x04, 0x02, 0x13, 0xce, 0xe6, 0xfc, 0x08, 0xe6, 0xf5, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0x22, 
+0x78, 0x84, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xed, 0x12, 0x14, 0x0d, 0x8f, 0x82, 0x8e, 0x83, 
+0xe5, 0x82, 0x22, 0xef, 0xf0, 0x90, 0xfa, 0xca, 0xe0, 0x54, 0x0f, 0x4e, 0xfe, 0xf0, 0xef, 0x54, 
+0xf0, 0x4e, 0xf0, 0x22, 0x78, 0x84, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x8c, 0x83, 0x22, 0xa6, 0x07, 
+0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x22, 0x78, 0x84, 0xe6, 0xfa, 0x08, 0xe6, 0xfb, 0x22, 0x78, 0x86, 
+0xe6, 0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x22, 0x26, 0xf6, 0x18, 0xee, 0x36, 0xf6, 0x22, 0x8b, 0x82, 
+0x8a, 0x83, 0xe5, 0x82, 0x22, 0x8b, 0x38, 0x8a, 0x39, 0x89, 0x3a, 0x8d, 0x3b, 0x90, 0xfa, 0xce, 
+0xe4, 0xf0, 0xa3, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe0, 
+0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x90, 0xfa, 0xcd, 0xe0, 0x65, 
+0x3b, 0x60, 0x46, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0xa3, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x21, 
+0x54, 0x90, 0xfa, 0xcd, 0xe0, 0xff, 0x90, 0xfa, 0xd0, 0xe4, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0x12, 
+0x21, 0x54, 0x90, 0xfa, 0xd0, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0xfa, 0xce, 0xcf, 0xf0, 0xa3, 0xef, 
+0xf0, 0x90, 0xfa, 0xcd, 0xe0, 0xa3, 0x75, 0xf0, 0x00, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xce, 0xe4, 
+0x75, 0xf0, 0x04, 0x12, 0x14, 0x2f, 0x02, 0x20, 0xd6, 0x90, 0xfa, 0xcf, 0xe0, 0x24, 0x01, 0xff, 
+0x90, 0xfa, 0xce, 0xe0, 0x34, 0x00, 0xab, 0x38, 0xaa, 0x39, 0xa9, 0x3a, 0x8f, 0xf0, 0x12, 0x14, 
+0x93, 0x7f, 0x00, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcd, 0x90, 0xfa, 0xce, 0xe4, 0x75, 0xf0, 
+0x01, 0x12, 0x14, 0x2f, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x8f, 0x68, 
+0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xfb, 
+0xf0, 0x44, 0x02, 0xf0, 0x08, 0x12, 0x20, 0x65, 0xe0, 0xa3, 0x30, 0xe5, 0x0c, 0x12, 0x20, 0x7c, 
+0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x78, 0x82, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 
+0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x54, 0xb8, 0xfd, 0xf0, 0xe5, 0x68, 0x24, 0xfe, 0x44, 0x20, 0xfc, 
+0x4d, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xb8, 0xf0, 0x4c, 0xf0, 0x8f, 
+0x82, 0x8e, 0x83, 0xa3, 0x74, 0x03, 0xf0, 0x18, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 
+0x05, 0x12, 0x20, 0x25, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x74, 0x95, 0x25, 0x68, 0xf5, 0x82, 
+0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0x44, 0x03, 0xfc, 0xed, 0x4c, 0xd0, 0x82, 0xd0, 
+0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 
+0x25, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x68, 0xf8, 0x74, 0x04, 0x46, 
+0xf6, 0x7f, 0x00, 0x22, 0x8b, 0x62, 0x8a, 0x63, 0x89, 0x64, 0x12, 0x2a, 0x62, 0x90, 0xfa, 0xbf, 
+0x12, 0x15, 0x06, 0xaa, 0x63, 0xa9, 0x64, 0x90, 0xfa, 0xc2, 0x12, 0x15, 0x06, 0x90, 0xfa, 0xc3, 
+0xe4, 0x75, 0xf0, 0x0a, 0x12, 0x14, 0x2f, 0x90, 0xfa, 0xc2, 0x12, 0x14, 0xfd, 0xe9, 0x24, 0x01, 
+0xf9, 0xe4, 0x3a, 0xfa, 0x90, 0xfa, 0xc5, 0x12, 0x15, 0x06, 0xab, 0x62, 0xaa, 0x63, 0xa9, 0x64, 
+0x12, 0x2a, 0x6e, 0xe0, 0xff, 0xc3, 0x13, 0xf0, 0xe4, 0x78, 0x88, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, 
+0xff, 0x78, 0x88, 0xe6, 0xc3, 0x9f, 0x50, 0x4a, 0x90, 0xfa, 0xbf, 0x12, 0x2a, 0x43, 0xff, 0x78, 
+0x89, 0xf6, 0x90, 0xfa, 0xc2, 0x12, 0x2a, 0x43, 0xfe, 0xf4, 0x5f, 0xff, 0x78, 0x89, 0xf6, 0x12, 
+0x2a, 0x40, 0x5e, 0x4f, 0xff, 0x78, 0x89, 0xf6, 0x12, 0x2a, 0x49, 0x75, 0xf0, 0x02, 0x12, 0x14, 
+0x2f, 0x90, 0xfa, 0xc3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x14, 0x2f, 0xab, 0x62, 0xaa, 0x63, 0xa9, 
+0x64, 0x90, 0x00, 0x04, 0x12, 0x13, 0xce, 0x30, 0xe4, 0x03, 0x12, 0x2a, 0x58, 0x78, 0x88, 0x06, 
+0x80, 0xaa, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x22, 0x8b, 0x5c, 0x8a, 0x5d, 0x89, 0x5e, 0x90, 0xfa, 
+0xbe, 0x74, 0x06, 0xf0, 0xe4, 0x90, 0xfa, 0xbd, 0xf0, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x26, 
+0x14, 0x70, 0x70, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x12, 0x12, 0x22, 0x14, 0x80, 
+0x62, 0x12, 0x2a, 0x79, 0x12, 0x1d, 0x5e, 0x90, 0xfa, 0xbe, 0xef, 0xf0, 0x80, 0x55, 0x90, 0xfa, 
+0xbe, 0x74, 0x81, 0xf0, 0x80, 0x4d, 0x12, 0x2a, 0x2f, 0x60, 0x09, 0x24, 0x30, 0x70, 0x3e, 0x12, 
+0x29, 0x85, 0x80, 0x3f, 0xe5, 0x5e, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x5d, 0xfa, 0x7b, 0x01, 0xc0, 
+0x03, 0xc0, 0x02, 0xc0, 0x01, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x05, 0x12, 0x13, 0xce, 0xfd, 0x90, 
+0x00, 0x08, 0x12, 0x14, 0x5b, 0xf5, 0x41, 0x85, 0xf0, 0x40, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 
+0x12, 0x23, 0xee, 0x90, 0xfa, 0xbd, 0xef, 0xf0, 0xe4, 0xa3, 0xf0, 0x80, 0x06, 0x90, 0xfa, 0xbe, 
+0x74, 0x81, 0xf0, 0x90, 0xfa, 0xbe, 0xe0, 0x12, 0x2a, 0x79, 0x90, 0x00, 0x02, 0x12, 0x14, 0x0d, 
+0x90, 0xfa, 0xbd, 0xe0, 0xff, 0x22, 0x12, 0x0f, 0x89, 0x7f, 0x02, 0x12, 0x11, 0x9f, 0x78, 0x6d, 
+0xe6, 0x44, 0x02, 0xf6, 0xd2, 0xb0, 0xd2, 0xb1, 0xd2, 0xb3, 0x90, 0xff, 0xa4, 0xe0, 0x90, 0xfa, 
+0x7a, 0xf0, 0x90, 0xff, 0xb4, 0xe0, 0x90, 0xfa, 0x7b, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x90, 0xfa, 
+0x78, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x90, 0xfa, 0x79, 0xf0, 0x90, 0xff, 0xa4, 0x74, 0x30, 0xf0, 
+0x90, 0xff, 0xb4, 0xf0, 0x90, 0xff, 0xa2, 0x74, 0x40, 0xf0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xfa, 
+0xe3, 0xe5, 0xa8, 0xf0, 0x75, 0xa8, 0x81, 0x90, 0xff, 0x92, 0xe0, 0x60, 0x04, 0xe4, 0xf0, 0x80, 
+0xf6, 0x90, 0xff, 0xfd, 0x74, 0x3a, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x90, 0xfa, 0x7a, 
+0xe0, 0x90, 0xff, 0xa4, 0xf0, 0x90, 0xfa, 0x7b, 0xe0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xfa, 0x78, 
+0xe0, 0x90, 0xff, 0xa2, 0xf0, 0x90, 0xfa, 0x79, 0xe0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xf9, 0x15, 
+0xe0, 0x60, 0x02, 0xc2, 0xb3, 0x90, 0xfa, 0xe3, 0xe0, 0xf5, 0xa8, 0x02, 0x10, 0x0c, 0x8b, 0x3c, 
+0x8a, 0x3d, 0x89, 0x3e, 0x8d, 0x3f, 0xe5, 0x3f, 0x70, 0x03, 0xaf, 0x3f, 0x22, 0x12, 0x2a, 0xa8, 
+0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x40, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x2e, 0xd4, 0x50, 0xf2, 
+0x12, 0x24, 0x7b, 0x40, 0x0b, 0x7f, 0x00, 0x22, 0x12, 0x2a, 0xc7, 0x12, 0x24, 0x7b, 0x50, 0xf8, 
+0x90, 0xff, 0xf3, 0x74, 0xa1, 0xf0, 0xe5, 0x3f, 0xb4, 0x01, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 
+0x02, 0xf0, 0x90, 0xff, 0xf1, 0xe4, 0xf0, 0xf5, 0x42, 0xe5, 0x3f, 0x14, 0xff, 0xe5, 0x42, 0xc3, 
+0x9f, 0x50, 0x2a, 0x12, 0x2e, 0xbd, 0x40, 0x03, 0xaf, 0x42, 0x22, 0xc3, 0xe5, 0x3f, 0x95, 0x42, 
+0xff, 0xbf, 0x02, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x2a, 0xba, 0x05, 0x42, 
+0x74, 0x01, 0x25, 0x3e, 0xf5, 0x3e, 0xe4, 0x35, 0x3d, 0xf5, 0x3d, 0x80, 0xcc, 0x12, 0x2e, 0xbd, 
+0x40, 0x03, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xba, 0xaf, 0x3f, 0x22, 0x90, 0xff, 0xf1, 0xe5, 0x41, 
+0xf0, 0x02, 0x2e, 0xd4, 0x75, 0xa8, 0x40, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x91, 
+0x02, 0x24, 0xce, 0x02, 0x2e, 0x88, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 
+0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 
+0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 
+0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x28, 
+0xcb, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 
+0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 
+0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 
+0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 
+0xe7, 0x80, 0xbe, 0xe4, 0xf5, 0x36, 0x12, 0x19, 0x21, 0xe0, 0xb4, 0x04, 0x0d, 0xe5, 0x36, 0x24, 
+0x03, 0xff, 0x12, 0x2d, 0x4f, 0x12, 0x19, 0x21, 0xe4, 0xf0, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, 
+0x02, 0x40, 0xe3, 0xe4, 0xf5, 0x36, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x90, 0x12, 0x19, 
+0x62, 0x60, 0x2c, 0x12, 0x29, 0xda, 0xef, 0x60, 0x52, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 
+0x90, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, 0xf0, 0x75, 0xf0, 0x0a, 0xe5, 0x36, 0x90, 0xfa, 0x9c, 
+0x12, 0x14, 0xdf, 0xe0, 0xa3, 0x30, 0xe6, 0x33, 0x12, 0x19, 0x21, 0x74, 0x04, 0xf0, 0x22, 0x75, 
+0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x19, 0x62, 0x60, 0x16, 0x12, 0x29, 0xda, 0xef, 
+0x60, 0x19, 0x75, 0xf0, 0x02, 0xe5, 0x36, 0x90, 0xfa, 0x94, 0x12, 0x14, 0xdf, 0xe4, 0xf0, 0xa3, 
+0xf0, 0x22, 0x05, 0x36, 0xe5, 0x36, 0xc3, 0x94, 0x02, 0x40, 0x9b, 0x22, 0xe4, 0xff, 0x90, 0xff, 
+0x83, 0xe0, 0x54, 0x0f, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x17, 0x74, 0xf0, 0x2f, 0xf5, 0x82, 0xe4, 
+0x34, 0xfe, 0xf5, 0x83, 0xe0, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xfb, 0x0f, 0x12, 0x18, 0x19, 0x80, 
+0xdd, 0xef, 0xfd, 0xc3, 0xe5, 0x31, 0x9d, 0xf5, 0x31, 0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0xd3, 
+0xe5, 0x31, 0x94, 0x00, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x06, 0xe4, 0x90, 0xff, 0x83, 0xf0, 0x22, 
+0x12, 0x19, 0x3e, 0x12, 0x19, 0x92, 0x12, 0x19, 0x8c, 0x12, 0x13, 0xb5, 0x24, 0x6e, 0x60, 0x1e, 
+0x14, 0x60, 0x1b, 0x24, 0x8e, 0x70, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x13, 0xce, 0xff, 0x24, 0xfc, 
+0x60, 0x03, 0x04, 0x70, 0x1f, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0d, 0x02, 0x10, 0x9c, 0x12, 0x19, 
+0x6c, 0x12, 0x22, 0xb8, 0x12, 0x18, 0xe8, 0x12, 0x13, 0xce, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, 
+0xff, 0x12, 0x2f, 0x6a, 0x22, 0x8b, 0x4b, 0x8a, 0x4c, 0x89, 0x4d, 0x8c, 0x4e, 0x8d, 0x4f, 0xd2, 
+0x00, 0x12, 0x2a, 0xa8, 0x70, 0x16, 0x12, 0x2a, 0xc7, 0xe5, 0x4e, 0x90, 0xff, 0xf1, 0xf0, 0x12, 
+0x2e, 0xd4, 0x50, 0xf2, 0x12, 0x26, 0x9a, 0x40, 0x0b, 0x7f, 0x18, 0x22, 0x12, 0x2a, 0xc7, 0x12, 
+0x26, 0x9a, 0x50, 0xf8, 0xe4, 0xf5, 0x51, 0xe5, 0x50, 0x14, 0xff, 0xe5, 0x51, 0xc3, 0x9f, 0x50, 
+0x17, 0x12, 0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x05, 0x51, 0x74, 0x01, 0x25, 0x4d, 0xf5, 
+0x4d, 0xe4, 0x35, 0x4c, 0xf5, 0x4c, 0x80, 0xdf, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x12, 
+0x26, 0x8a, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x7f, 0x00, 0x22, 0xab, 0x4b, 0xaa, 0x4c, 0xa9, 0x4d, 
+0x12, 0x13, 0xb5, 0x90, 0xff, 0xf1, 0xf0, 0x02, 0x2e, 0xd4, 0x90, 0xff, 0xf1, 0xe5, 0x4f, 0xf0, 
+0x02, 0x2e, 0xd4, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcb, 0xe4, 0xfd, 0x12, 0x20, 0xc5, 0x90, 0xfa, 
+0xcb, 0xe4, 0x75, 0xf0, 0x09, 0x12, 0x14, 0x2f, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 
+0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, 0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x12, 
+0x23, 0xee, 0x90, 0xff, 0xf7, 0xe5, 0x37, 0x12, 0x26, 0xfe, 0x90, 0xff, 0xf6, 0xe5, 0x37, 0xf0, 
+0x90, 0xfa, 0xcb, 0xe4, 0xf0, 0xa3, 0x74, 0x06, 0x12, 0x26, 0xfe, 0xe5, 0x37, 0x30, 0xe0, 0x07, 
+0x90, 0xff, 0xfc, 0x74, 0x94, 0xf0, 0x22, 0x90, 0xff, 0xfc, 0x74, 0x90, 0xf0, 0x22, 0xf0, 0x7b, 
+0x00, 0x7a, 0x00, 0x79, 0x37, 0x90, 0xfa, 0xcb, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x14, 0x45, 0x85, 
+0xf0, 0x41, 0xf5, 0x40, 0x7d, 0x01, 0x02, 0x23, 0xee, 0x15, 0x6b, 0xa8, 0x6b, 0xa6, 0x07, 0x30, 
+0x08, 0x05, 0x12, 0x10, 0xec, 0x80, 0xf8, 0xd2, 0x08, 0xa8, 0x6b, 0xe6, 0xff, 0xb4, 0x03, 0x0f, 
+0x78, 0x82, 0x76, 0xff, 0x08, 0x76, 0xe0, 0x08, 0x76, 0xff, 0x08, 0x76, 0xa0, 0x80, 0x0d, 0x78, 
+0x82, 0x76, 0xff, 0x08, 0x76, 0xe2, 0x08, 0x76, 0xff, 0x08, 0x76, 0xb0, 0x78, 0x86, 0x76, 0xfa, 
+0x08, 0x76, 0x9a, 0xef, 0x24, 0xfd, 0x75, 0xf0, 0x0a, 0xa4, 0xae, 0xf0, 0x12, 0x20, 0xb7, 0x7b, 
+0x01, 0x7a, 0xff, 0x79, 0x48, 0x78, 0x6e, 0x12, 0x14, 0xf4, 0xa8, 0x6b, 0xe6, 0x24, 0xfd, 0x75, 
+0xf0, 0x08, 0xa4, 0xff, 0xae, 0xf0, 0x78, 0x70, 0x12, 0x20, 0xb7, 0x79, 0x08, 0x78, 0x71, 0x12, 
+0x14, 0xf4, 0x78, 0x73, 0xef, 0x12, 0x20, 0xb7, 0x05, 0x6b, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 
+0xab, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xfa, 0xe2, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 
+0x79, 0xcb, 0xe4, 0xf5, 0x40, 0xf5, 0x41, 0x7d, 0x01, 0x12, 0x23, 0xee, 0x7e, 0x00, 0x90, 0xfa, 
+0xe0, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x52, 
+0x09, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x29, 0x90, 0xfa, 0xe0, 0xe0, 0x70, 0x04, 
+0xa3, 0xe0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcb, 0xe0, 0xb4, 0x10, 0x09, 0x90, 0xf9, 0x65, 
+0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0d, 0x90, 0xfa, 0xe2, 0x74, 0x03, 0xf0, 0x90, 0xf9, 0x65, 0xe0, 
+0x54, 0xef, 0xf0, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x22, 0x90, 0xff, 0x93, 0x74, 0x2a, 
+0xf0, 0x90, 0xff, 0xff, 0xe0, 0x60, 0x06, 0x90, 0xff, 0xfc, 0x74, 0x10, 0xf0, 0x90, 0xff, 0x91, 
+0xe0, 0x44, 0x90, 0xf0, 0x12, 0x27, 0x8b, 0x12, 0x15, 0x35, 0x12, 0x2d, 0xa5, 0x7e, 0x07, 0x7f, 
+0xd0, 0x12, 0x11, 0x68, 0x7e, 0x0f, 0x7f, 0xa0, 0x12, 0x11, 0x82, 0xe4, 0x78, 0x7d, 0xf6, 0x78, 
+0x7d, 0xe6, 0xff, 0xc3, 0x94, 0x06, 0x50, 0x0b, 0x74, 0x74, 0x2f, 0xf8, 0xe4, 0xf6, 0x78, 0x7d, 
+0x06, 0x80, 0xec, 0x7f, 0x03, 0x12, 0x2c, 0x5b, 0x90, 0xf9, 0x65, 0xe0, 0x20, 0xe4, 0x05, 0x7f, 
+0x04, 0x12, 0x2c, 0x5b, 0x90, 0xff, 0x9b, 0xe4, 0xf0, 0x90, 0xff, 0x9a, 0xf0, 0x90, 0xff, 0xe8, 
+0xe0, 0x54, 0x1f, 0xf0, 0xd2, 0xa8, 0x22, 0x12, 0x0f, 0x89, 0x78, 0x90, 0xef, 0xf6, 0x12, 0x27, 
+0x19, 0x12, 0x20, 0x59, 0x30, 0xe0, 0x25, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x7f, 0xf0, 0x78, 0x71, 
+0x12, 0x14, 0xeb, 0x90, 0x00, 0x02, 0x12, 0x13, 0xce, 0x30, 0xe7, 0x09, 0x90, 0x00, 0x02, 0xe4, 
+0x12, 0x14, 0x0d, 0x80, 0xe9, 0x12, 0x20, 0x2d, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x20, 0x59, 0x30, 
+0xe1, 0x1e, 0x12, 0x20, 0x1b, 0xe0, 0x54, 0x7f, 0xf0, 0x12, 0x2f, 0x15, 0x78, 0x6e, 0x12, 0x14, 
+0xeb, 0x90, 0x00, 0x02, 0x74, 0x80, 0x12, 0x14, 0x0d, 0x12, 0x20, 0x1b, 0xe0, 0x44, 0x80, 0xf0, 
+0x12, 0x2f, 0x80, 0xe4, 0xff, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x03, 0x6e, 0x01, 0xff, 0x48, 
+0x03, 0x71, 0x01, 0xff, 0x08, 0x02, 0x6c, 0x00, 0x00, 0x44, 0xfa, 0x94, 0x00, 0x00, 0x00, 0x00, 
+0x44, 0xfa, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfa, 0xae, 0x00, 0x00, 0x42, 0xfa, 0x7a, 0x00, 
+0x00, 0x42, 0xfa, 0x78, 0x00, 0x00, 0x42, 0xf9, 0x69, 0xff, 0xff, 0x42, 0xfa, 0x76, 0x00, 0x00, 
+0x43, 0xf9, 0x16, 0x0a, 0x32, 0x02, 0x41, 0xf9, 0x63, 0x20, 0x41, 0xf9, 0x64, 0x20, 0x41, 0xf9, 
+0x61, 0x00, 0x41, 0xf9, 0x62, 0x00, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf9, 0x65, 
+0x00, 0x41, 0xf9, 0x15, 0x00, 0x01, 0x20, 0x00, 0x41, 0xf8, 0x04, 0x00, 0x00, 0x12, 0x19, 0x82, 
+0xe5, 0x31, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x48, 0xc3, 0xe5, 0x31, 0x94, 
+0x08, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x11, 0x7f, 0x08, 0xef, 0xe5, 0x31, 0x94, 0x08, 0xf5, 0x31, 
+0xe5, 0x30, 0x94, 0x00, 0xf5, 0x30, 0x80, 0x05, 0xaf, 0x31, 0x12, 0x19, 0x92, 0xe4, 0xfe, 0xee, 
+0xc3, 0x9f, 0x50, 0x19, 0x12, 0x18, 0x2a, 0x12, 0x13, 0xb5, 0xfd, 0x74, 0xf8, 0x2e, 0xf5, 0x82, 
+0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xed, 0xf0, 0x0e, 0x12, 0x18, 0x19, 0x80, 0xe2, 0xef, 0x54, 0x7f, 
+0x90, 0xff, 0x81, 0xf0, 0x22, 0x8b, 0x5f, 0x8a, 0x60, 0x89, 0x61, 0x12, 0x2a, 0x6e, 0x70, 0x05, 
+0xa3, 0x74, 0x08, 0xf0, 0x22, 0xab, 0x5f, 0xaa, 0x60, 0xa9, 0x61, 0x12, 0x2a, 0x62, 0x90, 0xfa, 
+0xc5, 0x12, 0x15, 0x06, 0xe5, 0x61, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x60, 0xfa, 0x90, 0xfa, 0xbf, 
+0x12, 0x15, 0x06, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x78, 0x91, 0xf6, 0x90, 0xfa, 0xbd, 0xe0, 0xff, 
+0x78, 0x91, 0xe6, 0xc3, 0x9f, 0x50, 0x12, 0x12, 0x2a, 0x40, 0xff, 0x12, 0x2a, 0x49, 0x12, 0x2a, 
+0x5c, 0x78, 0x91, 0x06, 0x12, 0x2a, 0x58, 0x80, 0xe2, 0x22, 0xad, 0x07, 0xac, 0x06, 0x90, 0x2f, 
+0x06, 0xe4, 0x93, 0xff, 0x78, 0x7a, 0xf6, 0x54, 0x0f, 0x12, 0x19, 0x07, 0xe0, 0x08, 0x76, 0x00, 
+0x08, 0xf6, 0x18, 0x12, 0x18, 0x42, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0x78, 0x7b, 
+0xee, 0xf6, 0x08, 0xef, 0xf6, 0xee, 0x44, 0xf8, 0x18, 0xf6, 0xef, 0x08, 0xf6, 0x90, 0xff, 0x7a, 
+0xe0, 0x20, 0xe7, 0x03, 0x7f, 0x00, 0x22, 0x78, 0x7b, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 
+0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0x90, 0xff, 0x7a, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0x22, 0xab, 
+0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x90, 0x00, 0x03, 0x12, 0x13, 0xce, 0x54, 0xf0, 0x24, 0xa0, 0x22, 
+0x90, 0xfa, 0xc5, 0x12, 0x14, 0xfd, 0x02, 0x13, 0xb5, 0x90, 0xfa, 0xbf, 0x12, 0x14, 0xfd, 0xef, 
+0x12, 0x13, 0xfb, 0x90, 0xfa, 0xc6, 0xe4, 0x22, 0x90, 0xfa, 0xc0, 0xe4, 0x75, 0xf0, 0x01, 0x02, 
+0x14, 0x2f, 0x90, 0x00, 0x08, 0x12, 0x14, 0x5b, 0xaa, 0xf0, 0xf9, 0x7b, 0x01, 0x22, 0x90, 0x00, 
+0x05, 0x12, 0x13, 0xce, 0x90, 0xfa, 0xbd, 0xf0, 0x22, 0xab, 0x5c, 0xaa, 0x5d, 0xa9, 0x5e, 0x22, 
+0x90, 0xfa, 0xd9, 0xe0, 0xff, 0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xd3, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 
+0xd2, 0xe0, 0x9e, 0xf0, 0x90, 0xfa, 0xd4, 0xee, 0x8f, 0xf0, 0x12, 0x14, 0x2f, 0xef, 0x25, 0x57, 
+0xf5, 0x57, 0xee, 0x35, 0x56, 0xf5, 0x56, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 
+0x54, 0xfd, 0xf0, 0x90, 0xfa, 0xe2, 0xe0, 0x64, 0x03, 0x22, 0x90, 0xff, 0xf2, 0xe0, 0xab, 0x3c, 
+0xaa, 0x3d, 0xa9, 0x3e, 0x02, 0x13, 0xfb, 0x90, 0xff, 0xf3, 0x74, 0xa0, 0xf0, 0x22, 0x8f, 0x6a, 
+0xed, 0x70, 0x0f, 0xe5, 0x6a, 0xb4, 0x03, 0x05, 0x7f, 0x01, 0x02, 0x2e, 0xeb, 0x7f, 0x02, 0x02, 
+0x2e, 0xeb, 0xaf, 0x6a, 0x12, 0x27, 0x19, 0x74, 0x74, 0x25, 0x6a, 0xf8, 0xe6, 0x30, 0xe2, 0x0b, 
+0xd2, 0x09, 0x12, 0x18, 0x9b, 0xe0, 0x54, 0x7f, 0xf0, 0x80, 0x02, 0xc2, 0x09, 0xe5, 0x6a, 0xb4, 
+0x03, 0x07, 0x7f, 0x81, 0x12, 0x2e, 0xeb, 0x80, 0x05, 0x7f, 0x82, 0x12, 0x2e, 0xeb, 0x30, 0x09, 
+0x07, 0x12, 0x18, 0x9b, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x2f, 0x80, 0x22, 0x12, 0x0f, 0x89, 0x90, 
+0xff, 0xfd, 0xe0, 0x44, 0x60, 0xf0, 0xd2, 0x01, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x02, 0xf0, 0x90, 
+0xff, 0x00, 0xe0, 0x30, 0xe7, 0x13, 0x90, 0xff, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x2c, 0x80, 
+0x90, 0xff, 0xfc, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x0d, 0x12, 0x19, 0x3e, 0x53, 0x2c, 0x7f, 0x90, 
+0xff, 0xfc, 0xe0, 0x54, 0xfe, 0xf0, 0x90, 0xff, 0x81, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x02, 0x9f, 
+0x12, 0x19, 0x46, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, 0x8a, 0x12, 0x20, 0x9e, 0x30, 0xe1, 
+0x07, 0x7f, 0x13, 0x12, 0x2e, 0xa5, 0x80, 0x34, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, 0x16, 
+0x78, 0x8a, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x07, 0x90, 
+0xff, 0xb4, 0xe0, 0x54, 0xdf, 0xf0, 0xc2, 0xb3, 0x90, 0xf9, 0x15, 0xe0, 0x04, 0xf0, 0x78, 0x8a, 
+0xe6, 0xff, 0x12, 0x20, 0x59, 0xfd, 0x12, 0x2d, 0x21, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, 
+0x0f, 0x89, 0x78, 0x8f, 0xef, 0xf6, 0xd2, 0x00, 0x12, 0x27, 0x19, 0x90, 0xf9, 0x66, 0x12, 0x14, 
+0xfd, 0xe9, 0x24, 0x03, 0xf9, 0xe4, 0x3a, 0xfa, 0xc0, 0x02, 0x78, 0x86, 0xe6, 0xfe, 0x08, 0xe6, 
+0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0xd0, 0x02, 0x12, 0x20, 0x4b, 0x12, 0x2f, 0x80, 0x78, 
+0x8f, 0xe6, 0xff, 0x12, 0x19, 0xbb, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x12, 0x0f, 0x89, 0x78, 
+0x8b, 0xef, 0xf6, 0x12, 0x2e, 0x4c, 0x12, 0x2e, 0xa5, 0x90, 0xf9, 0x65, 0xe0, 0x54, 0x03, 0x60, 
+0x16, 0x78, 0x8b, 0xe6, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 
+0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x14, 0xf0, 0xe0, 0x70, 0x02, 
+0xd2, 0xb3, 0x02, 0x10, 0x0c, 0x8f, 0x69, 0x12, 0x27, 0x19, 0x12, 0x20, 0x2d, 0xe0, 0x54, 0x3f, 
+0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x54, 0x3f, 0xf0, 0x08, 0xe6, 0xfe, 0x08, 
+0xe6, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x20, 0x25, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0x74, 
+0x74, 0x25, 0x69, 0xf8, 0x74, 0xfb, 0x56, 0xf6, 0x7f, 0x00, 0x22, 0x8f, 0x37, 0xc2, 0x08, 0x12, 
+0x27, 0x19, 0x12, 0x20, 0x38, 0x78, 0x84, 0x12, 0x20, 0x1d, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x20, 
+0x70, 0x12, 0x20, 0x21, 0xe0, 0x20, 0xe0, 0xf6, 0xef, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 
+0x83, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x2f, 0x80, 0xaf, 0x37, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, 
+0x89, 0x12, 0x27, 0x19, 0x12, 0x20, 0x70, 0x24, 0x06, 0x12, 0x20, 0x23, 0xe0, 0xfd, 0x12, 0x20, 
+0x53, 0x90, 0x00, 0x03, 0x12, 0x20, 0x78, 0x24, 0x05, 0x12, 0x20, 0x25, 0xe0, 0x90, 0x00, 0x04, 
+0x12, 0x14, 0x0d, 0x12, 0x2f, 0x80, 0x7d, 0x02, 0xe4, 0xff, 0x12, 0x2c, 0xc0, 0x02, 0x10, 0x0c, 
+0xae, 0x05, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0x0e, 0x0e, 0x0e, 0xee, 0xd3, 0x95, 0x35, 
+0xe4, 0x95, 0x34, 0x40, 0x02, 0xae, 0x35, 0xee, 0xd3, 0x94, 0x08, 0x74, 0x80, 0x94, 0x81, 0x40, 
+0x0a, 0x7e, 0x03, 0x90, 0x00, 0x02, 0x74, 0x02, 0x12, 0x14, 0x0d, 0xaf, 0x06, 0x12, 0x2f, 0x6a, 
+0x22, 0x12, 0x0f, 0x89, 0x78, 0x8c, 0x12, 0x20, 0x9e, 0x30, 0xe2, 0x07, 0x7f, 0x13, 0x12, 0x2e, 
+0xa5, 0x80, 0x1b, 0x78, 0x8c, 0xe6, 0x24, 0x74, 0xf8, 0xe6, 0x20, 0xe1, 0x07, 0x7f, 0x12, 0x12, 
+0x2e, 0xa5, 0x80, 0x0a, 0x78, 0x8c, 0xe6, 0xff, 0x12, 0x21, 0x6e, 0x12, 0x2e, 0xa5, 0x02, 0x10, 
+0x0c, 0xae, 0x07, 0xed, 0x54, 0x03, 0x64, 0x01, 0x60, 0x03, 0x7f, 0x10, 0x22, 0xed, 0x54, 0x7c, 
+0xc3, 0x94, 0x04, 0x50, 0x03, 0x7f, 0x0b, 0x22, 0x74, 0x74, 0x2e, 0xf8, 0x74, 0x02, 0x46, 0xf6, 
+0x74, 0x95, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xed, 0xf0, 0x7f, 0x00, 0x22, 0xbf, 
+0x03, 0x06, 0x7c, 0xff, 0x7d, 0xe0, 0x80, 0x04, 0x7c, 0xff, 0x7d, 0xe2, 0x8d, 0x82, 0x8c, 0x83, 
+0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x20, 0x25, 0xe0, 0x44, 0x80, 0xf0, 0x74, 
+0x74, 0x2f, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, 0x64, 
+0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x16, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xff, 
+0xc3, 0xe5, 0x31, 0x9f, 0xe5, 0x30, 0x94, 0x00, 0x40, 0x05, 0x12, 0x25, 0x9c, 0x80, 0x03, 0x12, 
+0x2f, 0x76, 0x02, 0x10, 0x0c, 0x90, 0xff, 0xfc, 0xe0, 0x20, 0xe7, 0x1f, 0xc2, 0xaf, 0x7d, 0xff, 
+0xac, 0x05, 0x1d, 0xec, 0x60, 0x15, 0x7e, 0x04, 0x7f, 0x00, 0xef, 0x1f, 0xaa, 0x06, 0x70, 0x01, 
+0x1e, 0x4a, 0x60, 0xec, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0x80, 0xef, 0x22, 0x12, 0x0f, 0x89, 0x78, 
+0x6c, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x30, 0xe0, 0x12, 0x30, 0xe1, 0x0f, 0x90, 0xff, 0xfc, 0xe0, 
+0x44, 0x20, 0xf0, 0x7f, 0x04, 0x12, 0x11, 0x9f, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x8e, 0x65, 
+0x8f, 0x66, 0xe5, 0x66, 0x15, 0x66, 0xae, 0x65, 0x70, 0x02, 0x15, 0x65, 0xd3, 0x94, 0x00, 0xee, 
+0x94, 0x00, 0x40, 0x09, 0x7e, 0x07, 0x7f, 0xd0, 0x12, 0x0f, 0x62, 0x80, 0xe5, 0x22, 0x11, 0x1a, 
+0x2b, 0x1c, 0x23, 0x56, 0x2f, 0x5c, 0x2d, 0xcc, 0x2d, 0x7a, 0x2e, 0x6b, 0x2c, 0x8e, 0x2b, 0x66, 
+0x2b, 0xec, 0x2c, 0xf1, 0x2e, 0x2d, 0x1b, 0xe6, 0x2b, 0xaf, 0x28, 0x67, 0x0e, 0x12, 0x0f, 0x89, 
+0x78, 0x8d, 0x12, 0x20, 0x9e, 0x20, 0xe2, 0x07, 0x7f, 0x11, 0x12, 0x2e, 0xa5, 0x80, 0x0a, 0x78, 
+0x8d, 0xe6, 0xff, 0x12, 0x2c, 0x25, 0x12, 0x2e, 0xa5, 0x02, 0x10, 0x0c, 0x8f, 0x67, 0x12, 0x2c, 
+0x25, 0xaf, 0x67, 0x12, 0x27, 0x19, 0x12, 0x20, 0x38, 0x12, 0x2f, 0x80, 0x74, 0x74, 0x25, 0x67, 
+0xf8, 0x74, 0xfd, 0x56, 0xf6, 0xaf, 0x67, 0x12, 0x19, 0xbb, 0x22, 0x12, 0x0f, 0x89, 0xe5, 0x31, 
+0x64, 0x09, 0x70, 0x04, 0xe5, 0x30, 0x64, 0x01, 0x60, 0x05, 0x12, 0x29, 0x2d, 0x80, 0x06, 0x12, 
+0x19, 0x7a, 0x12, 0x19, 0x82, 0x02, 0x10, 0x0c, 0x12, 0x27, 0xfb, 0x12, 0x12, 0x3b, 0x90, 0xf8, 
+0x04, 0xe0, 0xff, 0x60, 0x05, 0x7d, 0x01, 0x12, 0x11, 0xd8, 0x12, 0x26, 0xa3, 0x12, 0x12, 0x77, 
+0x12, 0x10, 0xfa, 0x80, 0xe3, 0x12, 0x18, 0xed, 0xef, 0x12, 0x14, 0x0d, 0xe4, 0xf5, 0x2a, 0xf5, 
+0x2b, 0xef, 0x60, 0x03, 0x02, 0x2f, 0x76, 0xe4, 0xff, 0x12, 0x2f, 0x6a, 0x22, 0x90, 0xff, 0xf0, 
+0xe0, 0xff, 0x54, 0xa0, 0x60, 0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 
+0xc3, 0x22, 0xd3, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0x28, 0x60, 0xf7, 0xef, 0x30, 0xe5, 
+0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0xef, 0x30, 0xe7, 0x08, 0x12, 
+0x18, 0xad, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0xef, 0x12, 0x18, 0xf7, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 
+0x81, 0x01, 0x82, 0x02, 0x83, 0x03, 0x87, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 
+0x00, 0x40, 0x00, 0x08, 0x00, 0x78, 0x84, 0x12, 0x20, 0x2f, 0xa3, 0xa3, 0xe0, 0xff, 0x30, 0xe7, 
+0x06, 0x54, 0x7f, 0xf0, 0x44, 0x80, 0xf0, 0x22, 0x85, 0x34, 0x30, 0x85, 0x35, 0x31, 0x90, 0xff, 
+0x82, 0xe0, 0x54, 0xf7, 0xf0, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe4, 0xfe, 0xee, 0x90, 0x2f, 
+0x00, 0x93, 0xb5, 0x07, 0x02, 0xd3, 0x22, 0x0e, 0xbe, 0x07, 0xf2, 0xc3, 0x22, 0x00, 0x08, 0x18, 
+0x38, 0x28, 0x01, 0x81, 0x10, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0f, 0x89, 0x7f, 
+0x02, 0x12, 0x10, 0x18, 0x12, 0x19, 0x55, 0x02, 0x10, 0x0c, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x12, 
+0x18, 0x49, 0x12, 0x29, 0x2d, 0x22, 0x12, 0x19, 0x82, 0x12, 0x19, 0x3e, 0x12, 0x19, 0x7a, 0x22, 
+0xc2, 0x08, 0x22, 
+};
+
+#undef IMAGE_VERSION_NAME
+
+#undef IMAGE_ARRAY_NAME
+
diff -urN linux-2.4.20-pre1/drivers/usb/serial/io_ti.c linux-2.4.20-pre2/drivers/usb/serial/io_ti.c
--- linux-2.4.20-pre1/drivers/usb/serial/io_ti.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/serial/io_ti.c	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,2727 @@
+/*
+ * Edgeport USB Serial Converter driver
+ *
+ * Copyright(c) 2000-2002 Inside Out Networks, All rights reserved.
+ * Copyright(c) 2001-2002 Greg Kroah-Hartman <greg@kroah.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.
+ *
+ * Supports the following devices:
+ *	EP/1 EP/2 EP/4
+ *
+ * Version history:
+ *
+ *	July 11, 2002 	Removed 4 port device structure since all TI UMP 
+ *			chips have only 2 ports 
+ *			David Iacovelli (davidi@ionetworks.com)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/serial.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+#include "usb-serial.h"
+
+#include "io_16654.h"
+#include "io_usbvend.h"
+#include "io_ti.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.2"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
+#define DRIVER_DESC "Edgeport USB Serial Driver"
+
+
+/* firmware image code */
+#define IMAGE_VERSION_NAME	PagableOperationalCodeImageVersion
+#define IMAGE_ARRAY_NAME	PagableOperationalCodeImage
+#define IMAGE_SIZE		PagableOperationalCodeSize
+#include "io_fw_down3.h"	/* Define array OperationalCodeImage[] */
+
+#define EPROM_PAGE_SIZE		64
+
+
+struct edgeport_uart_buf_desc {
+	__u32 count;		// Number of bytes currently in buffer
+};
+
+/* different hardware types */
+#define HARDWARE_TYPE_930	0
+#define HARDWARE_TYPE_TIUMP	1
+
+// IOCTL_PRIVATE_TI_GET_MODE Definitions
+#define	TI_MODE_CONFIGURING	0   // Device has not entered start device 
+#define	TI_MODE_BOOT		1   // Staying in boot mode
+#define TI_MODE_DOWNLOAD	2   // Made it to download mode
+#define TI_MODE_TRANSITIONING	3   // Currently in boot mode but transitioning to download mode
+
+
+/* Product information read from the Edgeport */
+struct product_info
+{
+	int	TiMode;			// Current TI Mode
+	__u8	hardware_type;		// Type of hardware
+} __attribute__((packed));
+
+
+struct edgeport_port {
+	__u16 uart_base;
+	__u16 dma_address;
+	__u8 shadow_msr;
+	__u8 shadow_mcr;
+	__u8 shadow_lsr;
+	__u8 lsr_mask;
+	__u32 ump_read_timeout;		/* Number of miliseconds the UMP will
+					   wait without data before completing
+					   a read short */
+	int baud_rate;
+	int close_pending;
+	int lsr_event;
+	struct edgeport_uart_buf_desc tx;
+	struct async_icount	icount;
+	wait_queue_head_t	delta_msr_wait;	/* for handling sleeping while
+						   waiting for msr change to
+						   happen */
+	struct edgeport_serial	*edge_serial;
+	struct usb_serial_port	*port;
+};
+
+struct edgeport_serial {
+	struct product_info product_info;
+	u8 TI_I2C_Type;			// Type of I2C in UMP
+	u8 TiReadI2C;			// Set to TRUE if we have read the I2c in Boot Mode
+	int num_ports_open;
+	struct usb_serial *serial;
+};
+
+
+/* Devices that this driver supports */
+static struct usb_device_id edgeport_1port_id_table [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
+	{ }
+};
+
+static struct usb_device_id edgeport_2port_id_table [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) },
+	{ }
+};
+
+/* Devices that this driver supports */
+static __devinitdata struct usb_device_id id_table_combined [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_DOWN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_BOOT) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21_DOWN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_combined);
+
+
+static EDGE_FIRMWARE_VERSION_INFO OperationalCodeImageVersion;
+
+static int TIStayInBootMode = 0;
+static int ignore_cpu_rev = 0;
+
+
+
+static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+
+static int TIReadVendorRequestSync (struct usb_device *dev,
+				__u8		request,
+				__u16		value,
+				__u16		index,
+				u8 		*data,
+				int		size)
+{
+	int status;
+
+	status = usb_control_msg (dev,
+				usb_rcvctrlpipe(dev, 0),
+				request,
+				(USB_TYPE_VENDOR | 
+				 USB_RECIP_DEVICE | 
+				 USB_DIR_IN),
+				value,
+				index,
+				data,
+				size,
+				HZ);
+	if (status < 0)
+		return status;
+	if (status != size) {
+		dbg ("%s - wanted to write %d, but only wrote %d",
+		     __FUNCTION__, size, status);
+		return -ECOMM;
+	}
+	return 0;
+}
+
+static int TISendVendorRequestSync (struct usb_device *dev,
+				__u8		request,
+				__u16		value,
+				__u16		index,
+				u8 		*data,
+				int		size)
+{
+	int status;
+
+	status = usb_control_msg (dev,
+				usb_sndctrlpipe(dev, 0),
+				request,
+				(USB_TYPE_VENDOR | 
+				 USB_RECIP_DEVICE | 
+				 USB_DIR_OUT),
+				value,
+				index,
+				data,
+				size,
+				HZ);
+
+	if (status < 0)
+		return status;
+	if (status != size) {
+		dbg ("%s - wanted to write %d, but only wrote %d",
+		     __FUNCTION__, size, status);
+		return -ECOMM;
+	}
+	return 0;
+}
+
+static int TIWriteCommandSync (struct usb_device *dev, __u8 command,
+				__u8 moduleid, __u16 value, u8 *data,
+				int size)
+{
+	return TISendVendorRequestSync (dev,
+					  command,	  		// Request
+					  value,			// wValue 
+					  moduleid,			// wIndex
+					  data,				// TransferBuffer
+					  size);			// TransferBufferLength
+
+}
+
+
+/* clear tx/rx buffers and fifo in TI UMP */
+static int TIPurgeDataSync (struct usb_serial_port *port, __u16 mask)
+{
+	int port_number = port->number - port->serial->minor;
+
+	dbg ("%s - port %d, mask %x", __FUNCTION__, port_number, mask);
+
+	return TIWriteCommandSync (port->serial->dev,
+					UMPC_PURGE_PORT,
+					(__u8)(UMPM_UART1_PORT + port_number),
+					mask,
+					NULL,
+					0);
+}
+
+/**
+ * TIReadDownloadMemory - Read edgeport memory from TI chip
+ * @dev: usb device pointer
+ * @address: Device CPU address at which to read
+ * @length: Length of above data
+ * @address_type: Can read both XDATA and I2C
+ * @buffer: pointer to input data buffer
+ */
+int TIReadDownloadMemory (struct usb_device *dev, int start_address, int length,
+			  __u8 address_type, __u8 *buffer)
+{
+	int status = 0;
+	__u8 read_length;
+	__u16 be_start_address;
+	
+	dbg ("%s - @ %x for %d", __FUNCTION__, start_address, length);
+
+	/* Read in blocks of 64 bytes
+	 * (TI firmware can't handle more than 64 byte reads)
+	 */
+	while (length) {
+		if (length > 64)
+			read_length= 64;
+		else
+			read_length = (__u8)length;
+
+		if (read_length > 1) {
+			dbg ("%s - @ %x for %d", __FUNCTION__, 
+			     start_address, read_length);
+		}
+		be_start_address = cpu_to_be16 (start_address);
+		status = TIReadVendorRequestSync (dev,
+						  UMPC_MEMORY_READ,	// Request
+						  (__u16)address_type,	// wValue (Address type)
+						  be_start_address,	// wIndex (Address to read)
+						  buffer,		// TransferBuffer
+						  read_length);	// TransferBufferLength
+
+		if (status) {
+			dbg ("%s - ERROR %x", __FUNCTION__, status);
+			return status;
+		}
+
+		if (read_length > 1) {
+			usb_serial_debug_data (__FILE__, __FUNCTION__,
+					       read_length, buffer);
+		}
+
+		/* Update pointers/length */
+		start_address += read_length;
+		buffer += read_length;
+		length -= read_length;
+	}
+	
+	return status;
+}
+
+int TIReadRam (struct usb_device *dev, int start_address, int length, __u8 *buffer)
+{
+	return TIReadDownloadMemory (dev,
+				     start_address,
+				     length,
+				     DTK_ADDR_SPACE_XDATA,
+				     buffer);
+}
+
+/* Read edgeport memory to a given block */
+static int TIReadBootMemory (struct edgeport_serial *serial, int start_address, int length, __u8 * buffer)
+{
+	int status = 0;
+	int i;
+
+	for (i=0; i< length; i++) {
+		status = TIReadVendorRequestSync (serial->serial->dev,
+					UMPC_MEMORY_READ,		// Request
+					serial->TI_I2C_Type,		// wValue (Address type)
+					(__u16)(start_address+i),	// wIndex
+					&buffer[i],			// TransferBuffer
+					0x01);				// TransferBufferLength
+		if (status) {
+			dbg ("%s - ERROR %x", __FUNCTION__, status);
+			return status;
+		}
+	}
+
+	dbg ("%s - start_address = %x, length = %d", __FUNCTION__, start_address, length);
+	usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
+
+	serial->TiReadI2C = 1;
+
+	return status;
+}
+
+/* Write given block to TI EPROM memory */
+static int TIWriteBootMemory (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
+{
+	int status = 0;
+	int i;
+	__u8 temp;
+
+	/* Must do a read before write */
+	if (!serial->TiReadI2C) {
+		status = TIReadBootMemory(serial, 0, 1, &temp);
+		if (status)
+			return status;
+	}
+
+	for (i=0; i < length; ++i) {
+		status = TISendVendorRequestSync (serial->serial->dev,
+						UMPC_MEMORY_WRITE,		// Request
+						buffer[i],			// wValue
+						(__u16)(i+start_address),	// wIndex
+						NULL,				// TransferBuffer
+						0);				// TransferBufferLength
+		if (status)
+			return status;
+	}
+
+  	dbg ("%s - start_sddr = %x, length = %d", __FUNCTION__, start_address, length);
+	usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer);
+
+	return status;
+}
+
+
+/* Write edgeport I2C memory to TI chip	*/
+static int TIWriteDownloadI2C (struct edgeport_serial *serial, int start_address, int length, __u8 address_type, __u8 *buffer)
+{
+	int status = 0;
+	int write_length;
+	__u16 be_start_address;
+
+	/* We can only send a maximum of 1 aligned byte page at a time */
+	
+	/* calulate the number of bytes left in the first page */
+	write_length = EPROM_PAGE_SIZE - (start_address & (EPROM_PAGE_SIZE - 1));
+
+	if (write_length > length)
+		write_length = length;
+
+	dbg ("%s - BytesInFirstPage Addr = %x, length = %d", __FUNCTION__, start_address, write_length);
+	usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer);
+
+	/* Write first page */
+	be_start_address = cpu_to_be16 (start_address);
+	status = TISendVendorRequestSync (serial->serial->dev,
+					UMPC_MEMORY_WRITE,	// Request
+					(__u16)address_type,	// wValue
+					be_start_address,	// wIndex
+					buffer,			// TransferBuffer
+					write_length);
+	if (status) {
+		dbg ("%s - ERROR %d", __FUNCTION__, status);
+		return status;
+	}
+
+	length		-= write_length;
+	start_address	+= write_length;
+	buffer		+= write_length;
+
+	/* We should be aligned now -- can write max page size bytes at a time */
+	while (length) {
+		if (length > EPROM_PAGE_SIZE)
+			write_length = EPROM_PAGE_SIZE;
+		else
+			write_length = length;
+
+		dbg ("%s - Page Write Addr = %x, length = %d", __FUNCTION__, start_address, write_length);
+		usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer);
+
+		/* Write next page */
+		be_start_address = cpu_to_be16 (start_address);
+		status = TISendVendorRequestSync (serial->serial->dev,
+						UMPC_MEMORY_WRITE,	// Request
+						(__u16)address_type,	// wValue
+						be_start_address,	// wIndex
+						buffer,	  		// TransferBuffer
+						write_length);		// TransferBufferLength
+		if (status) {
+			dbg ("%s - ERROR %d", __FUNCTION__, status);
+			return status;
+		}
+		
+		length		-= write_length;
+		start_address	+= write_length;
+		buffer		+= write_length;
+	}
+	return status;
+}
+
+/* Examine the UMP DMA registers and LSR
+ * 
+ * Check the MSBit of the X and Y DMA byte count registers.
+ * A zero in this bit indicates that the TX DMA buffers are empty
+ * then check the TX Empty bit in the UART.
+ */
+static int TIIsTxActive (struct edgeport_port *port)
+{
+	int status;
+	struct out_endpoint_desc_block *oedb;
+	__u8 lsr;
+	int bytes_left = 0;
+
+	oedb = kmalloc (sizeof (* oedb), GFP_KERNEL);
+	if (!oedb) {
+		err ("%s - out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	/* Read the DMA Count Registers */
+	status = TIReadRam (port->port->serial->dev,
+			    port->dma_address,
+			    sizeof( *oedb),
+			    (void *)oedb);
+
+	if (status)
+		goto exit_is_tx_active;
+
+	dbg ("%s - XByteCount    0x%X", __FUNCTION__, oedb->XByteCount);
+
+	/* and the LSR */
+	status = TIReadRam (port->port->serial->dev, 
+			    port->uart_base + UMPMEM_OFFS_UART_LSR,
+			    1,
+			    &lsr);
+
+	if (status)
+		goto exit_is_tx_active;
+	dbg ("%s - LSR = 0x%X", __FUNCTION__, lsr);
+	
+	/* If either buffer has data or we are transmitting then return TRUE */
+	if ((oedb->XByteCount & 0x80 ) != 0 )
+		bytes_left += 64;
+
+//	if ((oedb->YByteCount & 0x80 ) != 0 ) 
+//		bytes_left += 64;
+
+	if ((lsr & UMP_UART_LSR_TX_MASK ) == 0 )
+		bytes_left += 1;
+
+// We return Not Active if we get any kind of error
+exit_is_tx_active:
+	dbg ("%s - return %d", __FUNCTION__, bytes_left );
+	return bytes_left;
+}
+
+static void TIChasePort(struct edgeport_port *port)
+{
+	int loops;
+	int last_count;
+	int write_size;
+
+restart_tx_loop:
+	// Base the LoopTime on the baud rate
+	if (port->baud_rate == 0)
+		port->baud_rate = 1200;
+
+	write_size = port->tx.count;
+	loops = max(100, (100*write_size)/(port->baud_rate/10));
+	dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__,
+	     write_size, port->baud_rate, loops);
+
+	while (1) {
+//		// Is it Stopped?
+//		if ( !DevExt->Started )
+//			return;
+
+		// Save Last count
+		last_count = port->tx.count;
+
+		dbg ("%s - Tx Buffer Size = %d loops = %d", __FUNCTION__,
+		     last_count, loops);
+
+		/* Is the Edgeport Buffer empty? */
+//		if ((port->tx.count == 0) && (port->CurrentWriteIrp == NULL)) {
+		if (port->tx.count == 0)
+			break;
+
+		/* Block the thread for 10ms */
+		wait_ms (10);
+
+		if (last_count == port->tx.count) {
+			/* No activity.. count down. */
+			--loops;
+			if (loops == 0) {
+				dbg ("%s - Wait for TxEmpty - TIMEOUT",
+				     __FUNCTION__);
+				return;
+			}
+		} else {
+			/* Reset timeout value back to a minimum of 1 second */
+			dbg ("%s - Wait for TxEmpty  Reset Count", __FUNCTION__);
+			goto restart_tx_loop;
+		}
+	}
+
+	dbg ("%s - Local Tx Buffer Empty -- Waiting for TI UMP to EMPTY X/Y and FIFO",
+	     __FUNCTION__);
+
+	write_size = TIIsTxActive (port);
+	loops = max(50, (100*write_size)/(port->baud_rate/10));
+	dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__, 
+	     write_size, port->baud_rate, loops);
+
+	while (1) {
+//		// Is it Stopped?
+//		if ( !DevExt->Started )
+//			return;
+
+		/* This function takes 4 ms; */
+		if (!TIIsTxActive (port)) {
+			/* Delay a few char times */
+			wait_ms (50);
+			dbg ("%s - Empty", __FUNCTION__);
+			return;
+		}
+
+		--loops;
+		if (loops == 0) {
+			dbg ("%s - TIMEOUT", __FUNCTION__);
+			return;
+		}
+	}
+}
+
+static int TIChooseConfiguration (struct usb_device *dev)
+{
+	// There may be multiple configurations on this device, in which case
+	// we would need to read and parse all of them to find out which one
+	// we want. However, we just support one config at this point,
+	// configuration # 1, which is Config Descriptor 0.
+
+	dbg ("%s - Number of Interfaces = %d", __FUNCTION__, dev->config->bNumInterfaces);
+	dbg ("%s - MAX Power            = %d", __FUNCTION__, dev->config->MaxPower*2);
+
+	if (dev->config->bNumInterfaces != 1) {
+		err ("%s - bNumInterfaces is not 1, ERROR!", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+int TIReadRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
+{
+	int status;
+
+	if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) {
+		status = TIReadDownloadMemory (serial->serial->dev,
+					       start_address,
+					       length,
+					       serial->TI_I2C_Type,
+					       buffer);
+	} else {
+		status = TIReadBootMemory (serial,
+					   start_address,
+					   length,
+					   buffer);
+	}
+
+	return status;
+}
+
+int TIWriteRom (struct edgeport_serial *serial, int start_address, int length, __u8 *buffer)
+{
+	if (serial->product_info.TiMode == TI_MODE_BOOT)
+		return TIWriteBootMemory (serial,
+					  start_address,
+					  length,
+					  buffer);
+
+	if (serial->product_info.TiMode == TI_MODE_DOWNLOAD)
+		return TIWriteDownloadI2C (serial,
+					   start_address,
+					   length,
+					   serial->TI_I2C_Type,
+					   buffer);
+
+	return -EINVAL;
+}
+
+
+
+/* Read a descriptor header from I2C based on type */
+static int TIGetDescriptorAddress (struct edgeport_serial *serial, int desc_type, struct ti_i2c_desc *rom_desc)
+{
+	int start_address;
+	int status;
+
+	/* Search for requested descriptor in I2C */
+	start_address = 2;
+	do {
+		status = TIReadRom (serial,
+				   start_address,
+				   sizeof(struct ti_i2c_desc),
+				   (__u8 *)rom_desc );
+		if (status)
+			return 0;
+
+		if (rom_desc->Type == desc_type)
+			return start_address;
+
+		start_address = start_address + sizeof(struct ti_i2c_desc) +  rom_desc->Size;
+
+	} while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type);
+	
+	return 0;
+}
+
+/* Validate descriptor checksum */
+static int ValidChecksum(struct ti_i2c_desc *rom_desc, __u8 *buffer)
+{
+	__u16 i;
+	__u8 cs = 0;
+
+	for (i=0; i < rom_desc->Size; i++) {
+		cs = (__u8)(cs + buffer[i]);
+	}
+	if (cs != rom_desc->CheckSum) {
+		dbg ("%s - Mismatch %x - %x", __FUNCTION__, rom_desc->CheckSum, cs);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Make sure that the I2C image is good */
+static int TiValidateI2cImage (struct edgeport_serial *serial)
+{
+	int status = 0;
+	struct ti_i2c_desc *rom_desc;
+	int start_address = 2;
+	__u8 *buffer;
+
+	rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
+	if (!rom_desc) {
+		err ("%s - out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+	buffer = kmalloc (TI_MAX_I2C_SIZE, GFP_KERNEL);
+	if (!buffer) {
+		err ("%s - out of memory when allocating buffer", __FUNCTION__);
+		kfree (rom_desc);
+		return -ENOMEM;
+	}
+
+	// Read the first byte (Signature0) must be 0x52
+	status = TIReadRom (serial, 0, 1, buffer);
+	if (status)
+		goto ExitTiValidateI2cImage; 
+
+	if (*buffer != 0x52) {
+		err ("%s - invalid buffer signature", __FUNCTION__);
+		status = -ENODEV;
+		goto ExitTiValidateI2cImage;
+	}
+
+	do {
+		// Validate the I2C
+		status = TIReadRom (serial,
+				start_address,
+				sizeof(struct ti_i2c_desc),
+				(__u8 *)rom_desc);
+		if (status)
+			break;
+
+		if ((start_address + sizeof(struct ti_i2c_desc) + rom_desc->Size) > TI_MAX_I2C_SIZE) {
+			status = -ENODEV;
+			dbg ("%s - structure too big, erroring out.", __FUNCTION__);
+			break;
+		}
+
+		dbg ("%s Type = 0x%x", __FUNCTION__, rom_desc->Type);
+
+		// Skip type 2 record
+		if ((rom_desc->Type & 0x0f) != I2C_DESC_TYPE_FIRMWARE_BASIC) {
+			// Read the descriptor data
+			status = TIReadRom(serial,
+						start_address+sizeof(struct ti_i2c_desc),
+						rom_desc->Size,
+						buffer);
+			if (status)
+				break;
+
+			status = ValidChecksum(rom_desc, buffer);
+			if (status)
+				break;
+		}
+		start_address = start_address + sizeof(struct ti_i2c_desc) + rom_desc->Size;
+
+	} while ((rom_desc->Type != I2C_DESC_TYPE_ION) && (start_address < TI_MAX_I2C_SIZE));
+
+	if ((rom_desc->Type != I2C_DESC_TYPE_ION) || (start_address > TI_MAX_I2C_SIZE))
+		status = -ENODEV;
+
+ExitTiValidateI2cImage:	
+	kfree (buffer);
+	kfree (rom_desc);
+	return status;
+}
+
+static int TIReadManufDescriptor (struct edgeport_serial *serial, __u8 *buffer)
+{
+	int status;
+	int start_address;
+	struct ti_i2c_desc *rom_desc;
+	struct edge_ti_manuf_descriptor *desc;
+
+	rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
+	if (!rom_desc) {
+		err ("%s - out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+	start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_ION, rom_desc);
+
+	if (!start_address) {
+		dbg ("%s - Edge Descriptor not found in I2C", __FUNCTION__);
+		status = -ENODEV;
+		goto exit;
+	}
+
+	// Read the descriptor data
+	status = TIReadRom (serial,
+				start_address+sizeof(struct ti_i2c_desc),
+				rom_desc->Size,
+				buffer);
+	if (status)
+		goto exit;
+	
+	status = ValidChecksum(rom_desc, buffer);
+	
+	desc = (struct edge_ti_manuf_descriptor *)buffer;
+	dbg ( "%s - IonConfig      0x%x", __FUNCTION__, desc->IonConfig 	);
+	dbg ( "%s - Version          %d", __FUNCTION__, desc->Version	  	);
+	dbg ( "%s - Cpu/Board      0x%x", __FUNCTION__, desc->CpuRev_BoardRev	);
+	dbg ( "%s - NumPorts         %d", __FUNCTION__, desc->NumPorts  	);	
+	dbg ( "%s - NumVirtualPorts  %d", __FUNCTION__, desc->NumVirtualPorts	);	
+	dbg ( "%s - TotalPorts       %d", __FUNCTION__, desc->TotalPorts  	);	
+
+exit:
+	kfree (rom_desc);
+	return status;
+}
+
+/* Build firmware header used for firmware update */
+static int BuildI2CFirmwareHeader (__u8 *header)
+{
+	__u8 *buffer;
+	int buffer_size;
+	int i;
+	__u8 cs = 0;
+	struct ti_i2c_desc *i2c_header;
+	struct ti_i2c_image_header *img_header;
+	struct ti_i2c_firmware_rec *firmware_rec;
+
+	// In order to update the I2C firmware we must change the type 2 record to type 0xF2.
+	// This will force the UMP to come up in Boot Mode.  Then while in boot mode, the driver 
+	// will download the latest firmware (padded to 15.5k) into the UMP ram. 
+	// And finally when the device comes back up in download mode the driver will cause 
+	// the new firmware to be copied from the UMP Ram to I2C and the firmware will update
+	// the record type from 0xf2 to 0x02.
+	
+	// Allocate a 15.5k buffer + 2 bytes for version number (Firmware Record)
+	buffer_size = (((1024 * 16) - 512 )+ sizeof(struct ti_i2c_firmware_rec));
+
+	buffer = kmalloc (buffer_size, GFP_KERNEL);
+	if (!buffer) {
+		err ("%s - out of memory", __FUNCTION__);
+		return -ENOMEM;
+	}
+	
+	// Set entire image of 0xffs
+	memset (buffer, 0xff, buffer_size);
+
+	// Copy version number into firmware record
+	firmware_rec = (struct ti_i2c_firmware_rec *)buffer;
+
+	firmware_rec->Ver_Major	= OperationalCodeImageVersion.MajorVersion;
+	firmware_rec->Ver_Minor	= OperationalCodeImageVersion.MinorVersion;
+
+	// Pointer to fw_down memory image
+	img_header = (struct ti_i2c_image_header *)&PagableOperationalCodeImage[0];
+
+	memcpy (buffer + sizeof(struct ti_i2c_firmware_rec),
+		&PagableOperationalCodeImage[sizeof(struct ti_i2c_image_header)],
+		img_header->Length);
+
+	for (i=0; i < buffer_size; i++) {
+		cs = (__u8)(cs + buffer[i]);
+	}
+
+	kfree (buffer);
+
+	// Build new header
+	i2c_header =  (struct ti_i2c_desc *)header;
+	firmware_rec =  (struct ti_i2c_firmware_rec*)i2c_header->Data;
+	
+	i2c_header->Type	= I2C_DESC_TYPE_FIRMWARE_BLANK;
+	i2c_header->Size	= (__u16)buffer_size;
+	i2c_header->CheckSum	= cs;
+	firmware_rec->Ver_Major	= OperationalCodeImageVersion.MajorVersion;
+	firmware_rec->Ver_Minor	= OperationalCodeImageVersion.MinorVersion;
+
+	return 0;
+}
+
+/* Try to figure out what type of I2c we have */
+static int TIGetI2cTypeInBootMode (struct edgeport_serial *serial)
+{
+	int status;
+	__u8 data;
+		
+	// Try to read type 2
+	status = TIReadVendorRequestSync (serial->serial->dev,
+					UMPC_MEMORY_READ,		// Request
+					DTK_ADDR_SPACE_I2C_TYPE_II,	// wValue (Address type)
+					0,		 		// wIndex
+					&data,				// TransferBuffer
+					0x01);				// TransferBufferLength
+	if (status)
+		dbg ("%s - read 2 status error = %d", __FUNCTION__, status);
+	else
+		dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
+	if ((!status) && data == 0x52) {
+		dbg ("%s - ROM_TYPE_II", __FUNCTION__);
+		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
+		return 0;
+	}
+
+	// Try to read type 3
+	status = TIReadVendorRequestSync (serial->serial->dev,
+					UMPC_MEMORY_READ,		// Request
+					DTK_ADDR_SPACE_I2C_TYPE_III,	// wValue (Address type)
+					0,				// wIndex
+					&data,				// TransferBuffer
+					0x01);				// TransferBufferLength
+	if (status)
+		dbg ("%s - read 3 status error = %d", __FUNCTION__, status);
+	else
+		dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data);
+	if ((!status) && data == 0x52) {
+		dbg ("%s - ROM_TYPE_III", __FUNCTION__);
+		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
+		return 0;
+	}
+
+	dbg ("%s - Unknown", __FUNCTION__);
+	serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
+	return -ENODEV;
+}
+
+static int TISendBulkTransferSync (struct usb_serial *serial, void *buffer, int length, int *num_sent)
+{
+	int status;
+
+	status = usb_bulk_msg (serial->dev,
+				usb_sndbulkpipe(serial->dev,
+						serial->port[0].bulk_out_endpointAddress),
+				buffer,
+				length,
+				num_sent,
+				HZ);
+	return status;
+}
+
+/* Download given firmware image to the device (IN BOOT MODE) */
+static int TIDownloadCodeImage (struct edgeport_serial *serial, __u8 *image, int image_length)
+{
+	int status = 0;
+	int pos;
+	int transfer;
+	int done;
+
+	// Transfer firmware image
+	for (pos = 0; pos < image_length; ) {
+		// Read the next buffer from file
+		transfer = image_length - pos;
+		if (transfer > EDGE_FW_BULK_MAX_PACKET_SIZE)
+			transfer = EDGE_FW_BULK_MAX_PACKET_SIZE;
+
+		// Transfer data
+		status = TISendBulkTransferSync (serial->serial, &image[pos], transfer, &done);
+		if (status)
+			break;
+		// Advance buffer pointer
+		pos += done;
+	}
+
+	return status;
+}
+
+// FIXME!!!
+static int TIConfigureBootDevice (struct usb_device *dev)
+{
+	return 0;
+}
+
+/**
+ * DownloadTIFirmware - Download run-time operating firmware to the TI5052
+ * 
+ * This routine downloads the main operating code into the TI5052, using the
+ * boot code already burned into E2PROM or ROM.
+ */
+static int TIDownloadFirmware (struct edgeport_serial *serial)
+{
+	int status = 0;
+	int start_address;
+	struct edge_ti_manuf_descriptor *ti_manuf_desc;
+	struct usb_interface_descriptor *interface;
+	int download_cur_ver;
+	int download_new_ver;
+//	PUSB_CONFIGURATION_DESCRIPTOR	ConfigDesc;
+//	PUSB_INTERFACE_DESCRIPTOR	pDesc;
+//	PVOID 				MemHandle;
+
+	/* This routine is entered by both the BOOT mode and the Download mode
+	 * We can determine which code is running by the reading the config
+	 * descriptor and if we have only one bulk pipe it is in boot mode
+	 */
+	serial->product_info.hardware_type = HARDWARE_TYPE_TIUMP;
+
+	/* Default to type 2 i2c */
+	serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
+
+	status = TIChooseConfiguration (serial->serial->dev);
+	if (status)
+		return status;
+
+	interface = serial->serial->dev->config->interface->altsetting;
+	if (!interface) {
+		err ("%s - no interface set, error!", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	// Setup initial mode -- the default mode 0 is TI_MODE_CONFIGURING
+	// if we have more than one endpoint we are definitely in download mode
+	if (interface->bNumEndpoints > 1)
+		serial->product_info.TiMode = TI_MODE_DOWNLOAD;
+	else
+		// Otherwise we will remain in configuring mode
+		serial->product_info.TiMode = TI_MODE_CONFIGURING;
+
+	// Save Download Version Number
+	OperationalCodeImageVersion.MajorVersion = PagableOperationalCodeImageVersion.MajorVersion;
+	OperationalCodeImageVersion.MinorVersion = PagableOperationalCodeImageVersion.MinorVersion;
+	OperationalCodeImageVersion.BuildNumber	 = PagableOperationalCodeImageVersion.BuildNumber;
+
+	/********************************************************************/
+	/* Download Mode */
+	/********************************************************************/
+	if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) {
+		struct ti_i2c_desc *rom_desc;
+
+		dbg ("%s - <<<<<<<<<<<<<<<RUNNING IN DOWNLOAD MODE>>>>>>>>>>", __FUNCTION__);
+
+		status = TiValidateI2cImage (serial);
+		if (status) {
+			dbg ("%s - <<<<<<<<<<<<<<<DOWNLOAD MODE -- BAD I2C >>>>>>>>>>",
+			     __FUNCTION__);
+			return status;
+		}
+		
+		/* Validate Hardware version number
+		 * Read Manufacturing Descriptor from TI Based Edgeport
+		 */
+		ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL);
+		if (!ti_manuf_desc) {
+			err ("%s - out of memory.", __FUNCTION__);
+			return -ENOMEM;
+		}
+		status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc);
+		if (status) {
+			kfree (ti_manuf_desc);
+			return status;
+		}
+
+		// Check version number of ION descriptor
+		if (!ignore_cpu_rev && TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev) < 2) {
+			dbg ( "%s - Wrong CPU Rev %d (Must be 2)", __FUNCTION__, 
+			     TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev));
+			kfree (ti_manuf_desc);
+		   	return -EINVAL;
+		}
+
+		rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL);
+		if (!rom_desc) {
+			err ("%s - out of memory.", __FUNCTION__);
+			kfree (ti_manuf_desc);
+			return -ENOMEM;
+		}
+
+		// Search for type 2 record (firmware record)
+		if ((start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc)) != 0) {
+			struct ti_i2c_firmware_rec *firmware_version;
+			__u8 record;
+
+			dbg ("%s - Found Type FIRMWARE (Type 2) record", __FUNCTION__);
+
+			firmware_version = kmalloc (sizeof (*firmware_version), GFP_KERNEL);
+			if (!firmware_version) {
+				err ("%s - out of memory.", __FUNCTION__);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return -ENOMEM;
+			}
+
+			// Validate version number				
+			// Read the descriptor data
+			status = TIReadRom (serial,
+					start_address+sizeof(struct ti_i2c_desc),
+					sizeof(struct ti_i2c_firmware_rec),
+					(__u8 *)firmware_version);
+			if (status) {
+				kfree (firmware_version);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+
+			// Check version number of download with current version in I2c
+			download_cur_ver = (firmware_version->Ver_Major << 8) + 
+					   (firmware_version->Ver_Minor);
+			download_new_ver = (OperationalCodeImageVersion.MajorVersion << 8) +
+					   (OperationalCodeImageVersion.MinorVersion);
+
+			dbg ("%s - >>>Firmware Versions Device %d.%d  Driver %d.%d",
+			     __FUNCTION__,
+			     firmware_version->Ver_Major,
+			     firmware_version->Ver_Minor,
+			     OperationalCodeImageVersion.MajorVersion,
+			     OperationalCodeImageVersion.MinorVersion);
+
+			// Check if we have an old version in the I2C and update if necessary
+			if (download_cur_ver != download_new_ver) {
+				dbg ("%s - Update I2C Download from %d.%d to %d.%d",
+				     __FUNCTION__,
+				     firmware_version->Ver_Major,
+				     firmware_version->Ver_Minor,
+				     OperationalCodeImageVersion.MajorVersion,
+				     OperationalCodeImageVersion.MinorVersion);
+
+				// In order to update the I2C firmware we must change the type 2 record to type 0xF2.
+				// This will force the UMP to come up in Boot Mode.  Then while in boot mode, the driver 
+				// will download the latest firmware (padded to 15.5k) into the UMP ram. 
+				// And finally when the device comes back up in download mode the driver will cause 
+				// the new firmware to be copied from the UMP Ram to I2C and the firmware will update
+				// the record type from 0xf2 to 0x02.
+
+				record = I2C_DESC_TYPE_FIRMWARE_BLANK;
+
+				// Change the I2C Firmware record type to 0xf2 to trigger an update
+				status = TIWriteRom (serial,
+							start_address,
+							sizeof(record),
+							&record);
+				if (status) {
+					kfree (firmware_version);
+					kfree (rom_desc);
+					kfree (ti_manuf_desc);
+					return status;
+				}
+
+				// verify the write -- must do this in order for write to 
+				// complete before we do the hardware reset
+				status = TIReadRom (serial,
+							start_address,
+							sizeof(record),
+							&record);
+
+				if (status) {
+					kfree (firmware_version);
+					kfree (rom_desc);
+					kfree (ti_manuf_desc);
+					return status;
+				}
+
+				if (record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
+					err ("%s - error resetting device", __FUNCTION__);
+					kfree (firmware_version);
+					kfree (rom_desc);
+					kfree (ti_manuf_desc);
+					return -ENODEV;
+				}
+
+				dbg ("%s - HARDWARE RESET", __FUNCTION__);
+
+				// Reset UMP -- Back to BOOT MODE
+				status = TISendVendorRequestSync (serial->serial->dev,
+								UMPC_HARDWARE_RESET,	// Request
+								0,			// wValue
+								0,			// wIndex
+								NULL,			// TransferBuffer
+								0);			// TransferBufferLength
+
+				dbg ( "%s - HARDWARE RESET return %d", __FUNCTION__, status);
+
+				/* return an error on purpose. */
+				return -ENODEV;
+			}
+		}
+		// Search for type 0xF2 record (firmware blank record)
+		else if ((start_address = TIGetDescriptorAddress (serial, I2C_DESC_TYPE_FIRMWARE_BLANK, rom_desc)) != 0) {
+			#define HEADER_SIZE	(sizeof(struct ti_i2c_desc) + sizeof(struct ti_i2c_firmware_rec))
+			__u8 *header;
+			__u8 *vheader;
+
+			header  = kmalloc (HEADER_SIZE, GFP_KERNEL);
+			if (!header) {
+				err ("%s - out of memory.", __FUNCTION__);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return -ENOMEM;
+			}
+				
+			vheader = kmalloc (HEADER_SIZE, GFP_KERNEL);
+			if (!vheader) {
+				err ("%s - out of memory.", __FUNCTION__);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return -ENOMEM;
+			}
+			
+			dbg ("%s - Found Type BLANK FIRMWARE (Type F2) record", __FUNCTION__);
+
+			// In order to update the I2C firmware we must change the type 2 record to type 0xF2.
+			// This will force the UMP to come up in Boot Mode.  Then while in boot mode, the driver 
+			// will download the latest firmware (padded to 15.5k) into the UMP ram. 
+			// And finally when the device comes back up in download mode the driver will cause 
+			// the new firmware to be copied from the UMP Ram to I2C and the firmware will update
+			// the record type from 0xf2 to 0x02.
+			status = BuildI2CFirmwareHeader(header);
+			if (status) {
+				kfree (vheader);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+
+			// Update I2C with type 0xf2 record with correct size and checksum
+			status = TIWriteRom (serial,
+						start_address,
+						HEADER_SIZE,
+						header);
+			if (status) {
+				kfree (vheader);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+
+			// verify the write -- must do this in order for write to 
+			// complete before we do the hardware reset
+			status = TIReadRom (serial,
+						start_address,
+						HEADER_SIZE,
+						vheader);
+
+			if (status) {
+				dbg ("%s - can't read header back", __FUNCTION__);
+				kfree (vheader);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+			if (memcmp(vheader, header, HEADER_SIZE)) {
+				dbg ("%s - write download record failed", __FUNCTION__);
+				kfree (vheader);
+				kfree (header);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+
+			kfree (vheader);
+			kfree (header);
+
+			dbg ("%s - Start firmware update", __FUNCTION__);
+
+			// Tell firmware to copy download image into I2C 
+			status = TISendVendorRequestSync (serial->serial->dev,
+						UMPC_COPY_DNLD_TO_I2C,	// Request
+						0,			// wValue 
+						0,			// wIndex
+						NULL,			// TransferBuffer
+						0);			// TransferBufferLength
+
+		  	dbg ("%s - Update complete 0x%x", __FUNCTION__, status);
+			if (status) {
+				dbg ("%s - UMPC_COPY_DNLD_TO_I2C failed", __FUNCTION__);
+				kfree (rom_desc);
+				kfree (ti_manuf_desc);
+				return status;
+			}
+		}
+
+		// The device is running the download code
+		kfree (rom_desc);
+		kfree (ti_manuf_desc);
+		return 0;
+	}
+
+	/********************************************************************/
+	/* Boot Mode */
+	/********************************************************************/
+	dbg ("%s - <<<<<<<<<<<<<<<RUNNING IN BOOT MODE>>>>>>>>>>>>>>>",
+	     __FUNCTION__);
+
+	// Configure the TI device so we can use the BULK pipes for download
+	status = TIConfigureBootDevice (serial->serial->dev);
+	if (status)
+		return status;
+
+	if (serial->serial->dev->descriptor.idVendor != USB_VENDOR_ID_ION) {
+		dbg ("%s - VID = 0x%x", __FUNCTION__,
+		     serial->serial->dev->descriptor.idVendor);
+		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
+		goto StayInBootMode;
+	}
+
+	// We have an ION device (I2c Must be programmed)
+	// Determine I2C image type
+	if (TIGetI2cTypeInBootMode(serial)) {
+		goto StayInBootMode;
+	}
+
+	// Registry variable set?
+	if (TIStayInBootMode) {
+		dbg ("%s - TIStayInBootMode", __FUNCTION__);
+		goto StayInBootMode;
+	}
+
+	// Check for ION Vendor ID and that the I2C is valid
+	if (!TiValidateI2cImage(serial)) {
+		struct ti_i2c_image_header *header;
+		int i;
+		__u8 cs = 0;
+		__u8 *buffer;
+		int buffer_size;
+
+		/* Validate Hardware version number
+		 * Read Manufacturing Descriptor from TI Based Edgeport
+		 */
+		ti_manuf_desc = kmalloc (sizeof (*ti_manuf_desc), GFP_KERNEL);
+		if (!ti_manuf_desc) {
+			err ("%s - out of memory.", __FUNCTION__);
+			return -ENOMEM;
+		}
+		status = TIReadManufDescriptor (serial, (__u8 *)ti_manuf_desc);
+		if (status) {
+			kfree (ti_manuf_desc);
+			goto StayInBootMode;
+		}
+
+		// Check for version 2
+		if (!ignore_cpu_rev && TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev) < 2) {
+			dbg ("%s - Wrong CPU Rev %d (Must be 2)", __FUNCTION__,
+			     TI_GET_CPU_REVISION(ti_manuf_desc->CpuRev_BoardRev));
+			kfree (ti_manuf_desc);
+			goto StayInBootMode;
+		}
+
+		kfree (ti_manuf_desc);
+
+		// In order to update the I2C firmware we must change the type 2 record to type 0xF2.
+		// This will force the UMP to come up in Boot Mode.  Then while in boot mode, the driver 
+		// will download the latest firmware (padded to 15.5k) into the UMP ram. 
+		// And finally when the device comes back up in download mode the driver will cause 
+		// the new firmware to be copied from the UMP Ram to I2C and the firmware will update
+		// the record type from 0xf2 to 0x02.
+		
+		/*
+		 * Do we really have to copy the whole firmware image,
+		 * or could we do this in place!
+		 */
+
+		// Allocate a 15.5k buffer + 3 byte header
+		buffer_size = (((1024 * 16) - 512) + sizeof(struct ti_i2c_image_header));
+		buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!buffer) {
+			err ("%s - out of memory", __FUNCTION__);
+			return -ENOMEM;
+		}
+		
+		// Initialize the buffer to 0xff (pad the buffer)
+		memset (buffer, 0xff, buffer_size);
+
+		memcpy (buffer, &PagableOperationalCodeImage[0], PagableOperationalCodeSize);
+
+		for(i = sizeof(struct ti_i2c_image_header); i < buffer_size; i++) {
+			cs = (__u8)(cs + buffer[i]);
+		}
+		
+		header = (struct ti_i2c_image_header *)buffer;
+		
+		// update length and checksum after padding
+		header->Length 	 = (__u16)(buffer_size - sizeof(struct ti_i2c_image_header));
+		header->CheckSum = cs;
+
+		// Download the operational code 
+		dbg ("%s - Downloading operational code image (TI UMP)", __FUNCTION__);
+		status = TIDownloadCodeImage (serial, buffer, buffer_size);
+
+		kfree (buffer);
+
+		if (status) {
+	  		dbg ("%s - Error downloading operational code image", __FUNCTION__);
+			return status;
+		}
+
+		// Device will reboot
+		serial->product_info.TiMode = TI_MODE_TRANSITIONING;
+
+  		dbg ("%s - Download successful -- Device rebooting...", __FUNCTION__);
+
+		/* return an error on purpose */
+		return -ENODEV;
+	}
+
+StayInBootMode:
+	// Eprom is invalid or blank stay in boot mode
+	dbg ("%s - <<<<<<<<<<<<<<<STAYING IN BOOT MODE>>>>>>>>>>>>", __FUNCTION__);
+	serial->product_info.TiMode = TI_MODE_BOOT;
+
+	return 0;
+}
+
+
+static int TISetDtr (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+	port->shadow_mcr |= MCR_DTR;
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_DTR,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				1,	/* set */
+				NULL,
+				0);
+}
+
+static int TIClearDtr (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+	port->shadow_mcr &= ~MCR_DTR;
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_DTR,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,	/* clear */
+				NULL,
+				0);
+}
+
+static int TISetRts (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+	port->shadow_mcr |= MCR_RTS;
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_RTS,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				1,	/* set */
+				NULL,
+				0);
+}
+
+static int TIClearRts (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+	port->shadow_mcr &= ~MCR_RTS;
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_RTS,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,	/* clear */
+				NULL,
+				0);
+}
+
+static int TISetLoopBack (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_LOOPBACK,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				1,	/* set */
+				NULL,
+				0);
+}
+
+static int TIClearLoopBack (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_LOOPBACK,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,	/* clear */
+				NULL,
+				0);
+}
+
+static int TISetBreak (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_BREAK,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				1,	/* set */
+				NULL,
+				0);
+}
+
+static int TIClearBreak (struct edgeport_port *port)
+{
+	int port_number = port->port->number - port->port->serial->minor;
+
+	dbg ("%s", __FUNCTION__);
+
+	return TIWriteCommandSync (port->port->serial->dev,
+				UMPC_SET_CLR_BREAK,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,	/* clear */
+				NULL,
+				0);
+}
+
+static int TIRestoreMCR (struct edgeport_port *port, __u8 mcr)
+{
+	int status = 0;
+
+	dbg ("%s - %x", __FUNCTION__, mcr);
+
+	if (mcr & MCR_DTR)
+		status = TISetDtr (port);
+	else
+		status = TIClearDtr (port);
+
+	if (status)
+		return status;
+
+	if (mcr & MCR_RTS)
+		status = TISetRts (port);
+	else
+		status = TIClearRts (port);
+
+	if (status)
+		return status;
+
+	if (mcr & MCR_LOOPBACK)
+		status = TISetLoopBack (port);
+	else
+		status = TIClearLoopBack (port);
+
+	return status;
+}
+
+
+
+/* Convert TI LSR to standard UART flags */
+static __u8 MapLineStatus (__u8 ti_lsr)
+{
+	__u8 lsr = 0;
+
+#define MAP_FLAG(flagUmp, flagUart)    \
+	if (ti_lsr & flagUmp) lsr |= flagUart;
+
+	MAP_FLAG(UMP_UART_LSR_OV_MASK, LSR_OVER_ERR)	/* overrun */
+	MAP_FLAG(UMP_UART_LSR_PE_MASK, LSR_PAR_ERR)	/* parity error */
+	MAP_FLAG(UMP_UART_LSR_FE_MASK, LSR_FRM_ERR)	/* framing error */
+	MAP_FLAG(UMP_UART_LSR_BR_MASK, LSR_BREAK)	/* break detected */
+	MAP_FLAG(UMP_UART_LSR_RX_MASK, LSR_RX_AVAIL)	/* receive data available */
+	MAP_FLAG(UMP_UART_LSR_TX_MASK, LSR_TX_EMPTY)	/* transmit holding register empty */
+
+#undef MAP_FLAG
+
+	return lsr;
+}
+
+static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr)
+{
+	struct async_icount *icount;
+
+	dbg ("%s - %02x", __FUNCTION__, msr);
+
+	if (msr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) {
+		icount = &edge_port->icount;
+
+		/* update input line counters */
+		if (msr & MSR_DELTA_CTS)
+			icount->cts++;
+		if (msr & MSR_DELTA_DSR)
+			icount->dsr++;
+		if (msr & MSR_DELTA_CD)
+			icount->dcd++;
+		if (msr & MSR_DELTA_RI)
+			icount->rng++;
+		wake_up_interruptible (&edge_port->delta_msr_wait);
+	}
+
+	/* Save the new modem status */
+	edge_port->shadow_msr = msr & 0xf0;
+
+	return;
+}
+
+static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8 lsr, __u8 data)
+{
+	struct async_icount *icount;
+	__u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK));
+
+	dbg ("%s - %02x", __FUNCTION__, new_lsr);
+
+	edge_port->shadow_lsr = lsr;
+
+	if (new_lsr & LSR_BREAK) {
+		/*
+		 * Parity and Framing errors only count if they
+		 * occur exclusive of a break being received.
+		 */
+		new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
+	}
+
+	/* Place LSR data byte into Rx buffer */
+	if (lsr_data && edge_port->port->tty) {
+		tty_insert_flip_char(edge_port->port->tty, data, 0);
+		tty_flip_buffer_push(edge_port->port->tty);
+	}
+
+	/* update input line counters */
+	icount = &edge_port->icount;
+	if (new_lsr & LSR_BREAK)
+		icount->brk++;
+	if (new_lsr & LSR_OVER_ERR)
+		icount->overrun++;
+	if (new_lsr & LSR_PAR_ERR)
+		icount->parity++;
+	if (new_lsr & LSR_FRM_ERR)
+		icount->frame++;
+}
+
+
+static void edge_interrupt_callback (struct urb *urb)
+{
+	struct edgeport_serial	*edge_serial = (struct edgeport_serial *)urb->context;
+	struct usb_serial_port *port;
+	struct edgeport_port *edge_port;
+	unsigned char *data = urb->transfer_buffer;
+	int length = urb->actual_length;
+	int port_number;
+	int function;
+	__u8 lsr;
+	__u8 msr;
+
+	dbg("%s", __FUNCTION__);
+
+	if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__" - nonzero control read status received: %d", urb->status);
+		return;
+	}
+
+	if (!length) {
+		dbg ("%s - no data in urb", __FUNCTION__);
+		return;
+	}
+		
+	usb_serial_debug_data (__FILE__, __FUNCTION__, length, data);
+		
+	if (length != 2) {
+		dbg ("%s - expecting packet of size 2, got %d", __FUNCTION__, length);
+		return;
+	}
+
+	port_number = TIUMP_GET_PORT_FROM_CODE (data[0]);
+	function    = TIUMP_GET_FUNC_FROM_CODE (data[0]);
+	dbg ("%s - port_number %d, function %d, info 0x%x",
+	     __FUNCTION__, port_number, function, data[1]);
+	port = &edge_serial->serial->port[port_number];
+	if (port_paranoia_check (port, __FUNCTION__)) {
+		dbg ("%s - change found for port that is not present",
+		     __FUNCTION__);
+		return;
+	}
+	edge_port = port->private;
+	if (!edge_port) {
+		dbg ("%s - edge_port not found", __FUNCTION__);
+		return;
+	}
+	switch (function) {
+	case TIUMP_INTERRUPT_CODE_LSR:
+		lsr = MapLineStatus(data[1]);
+		if (lsr & UMP_UART_LSR_DATA_MASK) {
+			/* Save the LSR event for bulk read completion routine */
+			dbg ("%s - LSR Event Port %u LSR Status = %02x",
+			     __FUNCTION__, port_number, lsr);
+			edge_port->lsr_event = 1;
+			edge_port->lsr_mask = lsr;
+		} else {
+			dbg ("%s - ===== Port %d LSR Status = %02x ======",
+			     __FUNCTION__, port_number, lsr);
+			handle_new_lsr (edge_port, 0, lsr, 0);
+		}
+		break;
+
+	case TIUMP_INTERRUPT_CODE_MSR:	// MSR
+		/* Copy MSR from UMP */
+		msr = data[1];
+		dbg ("%s - ===== Port %u MSR Status = %02x ======\n",
+		     __FUNCTION__, port_number, msr);
+		handle_new_msr (edge_port, msr);
+		break;
+
+	default:
+		err ("%s - Unknown Interrupt code from UMP %x\n",
+		     __FUNCTION__, data[1]);
+		break;
+		
+	}
+}
+
+static void edge_bulk_in_callback (struct urb *urb)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+	unsigned char *data = urb->transfer_buffer;
+	struct tty_struct *tty;
+	int status;
+	int i;
+	int port_number;
+
+	dbg("%s", __FUNCTION__);
+
+	if (port_paranoia_check (edge_port->port, __FUNCTION__))
+		return;
+
+	if (urb->status) {
+		dbg ("%s - nonzero read bulk status received: %d",
+		     __FUNCTION__, urb->status);
+
+		if (urb->status == -EPIPE) {
+			/* clear any problem that might have happened on this pipe */
+			usb_clear_halt (edge_port->port->serial->dev, urb->pipe);
+			goto exit;
+		}
+		return;
+	}
+
+	port_number = edge_port->port->number - edge_port->port->serial->minor;
+
+	if (edge_port->lsr_event) {
+		edge_port->lsr_event = 0;
+		dbg ("%s ===== Port %u LSR Status = %02x, Data = %02x ======",
+		     __FUNCTION__, port_number, edge_port->lsr_mask, *data);
+		handle_new_lsr (edge_port, 1, edge_port->lsr_mask, *data);
+		/* Adjust buffer length/pointer */
+		--urb->actual_length;
+		++data;
+	}
+
+	tty = edge_port->port->tty;
+	if (tty && urb->actual_length) {
+		usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+		if (edge_port->close_pending) {
+			dbg ("%s - close is pending, dropping data on the floor.", __FUNCTION__);
+		} else {
+			for (i = 0; i < urb->actual_length ; ++i) {
+				/* if we insert more than TTY_FLIPBUF_SIZE characters,
+				 * we drop them. */
+				if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+					tty_flip_buffer_push(tty);
+				}
+				/* this doesn't actually push the data through unless
+				 * tty->low_latency is set */
+				tty_insert_flip_char(tty, data[i], 0);
+			}
+			tty_flip_buffer_push(tty);
+		}
+		edge_port->icount.rx += urb->actual_length;
+	}
+
+exit:
+	/* continue always trying to read */
+	urb->dev = edge_port->port->serial->dev;
+	status = usb_submit_urb (urb);
+	if (status)
+		err ("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, status);
+}
+
+static void edge_bulk_out_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	struct tty_struct *tty;
+
+	dbg ("%s - port %d", __FUNCTION__, port->number);
+
+	if (!serial) {
+		dbg ("%s - bad serial pointer, exiting", __FUNCTION__);
+		return;
+	}
+
+	if (urb->status) {
+		dbg ("%s - nonzero write bulk status received: %d",
+		     __FUNCTION__, urb->status);
+
+		if (urb->status == -EPIPE) {
+			/* clear any problem that might have happened on this pipe */
+			usb_clear_halt (serial->dev, urb->pipe);
+		}
+		return;
+	}
+
+	tty = port->tty;
+	if (tty) {
+		/* let the tty driver wakeup if it has a special write_wakeup function */
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+			(tty->ldisc.write_wakeup)(tty);
+		}
+
+		/* tell the tty driver that something has changed */
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+static int edge_open (struct usb_serial_port *port, struct file * filp)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)port->private;
+	struct edgeport_serial *edge_serial;
+	struct usb_device *dev;
+	struct urb *urb;
+	int port_number;
+	int status = 0;
+	u16 open_settings;
+	u8 transaction_timeout;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return -ENODEV;
+	
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (edge_port == NULL)
+		return -ENODEV;
+
+	down (&port->sem);
+
+	++port->open_count;
+	MOD_INC_USE_COUNT;
+	
+	if (!port->active) {
+		port->active = 1;
+
+		/* force low_latency on so that our tty_push actually forces the data through, 
+		   otherwise it is scheduled, and with high data rates (like with OHCI) data
+		   can get lost. */
+		if (port->tty)
+			port->tty->low_latency = 1;
+
+		port_number = port->number - port->serial->minor;
+		switch (port_number) {
+			case 0:
+				edge_port->uart_base = UMPMEM_BASE_UART1;
+				edge_port->dma_address = UMPD_OEDB1_ADDRESS;
+				break;
+			case 1:
+				edge_port->uart_base = UMPMEM_BASE_UART2;
+				edge_port->dma_address = UMPD_OEDB2_ADDRESS;
+				break;
+			default:
+				err ("Unknown port number!!!");
+				status = -ENODEV;
+				goto exit;
+		}
+
+		dbg ("%s - port_number = %d, uart_base = %04x, dma_address = %04x",
+		     __FUNCTION__, port_number, edge_port->uart_base, edge_port->dma_address);
+
+		dev = port->serial->dev;
+
+		memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount));
+		init_waitqueue_head (&edge_port->delta_msr_wait);
+
+		/* turn off loopback */
+		status = TIClearLoopBack (edge_port);
+		if (status)
+			goto exit;
+		
+		/* set up the port settings */
+		edge_set_termios (port, NULL);
+
+		/* open up the port */
+
+		/* milliseconds to timeout for DMA transfer */
+		transaction_timeout = 2;
+
+		edge_port->ump_read_timeout = max (20, ((transaction_timeout * 3) / 2) );
+
+		// milliseconds to timeout for DMA transfer
+		open_settings = (u8)(UMP_DMA_MODE_CONTINOUS | 
+				     UMP_PIPE_TRANS_TIMEOUT_ENA | 
+				     (transaction_timeout << 2));
+
+		dbg ("%s - Sending UMPC_OPEN_PORT", __FUNCTION__);
+
+		/* Tell TI to open and start the port */
+		status = TIWriteCommandSync (dev,
+						UMPC_OPEN_PORT,
+						(u8)(UMPM_UART1_PORT + port_number),
+						open_settings,
+						NULL,
+						0);
+		if (status)
+			goto exit;
+
+		/* Start the DMA? */
+		status = TIWriteCommandSync (dev,
+						UMPC_START_PORT,
+						(u8)(UMPM_UART1_PORT + port_number),
+						0,
+						NULL,
+						0);
+		if (status)
+			goto exit;
+
+		/* Clear TX and RX buffers in UMP */
+		status = TIPurgeDataSync (port, UMP_PORT_DIR_OUT | UMP_PORT_DIR_IN);
+		if (status)
+			goto exit;
+
+		/* Read Initial MSR */
+		status = TIReadVendorRequestSync (dev,
+						UMPC_READ_MSR,	// Request
+						0,		// wValue
+						(__u16)(UMPM_UART1_PORT + port_number),	// wIndex (Address)
+						&edge_port->shadow_msr,			// TransferBuffer
+						1);					// TransferBufferLength
+		if (status)
+			goto exit;
+
+		dbg ("ShadowMSR 0x%X", edge_port->shadow_msr);
+	 
+		edge_serial = edge_port->edge_serial;
+		if (edge_serial->num_ports_open == 0) {
+			dbg ("%s - setting up bulk in urb", __FUNCTION__);
+			/* we are the first port to be opened, let's post the interrupt urb */
+			urb = edge_serial->serial->port[0].interrupt_in_urb;
+			if (!urb) {
+				err ("%s - no interrupt urb present, exiting", __FUNCTION__);
+				status = -EINVAL;
+				goto exit;
+			}
+			urb->complete = edge_interrupt_callback;
+			urb->context = edge_serial;
+			urb->dev = dev;
+			status = usb_submit_urb (urb);
+			if (status) {
+				err ("%s - usb_submit_urb failed with value %d", __FUNCTION__, status);
+				goto exit;
+			}
+		}
+
+		/* reset the data toggle on the bulk endpoints */
+		usb_clear_halt (dev, port->write_urb->pipe);
+		usb_clear_halt (dev, port->read_urb->pipe);
+
+		/* start up our bulk read urb */
+		urb = port->read_urb;
+		if (!urb) {
+			err ("%s - no read urb present, exiting", __FUNCTION__);
+			status = -EINVAL;
+			goto exit;
+		}
+		urb->complete = edge_bulk_in_callback;
+		urb->context = edge_port;
+		urb->dev = dev;
+		status = usb_submit_urb (urb);
+		if (status) {
+			err ("%s - read bulk usb_submit_urb failed with value %d", __FUNCTION__, status);
+			goto exit;
+		}
+
+		++edge_serial->num_ports_open;
+
+	}
+exit:
+	up (&port->sem);
+
+	dbg("%s - exited, status = %d", __FUNCTION__, status);
+
+	if (status)
+		MOD_DEC_USE_COUNT;
+
+	return status;
+}
+
+static void edge_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial *serial;
+	struct edgeport_serial *edge_serial;
+	struct edgeport_port *edge_port;
+	int port_number;
+	int status;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+			 
+	serial = get_usb_serial (port, __FUNCTION__);
+	if (!serial)
+		return;
+	
+	edge_serial = (struct edgeport_serial *)serial->private;
+	edge_port = (struct edgeport_port *)port->private;
+	if ((edge_serial == NULL) || (edge_port == NULL))
+		return;
+
+	down (&port->sem);
+	--port->open_count;
+	if (port->open_count <= 0) {
+		if (serial->dev) {
+			/* The bulkreadcompletion routine will check 
+			 * this flag and dump add read data */
+			edge_port->close_pending = 1;
+
+			/* chase the port close */
+			TIChasePort (edge_port);
+
+			usb_unlink_urb (port->read_urb);
+
+			/* assuming we can still talk to the device,
+			 * send a close port command to it */
+			dbg("%s - send umpc_close_port", __FUNCTION__);
+			port_number = port->number - port->serial->minor;
+			status = TIWriteCommandSync (port->serial->dev,
+						     UMPC_CLOSE_PORT,
+						     (__u8)(UMPM_UART1_PORT + port_number),
+						     0,
+						     NULL,
+						     0);
+			--edge_port->edge_serial->num_ports_open;
+			if (edge_port->edge_serial->num_ports_open <= 0) {
+				/* last port is now closed, let's shut down our interrupt urb */
+				usb_unlink_urb (serial->port[0].interrupt_in_urb);
+				edge_port->edge_serial->num_ports_open = 0;
+			}
+		}
+		edge_port->close_pending = 0;
+		port->active = 0;
+		port->open_count = 0;
+	}
+	up (&port->sem);
+
+	dbg(__FUNCTION__" exited");
+	MOD_DEC_USE_COUNT;
+
+}
+
+static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *data, int count)
+{
+	struct usb_serial *serial = port->serial;
+	struct edgeport_port *edge_port = port->private;
+	int result;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (count == 0) {
+		dbg("%s - write request of 0 bytes", __FUNCTION__);
+		return 0;
+	}
+
+	if (edge_port == NULL)
+		return -ENODEV;
+	if (edge_port->close_pending == 1)
+		return -ENODEV;
+	
+	if (port->write_urb->status == -EINPROGRESS) {
+		dbg ("%s - already writing", __FUNCTION__);
+		return 0;
+	}
+
+	count = min (count, port->bulk_out_size);
+
+	if (from_user) {
+		if (copy_from_user(port->write_urb->transfer_buffer, data, count))
+			return -EFAULT;
+	} else {
+		memcpy (port->write_urb->transfer_buffer, data, count);
+	}
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
+
+	/* set up our urb */
+	usb_fill_bulk_urb (port->write_urb, serial->dev,
+			   usb_sndbulkpipe (serial->dev,
+					    port->bulk_out_endpointAddress),
+			   port->write_urb->transfer_buffer, count,
+			   edge_bulk_out_callback,
+			   port);
+
+	/* send the data out the bulk port */
+	result = usb_submit_urb(port->write_urb);
+	if (result)
+		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+	else
+		result = count;
+
+	if (result > 0)
+		edge_port->icount.tx += count;
+
+	return result;
+}
+
+static int edge_write_room (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	int room = 0;
+
+	dbg(__FUNCTION__);
+
+	if (edge_port == NULL)
+		return -ENODEV;
+	if (edge_port->close_pending == 1)
+		return -ENODEV;
+	
+	dbg(__FUNCTION__" - port %d", port->number);
+
+	if (port->write_urb->status != -EINPROGRESS)
+		room = port->bulk_out_size;
+
+	dbg(__FUNCTION__ " - returns %d", room);
+	return room;
+}
+
+static int edge_chars_in_buffer (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	int chars = 0;
+
+	dbg(__FUNCTION__);
+
+	if (edge_port == NULL)
+		return -ENODEV;
+	if (edge_port->close_pending == 1)
+		return -ENODEV;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (port->write_urb->status == -EINPROGRESS)
+		chars = port->write_urb->transfer_buffer_length;
+
+	dbg ("%s - returns %d", __FUNCTION__, chars);
+	return chars;
+}
+
+static void edge_throttle (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct tty_struct *tty;
+	int status;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (edge_port == NULL)
+		return;
+
+	tty = port->tty;
+	if (!tty) {
+		dbg ("%s - no tty available", __FUNCTION__);
+		return;
+	}
+	/* if we are implementing XON/XOFF, send the stop character */
+	if (I_IXOFF(tty)) {
+		unsigned char stop_char = STOP_CHAR(tty);
+		status = edge_write (port, 0, &stop_char, 1);
+		if (status <= 0) {
+			return;
+		}
+	}
+
+	/* if we are implementing RTS/CTS, toggle that line */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		status = TIClearRts (edge_port);
+	}
+
+	usb_unlink_urb (port->read_urb);
+}
+
+static void edge_unthrottle (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct tty_struct *tty;
+	int status;
+
+	dbg(__FUNCTION__" - port %d", port->number);
+
+	if (edge_port == NULL)
+		return;
+
+	tty = port->tty;
+	if (!tty) {
+		dbg ("%s - no tty available", __FUNCTION__);
+		return;
+	}
+
+	/* if we are implementing XON/XOFF, send the start character */
+	if (I_IXOFF(tty)) {
+		unsigned char start_char = START_CHAR(tty);
+		status = edge_write (port, 0, &start_char, 1);
+		if (status <= 0) {
+			return;
+		}
+	}
+
+	/* if we are implementing RTS/CTS, toggle that line */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		status = TISetRts (edge_port);
+	}
+
+	port->read_urb->dev = port->serial->dev;
+	status = usb_submit_urb (port->read_urb);
+	if (status) {
+		err ("%s - usb_submit_urb failed with value %d", __FUNCTION__, status);
+	}
+}
+
+
+static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
+{
+	struct ump_uart_config *config;
+	struct tty_struct *tty;
+	int baud;
+	int round;
+	unsigned cflag;
+	int status;
+	int port_number = edge_port->port->number - edge_port->port->serial->minor;
+
+	dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
+
+	tty = edge_port->port->tty;
+	if ((!tty) ||
+	    (!tty->termios)) {
+		dbg("%s - no tty structures", __FUNCTION__);
+		return;
+	}
+
+	config = kmalloc (sizeof (*config), GFP_KERNEL);
+	if (!config) {
+		err ("%s - out of memory", __FUNCTION__);
+		return;
+	}
+
+	cflag = tty->termios->c_cflag;
+
+	config->wFlags = 0;
+
+	/* These flags must be set */
+	config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT;
+	config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR;
+	config->bUartMode = 0;
+
+	switch (cflag & CSIZE) {
+		case CS5:
+			    config->bDataBits = UMP_UART_CHAR5BITS;
+			    dbg ("%s - data bits = 5", __FUNCTION__);
+			    break;
+		case CS6:
+			    config->bDataBits = UMP_UART_CHAR6BITS;
+			    dbg ("%s - data bits = 6", __FUNCTION__);
+			    break;
+		case CS7:
+			    config->bDataBits = UMP_UART_CHAR7BITS;
+			    dbg ("%s - data bits = 7", __FUNCTION__);
+			    break;
+		default:
+		case CS8:
+			    config->bDataBits = UMP_UART_CHAR8BITS;
+			    dbg ("%s - data bits = 8", __FUNCTION__);
+			    break;
+	}
+
+	if (cflag & PARENB) {
+		if (cflag & PARODD) {
+			config->wFlags |= UMP_MASK_UART_FLAGS_PARITY;
+			config->bParity = UMP_UART_ODDPARITY;
+			dbg(__FUNCTION__" - parity = odd");
+		} else {
+			config->wFlags |= UMP_MASK_UART_FLAGS_PARITY;
+			config->bParity = UMP_UART_EVENPARITY;
+			dbg(__FUNCTION__" - parity = even");
+		}
+	} else {
+		config->bParity = UMP_UART_NOPARITY; 	
+		dbg(__FUNCTION__" - parity = none");
+	}
+
+	if (cflag & CSTOPB) {
+		config->bStopBits = UMP_UART_STOPBIT2;
+		dbg(__FUNCTION__" - stop bits = 2");
+	} else {
+		config->bStopBits = UMP_UART_STOPBIT1;
+		dbg(__FUNCTION__" - stop bits = 1");
+	}
+
+	/* figure out the flow control settings */
+	if (cflag & CRTSCTS) {
+		config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW;
+		config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW;
+		dbg(__FUNCTION__" - RTS/CTS is enabled");
+	} else {
+		dbg(__FUNCTION__" - RTS/CTS is disabled");
+	}
+
+	/* if we are implementing XON/XOFF, set the start and stop character in the device */
+	if (I_IXOFF(tty) || I_IXON(tty)) {
+		config->cXon  = START_CHAR(tty);
+		config->cXoff = STOP_CHAR(tty);
+
+		/* if we are implementing INBOUND XON/XOFF */
+		if (I_IXOFF(tty)) {
+			config->wFlags |= UMP_MASK_UART_FLAGS_IN_X;
+			dbg ("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
+			     __FUNCTION__, config->cXon, config->cXoff);
+		} else {
+			dbg ("%s - INBOUND XON/XOFF is disabled", __FUNCTION__);
+		}
+
+		/* if we are implementing OUTBOUND XON/XOFF */
+		if (I_IXON(tty)) {
+			config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X;
+			dbg ("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
+			     __FUNCTION__, config->cXon, config->cXoff);
+		} else {
+			dbg ("%s - OUTBOUND XON/XOFF is disabled", __FUNCTION__);
+		}
+	}
+
+	/* Round the baud rate */
+	baud = tty_get_baud_rate(tty);
+	if (!baud) {
+		/* pick a default, any default... */
+		baud = 9600;
+	}
+	config->wBaudRate = (__u16)(461550L / baud);
+	round = 4615500L / baud;
+	if ((round - (config->wBaudRate * 10)) >= 5)
+		config->wBaudRate++;
+
+	dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate);
+
+	dbg ("wBaudRate:   %d", (int)(461550L / config->wBaudRate));
+	dbg ("wFlags:    0x%x", config->wFlags);
+	dbg ("bDataBits:   %d", config->bDataBits);
+	dbg ("bParity:     %d", config->bParity);
+	dbg ("bStopBits:   %d", config->bStopBits);
+	dbg ("cXon:        %d", config->cXon);
+	dbg ("cXoff:       %d", config->cXoff);
+	dbg ("bUartMode:   %d", config->bUartMode);
+
+	/* move the word values into big endian mode */
+	cpu_to_be16s (&config->wFlags);
+	cpu_to_be16s (&config->wBaudRate);
+
+	status = TIWriteCommandSync (edge_port->port->serial->dev,
+				UMPC_SET_CONFIG,
+				(__u8)(UMPM_UART1_PORT + port_number),
+				0,
+				(__u8 *)config,
+				sizeof(*config));
+	if (status) {
+		dbg ("%s - error %d when trying to write config to device",
+		     __FUNCTION__, status);
+	}
+
+	kfree (config);
+	
+	return;
+}
+
+static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct tty_struct *tty = port->tty;
+	unsigned int cflag;
+
+	if (!port->tty || !port->tty->termios) {
+		dbg ("%s - no tty or termios", __FUNCTION__);
+		return;
+	}
+
+	cflag = tty->termios->c_cflag;
+	/* check that they really want us to change something */
+	if (old_termios) {
+		if ((cflag == old_termios->c_cflag) &&
+		    (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg ("%s - nothing to change", __FUNCTION__);
+			return;
+		}
+	}
+
+	dbg("%s - clfag %08x iflag %08x", __FUNCTION__, 
+	    tty->termios->c_cflag,
+	    RELEVANT_IFLAG(tty->termios->c_iflag));
+	if (old_termios) {
+		dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+		    old_termios->c_cflag,
+		    RELEVANT_IFLAG(old_termios->c_iflag));
+	}
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (edge_port == NULL)
+		return;
+
+	/* change the port settings to the new ones specified */
+	change_port_settings (edge_port, old_termios);
+
+	return;
+}
+
+static int set_modem_info (struct edgeport_port *edge_port, unsigned int cmd, unsigned int *value)
+{
+	unsigned int mcr = edge_port->shadow_mcr;
+	unsigned int arg;
+
+	if (copy_from_user(&arg, value, sizeof(int)))
+		return -EFAULT;
+
+	switch (cmd) {
+		case TIOCMBIS:
+			if (arg & TIOCM_RTS)
+				mcr |= MCR_RTS;
+			if (arg & TIOCM_DTR)
+				mcr |= MCR_RTS;
+			if (arg & TIOCM_LOOP)
+				mcr |= MCR_LOOPBACK;
+			break;
+
+		case TIOCMBIC:
+			if (arg & TIOCM_RTS)
+				mcr &= ~MCR_RTS;
+			if (arg & TIOCM_DTR)
+				mcr &= ~MCR_RTS;
+			if (arg & TIOCM_LOOP)
+				mcr &= ~MCR_LOOPBACK;
+			break;
+
+		case TIOCMSET:
+			/* turn off the RTS and DTR and LOOPBACK 
+			 * and then only turn on what was asked to */
+			mcr &=  ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
+			mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
+			mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
+			mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
+			break;
+	}
+
+	edge_port->shadow_mcr = mcr;
+
+	TIRestoreMCR (edge_port, mcr);
+
+	return 0;
+}
+
+static int get_modem_info (struct edgeport_port *edge_port, unsigned int *value)
+{
+	unsigned int result = 0;
+	unsigned int msr = edge_port->shadow_msr;
+	unsigned int mcr = edge_port->shadow_mcr;
+
+	result = ((mcr & MCR_DTR)	? TIOCM_DTR: 0)	  /* 0x002 */
+		  | ((mcr & MCR_RTS)	? TIOCM_RTS: 0)   /* 0x004 */
+		  | ((msr & MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
+		  | ((msr & MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
+		  | ((msr & MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
+		  | ((msr & MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
+
+
+	dbg(__FUNCTION__" -- %x", result);
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+static int get_serial_info (struct edgeport_port *edge_port, struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	tmp.type		= PORT_16550A;
+	tmp.line		= edge_port->port->serial->minor;
+	tmp.port		= edge_port->port->number;
+	tmp.irq			= 0;
+	tmp.flags		= ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+	tmp.xmit_fifo_size	= edge_port->port->bulk_out_size;
+	tmp.baud_base		= 9600;
+	tmp.close_delay		= 5*HZ;
+	tmp.closing_wait	= 30*HZ;
+//	tmp.custom_divisor	= state->custom_divisor;
+//	tmp.hub6		= state->hub6;
+//	tmp.io_type		= state->io_type;
+
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct async_icount cnow;
+	struct async_icount cprev;
+
+	dbg(__FUNCTION__" - port %d, cmd = 0x%x", port->number, cmd);
+
+	switch (cmd) {
+		case TIOCINQ:
+			dbg(__FUNCTION__" (%d) TIOCINQ",  port->number);
+//			return get_number_bytes_avail(edge_port, (unsigned int *) arg);
+			break;
+
+		case TIOCSERGETLSR:
+			dbg(__FUNCTION__" (%d) TIOCSERGETLSR",  port->number);
+//			return get_lsr_info(edge_port, (unsigned int *) arg);
+			break;
+
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET",  port->number);
+			return set_modem_info(edge_port, cmd, (unsigned int *) arg);
+			break;
+
+		case TIOCMGET:  
+			dbg(__FUNCTION__" (%d) TIOCMGET",  port->number);
+			return get_modem_info(edge_port, (unsigned int *) arg);
+			break;
+
+		case TIOCGSERIAL:
+			dbg(__FUNCTION__" (%d) TIOCGSERIAL",  port->number);
+			return get_serial_info(edge_port, (struct serial_struct *) arg);
+			break;
+
+		case TIOCSSERIAL:
+			dbg(__FUNCTION__" (%d) TIOCSSERIAL",  port->number);
+			break;
+
+		case TIOCMIWAIT:
+			dbg(__FUNCTION__" (%d) TIOCMIWAIT",  port->number);
+			cprev = edge_port->icount;
+			while (1) {
+				interruptible_sleep_on(&edge_port->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+				cnow = edge_port->icount;
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+					return -EIO; /* no change => error */
+				if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+				    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+				    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+				    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+					return 0;
+				}
+				cprev = cnow;
+			}
+			/* not reached */
+			break;
+
+		case TIOCGICOUNT:
+			dbg ("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+			     port->number, edge_port->icount.rx, edge_port->icount.tx);
+			if (copy_to_user((void *)arg, &edge_port->icount, sizeof(edge_port->icount)))
+				return -EFAULT;
+			return 0;
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+static void edge_break (struct usb_serial_port *port, int break_state)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	int status;
+
+	dbg ("%s - state = %d", __FUNCTION__, break_state);
+
+	/* chase the port close */
+	TIChasePort (edge_port);
+
+	if (break_state == -1) {
+		status = TISetBreak (edge_port);
+	} else {
+		status = TIClearBreak (edge_port);
+	}
+	if (status) {
+		dbg ("%s - error %d sending break set/clear command.",
+		     __FUNCTION__, status);
+	}
+}
+
+static int edge_startup (struct usb_serial *serial)
+{
+	struct edgeport_serial *edge_serial;
+	struct edgeport_port *edge_port;
+	struct usb_device *dev;
+	int status;
+	int i;
+
+	dev = serial->dev;
+
+	/* create our private serial structure */
+	edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
+	if (edge_serial == NULL) {
+		err(__FUNCTION__" - Out of memory");
+		return -ENOMEM;
+	}
+	memset (edge_serial, 0, sizeof(struct edgeport_serial));
+	edge_serial->serial = serial;
+	serial->private = edge_serial;
+
+	status = TIDownloadFirmware (edge_serial);
+	if (status) {
+		kfree (edge_serial);
+		return status;
+	}
+
+	/* set up our port private structures */
+	for (i = 0; i < serial->num_ports; ++i) {
+		edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
+		if (edge_port == NULL) {
+			err(__FUNCTION__" - Out of memory");
+			return -ENOMEM;
+		}
+		memset (edge_port, 0, sizeof(struct edgeport_port));
+		edge_port->port = &serial->port[i];
+		edge_port->edge_serial = edge_serial;
+		serial->port[i].private = edge_port;
+	}
+	
+	return 0;
+}
+
+static void edge_shutdown (struct usb_serial *serial)
+{
+	int i;
+
+	dbg (__FUNCTION__);
+
+	for (i=0; i < serial->num_ports; ++i) {
+		kfree (serial->port[i].private);
+		serial->port[i].private = NULL;
+	}
+	kfree (serial->private);
+	serial->private = NULL;
+}
+
+
+static struct usb_serial_device_type edgeport_1port_device = {
+	name:			"Edgeport TI 1 port adapter",
+	id_table:		edgeport_1port_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+static struct usb_serial_device_type edgeport_2port_device = {
+	name:			"Edgeport TI 2 port adapter",
+	id_table:		edgeport_2port_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		2,
+	num_bulk_out:		2,
+	num_ports:		2,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+
+static int __init edgeport_init(void)
+{
+	usb_serial_register (&edgeport_1port_device);
+	usb_serial_register (&edgeport_2port_device);
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return 0;
+}
+
+static void __exit edgeport_exit (void)
+{
+	usb_serial_deregister (&edgeport_1port_device);
+	usb_serial_deregister (&edgeport_2port_device);
+}
+
+module_init(edgeport_init);
+module_exit(edgeport_exit);
+
+/* Module information */
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+MODULE_PARM(ignore_cpu_rev, "i");
+MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device");
+
diff -urN linux-2.4.20-pre1/drivers/usb/serial/io_ti.h linux-2.4.20-pre2/drivers/usb/serial/io_ti.h
--- linux-2.4.20-pre1/drivers/usb/serial/io_ti.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/serial/io_ti.h	Mon Aug 12 16:34:16 2002
@@ -0,0 +1,180 @@
+/*****************************************************************************  
+ *
+ *	Copyright (c) 1997-2002 Inside Out Networks, Inc.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *
+ *	Feb-16-2001	DMI	Added I2C structure definitions
+ *	May-29-2002	gkh	Ported to Linux
+ *
+ *
+ ******************************************************************************/
+
+#ifndef _IO_TI_H_
+#define _IO_TI_H_
+
+/* Address Space */
+#define DTK_ADDR_SPACE_XDATA		0x03	/* Addr is placed in XDATA space */
+#define DTK_ADDR_SPACE_I2C_TYPE_II	0x82	/* Addr is placed in I2C area */
+#define DTK_ADDR_SPACE_I2C_TYPE_III	0x83	/* Addr is placed in I2C area */
+
+// UART Defines
+#define UMPMEM_BASE_UART1		0xFFA0  /* UMP UART1 base address          */
+#define UMPMEM_BASE_UART2		0xFFB0  /* UMP UART2 base address          */
+#define UMPMEM_OFFS_UART_LSR		0x05    /* UMP UART LSR register offset    */
+
+/* Bits per character */
+#define UMP_UART_CHAR5BITS		0x00
+#define UMP_UART_CHAR6BITS		0x01
+#define UMP_UART_CHAR7BITS		0x02
+#define UMP_UART_CHAR8BITS		0x03
+
+/* Parity */
+#define UMP_UART_NOPARITY		0x00
+#define UMP_UART_ODDPARITY		0x01
+#define UMP_UART_EVENPARITY		0x02
+#define UMP_UART_MARKPARITY		0x03
+#define UMP_UART_SPACEPARITY		0x04
+
+/* Stop bits */
+#define UMP_UART_STOPBIT1		0x00
+#define UMP_UART_STOPBIT15		0x01
+#define UMP_UART_STOPBIT2		0x02
+
+/* Line status register masks */
+#define UMP_UART_LSR_OV_MASK		0x01
+#define UMP_UART_LSR_PE_MASK		0x02
+#define UMP_UART_LSR_FE_MASK		0x04
+#define UMP_UART_LSR_BR_MASK		0x08
+#define UMP_UART_LSR_ER_MASK		0x0F
+#define UMP_UART_LSR_RX_MASK		0x10
+#define UMP_UART_LSR_TX_MASK		0x20
+
+#define UMP_UART_LSR_DATA_MASK		( LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK )
+
+/* Port Settings Constants) */
+#define UMP_MASK_UART_FLAGS_RTS_FLOW		0x0001
+#define UMP_MASK_UART_FLAGS_RTS_DISABLE		0x0002
+#define UMP_MASK_UART_FLAGS_PARITY		0x0008
+#define UMP_MASK_UART_FLAGS_OUT_X_DSR_FLOW	0x0010
+#define UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW	0x0020
+#define UMP_MASK_UART_FLAGS_OUT_X		0x0040
+#define UMP_MASK_UART_FLAGS_OUT_XA		0x0080
+#define UMP_MASK_UART_FLAGS_IN_X		0x0100
+#define UMP_MASK_UART_FLAGS_DTR_FLOW		0x0800
+#define UMP_MASK_UART_FLAGS_DTR_DISABLE		0x1000
+#define UMP_MASK_UART_FLAGS_RECEIVE_MS_INT	0x2000
+#define UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR	0x4000
+
+#define UMP_DMA_MODE_CONTINOUS			0x01
+#define UMP_PIPE_TRANS_TIMEOUT_ENA		0x80
+#define UMP_PIPE_TRANSFER_MODE_MASK		0x03
+#define UMP_PIPE_TRANS_TIMEOUT_MASK		0x7C
+
+/* Purge port Direction Mask Bits */
+#define UMP_PORT_DIR_OUT			0x01
+#define UMP_PORT_DIR_IN				0x02
+
+// Address of Port 0
+#define UMPM_UART1_PORT  			0x03
+
+// Commands
+#define	UMPC_SET_CONFIG 		0x05
+#define	UMPC_OPEN_PORT  		0x06
+#define	UMPC_CLOSE_PORT 		0x07
+#define	UMPC_START_PORT 		0x08
+#define	UMPC_STOP_PORT  		0x09
+#define	UMPC_TEST_PORT  		0x0A
+#define	UMPC_PURGE_PORT 		0x0B
+
+#define	UMPC_COMPLETE_READ		0x80	// Force the Firmware to complete the current Read
+#define	UMPC_HARDWARE_RESET		0x81	// Force UMP back into BOOT Mode
+#define	UMPC_COPY_DNLD_TO_I2C		0x82	// Copy current download image to type 0xf2 record in 16k I2C
+						// firmware will change 0xff record to type 2 record when complete
+
+	// Special function register commands
+	// wIndex is register address
+	// wValue is MSB/LSB mask/data
+#define	UMPC_WRITE_SFR	  		0x83	// Write SFR Register
+
+	// wIndex is register address
+#define	UMPC_READ_SFR	  		0x84	// Read SRF Register
+
+	// Set or Clear DTR (wValue bit 0 Set/Clear)		wIndex ModuleID (port)
+#define	UMPC_SET_CLR_DTR		0x85
+
+	// Set or Clear RTS (wValue bit 0 Set/Clear)		wIndex ModuleID (port)
+#define	UMPC_SET_CLR_RTS		0x86
+
+	// Set or Clear LOOPBACK (wValue bit 0 Set/Clear)	wIndex ModuleID (port)
+#define	UMPC_SET_CLR_LOOPBACK		0x87
+
+	// Set or Clear BREAK (wValue bit 0 Set/Clear)		wIndex ModuleID (port)
+#define	UMPC_SET_CLR_BREAK		0x88
+
+	// Read MSR wIndex ModuleID (port)
+#define	UMPC_READ_MSR			0x89
+
+	/* Toolkit commands */
+	/* Read-write group */
+#define	UMPC_MEMORY_READ   		0x92
+#define	UMPC_MEMORY_WRITE  		0x93
+
+/*
+ *	UMP DMA Definitions
+ */
+#define UMPD_OEDB1_ADDRESS		0xFF08
+#define UMPD_OEDB2_ADDRESS		0xFF10
+
+struct out_endpoint_desc_block
+{
+	__u8 Configuration;
+	__u8 XBufAddr;
+	__u8 XByteCount;
+	__u8 Unused1;
+	__u8 Unused2;
+	__u8 YBufAddr;
+	__u8 YByteCount;
+	__u8 BufferSize;
+} __attribute__((packed));
+
+
+/*
+ * TYPE DEFINITIONS
+ * Structures for Firmware commands
+ */
+struct ump_uart_config		/* UART settings                    */
+{
+	__u16 wBaudRate;	/* Baud rate                        */
+	__u16 wFlags;		/* Bitmap mask of flags             */
+	__u8 bDataBits;		/* 5..8 - data bits per character   */
+	__u8 bParity;		/* Parity settings                  */
+	__u8 bStopBits;		/* Stop bits settings               */
+	char cXon;		/* XON character                    */
+	char cXoff;		/* XOFF character                   */
+	__u8 bUartMode;		/* Will be updated when a user      */
+				/* interface is defined             */
+} __attribute__((packed));
+
+
+/*
+ * TYPE DEFINITIONS
+ * Structures for USB interrupts
+ */
+typedef struct				/* Interrupt packet structure       */
+{
+	__u8 bICode;			/* Interrupt code (interrupt num)   */
+	__u8 bIInfo;			/* Interrupt information            */
+} tUmpInterrupt, *ptUmpInterrupt __attribute__((packed));
+
+
+#define TIUMP_GET_PORT_FROM_CODE(c)	(((c) >> 4) - 3)
+#define TIUMP_GET_FUNC_FROM_CODE(c)	((c) & 0x0f)
+#define TIUMP_INTERRUPT_CODE_LSR	0x03
+#define TIUMP_INTERRUPT_CODE_MSR	0x04
+
+#endif
diff -urN linux-2.4.20-pre1/drivers/usb/serial/io_usbvend.h linux-2.4.20-pre2/drivers/usb/serial/io_usbvend.h
--- linux-2.4.20-pre1/drivers/usb/serial/io_usbvend.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/serial/io_usbvend.h	Mon Aug 12 16:34:16 2002
@@ -106,11 +106,22 @@
 #define ION_DEVICE_ID_BB_EDGEPORT_4_DIN		0x011	// Edgeport/4 RS232 with Apple DIN connector
 #define ION_DEVICE_ID_BB_EDGEPORT_16_DUAL_CPU	0x012	// Half of an Edgeport/16 (the kind with 2 EP/8s)
 #define ION_DEVICE_ID_BB_EDGEPORT_8I		0x014	// Edgeport/8 RS422 (single-CPU)
-// These IDs are used by the Edgeport.exe program for uninstalling.
-// 
-#define EDGEPORT_DEVICE_IDS	{0x001, 0x003, 0x004, 0x005, 0x006, 0x007, 0x00B, \
-				 0x00C, 0x00D, 0x00E, 0x00F, 0x010, 0x011, 0x012, \
-				 0x013, 0x014 }
+
+/* Edgeport TI based devices */
+#define ION_DEVICE_ID_TI_EDGEPORT_4		0x0201	/* Edgeport/4 RS232 */
+#define ION_DEVICE_ID_TI_EDGEPORT_2		0x0205	/* Edgeport/2 RS232 */
+#define ION_DEVICE_ID_TI_EDGEPORT_4I		0x0206	/* Edgeport/4i RS422 */
+#define ION_DEVICE_ID_TI_EDGEPORT_2I		0x0207	/* Edgeport/2i RS422/RS485 */
+#define ION_DEVICE_ID_TI_EDGEPORT_421		0x020C	/* Edgeport/421 4 hub 2 RS232 + Parallel (lucent on a different hub port) */
+#define ION_DEVICE_ID_TI_EDGEPORT_21		0x020D	/* Edgeport/21 2 RS232 + Parallel (lucent on a different hub port) */
+#define ION_DEVICE_ID_TI_EDGEPORT_1		0x0215	/* Edgeport/1 RS232 */
+#define ION_DEVICE_ID_TI_EDGEPORT_42		0x0217	/* Edgeport/42 4 hub 2 RS232 */
+#define ION_DEVICE_ID_TI_EDGEPORT_22		0x021A	/* Edgeport/22  Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 */
+
+#define ION_DEVICE_ID_TI_EDGEPORT_421_BOOT	0x0240	/* Edgeport/421 in boot mode */
+#define ION_DEVICE_ID_TI_EDGEPORT_421_DOWN	0x0241	/* Edgeport/421 in download mode first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */
+#define ION_DEVICE_ID_TI_EDGEPORT_21_BOOT	0x0242	/* Edgeport/21 in boot mode */
+#define ION_DEVICE_ID_TI_EDGEPORT_21_DOWN	0x0243	/*Edgeport/42 in download mode: first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */
 
 
 #define	MAKE_USB_PRODUCT_ID( OemId, DeviceId )					\
@@ -217,7 +228,7 @@
 //		descriptor format, so that they may be separately retrieved,
 //		if necessary, with a minimum of work on the 930. This also
 //		requires them to be in UNICODE format, which, for English at
-//		least, simply means extending each UCHAR into a USHORT.
+//		least, simply means extending each __u8 into a __u16.
 //	3.	For all fields, 00 means 'uninitialized'.
 //	4.	All unused areas should be set to 00 for future expansion.
 //
@@ -385,5 +396,92 @@
 
 #define	BOOT_CAP_RESET_CMD	0x0001	// If set, boot correctly supports ION_RESET_DEVICE
 
-#endif	// if !defined()
 
+
+/************************************************************************
+                 T I   U M P   D E F I N I T I O N S
+ ***********************************************************************/
+
+//************************************************************************
+//	TI I2C Format Definitions
+//************************************************************************
+#define I2C_DESC_TYPE_INFO_BASIC	1
+#define I2C_DESC_TYPE_FIRMWARE_BASIC	2
+#define I2C_DESC_TYPE_DEVICE		3
+#define I2C_DESC_TYPE_CONFIG		4
+#define I2C_DESC_TYPE_STRING		5
+#define I2C_DESC_TYPE_FIRMWARE_BLANK 	0xf2
+
+#define I2C_DESC_TYPE_MAX		5
+// 3410 may define types 6, 7 for other firmware downloads
+
+// Special section defined by ION
+#define I2C_DESC_TYPE_ION		0	// Not defined by TI
+
+
+struct ti_i2c_desc
+{
+	__u8	Type;			// Type of descriptor
+	__u16	Size;			// Size of data only not including header
+	__u8	CheckSum;		// Checksum (8 bit sum of data only)
+	__u8	Data[0];		// Data starts here
+}__attribute__((packed));
+
+struct ti_i2c_firmware_rec 
+{
+	__u8	Ver_Major;		// Firmware Major version number
+	__u8	Ver_Minor;		// Firmware Minor version number
+	__u8	Data[0];		// Download starts here
+}__attribute__((packed));
+
+
+// Structure of header of download image in fw_down.h
+struct ti_i2c_image_header
+{
+	__u16	Length;
+	__u8	CheckSum;
+}__attribute__((packed));
+
+typedef struct
+{
+	__u8	Power;		// Self powered
+				// bit 7: 1 - power switching supported
+				//        0 - power switching not supported
+				//
+				// bit 0: 1 - self powered
+				//        0 - bus powered
+				//
+				//
+	__u16	HubVid;		// VID HUB
+	__u16	HubPid;		// PID HUB
+	__u16	DevPid;		// PID Edgeport
+	__u8	HubTime;	// Time for power on to power good
+	__u8	HubCurrent;	// HUB Current = 100ma
+} TI_BASIC_DESCRIPTOR, *PTI_BASIC_DESCRIPTOR __attribute__((packed));
+
+
+#define TI_GET_CPU_REVISION(x)		(__u8)((((x)>>4)&0x0f))
+#define TI_GET_BOARD_REVISION(x)	(__u8)(((x)&0x0f))
+
+#define TI_I2C_SIZE_MASK		0x1f  // 5 bits
+#define TI_GET_I2C_SIZE(x)		((((x) & TI_I2C_SIZE_MASK)+1)*256)
+
+#define TI_MAX_I2C_SIZE			( 16 * 1024 )
+
+/* TI USB 5052 definitions */
+struct edge_ti_manuf_descriptor
+{
+	__u8 IonConfig;		//  Config byte for ION manufacturing use
+	__u8 IonConfig2;	//  Expansion
+	__u8 Version;		//  Verqsion
+	__u8 CpuRev_BoardRev;	//  CPU revision level (0xF0) and Board Rev Level (0x0F)
+	__u8 NumPorts;		//  Number of ports	for this UMP
+	__u8 NumVirtualPorts;	//  Number of Virtual ports
+	__u8 HubConfig1;	//  Used to configure the Hub
+	__u8 HubConfig2;	//  Used to configure the Hub
+	__u8 TotalPorts;	//  Total Number of Com Ports for the entire device (All UMPs)
+	__u8 Reserved;
+}__attribute__((packed));
+
+
+#endif		// if !defined()
diff -urN linux-2.4.20-pre1/drivers/usb/serial/keyspan.c linux-2.4.20-pre2/drivers/usb/serial/keyspan.c
--- linux-2.4.20-pre1/drivers/usb/serial/keyspan.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/drivers/usb/serial/keyspan.c	Mon Aug 12 16:34:16 2002
@@ -109,11 +109,11 @@
 
 	const keyspan_device_details	*device_details;
 
-	urb_t		*instat_urb;
+	struct urb	*instat_urb;
 	char		instat_buf[INSTAT_BUFLEN];
 
 	/* XXX this one probably will need a lock */
-	urb_t		*glocont_urb;
+	struct urb	*glocont_urb;
 	char		glocont_buf[GLOCONT_BUFLEN];
 };
 
@@ -128,18 +128,18 @@
 	const keyspan_device_details	*device_details;
 
 	/* Input endpoints and buffer for this port */
-	urb_t		*in_urbs[2];
+	struct urb	*in_urbs[2];
 	char		in_buffer[2][64];
 	/* Output endpoints and buffer for this port */
-	urb_t		*out_urbs[2];
+	struct urb	*out_urbs[2];
 	char		out_buffer[2][64];
 
 	/* Input ack endpoint */
-	urb_t		*inack_urb;
+	struct urb	*inack_urb;
 	char		inack_buffer[1];
 
 	/* Output control endpoint */
-	urb_t		*outcont_urb;
+	struct urb	*outcont_urb;
 	char		outcont_buffer[64];
 
 	/* Settings for the port */
@@ -340,7 +340,7 @@
 	const keyspan_device_details	*d_details;
 	int				flip;
 	int 				left, todo;
-	urb_t 				*this_urb;
+	struct urb			*this_urb;
 	int 				err;
 
 	p_priv = (struct keyspan_port_private *)(port->private);
@@ -869,7 +869,7 @@
 	struct usb_serial 		*serial = port->serial;
 	const keyspan_device_details	*d_details;
 	int				i, already_active, err;
-	urb_t *urb;
+	struct urb			*urb;
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
@@ -909,7 +909,7 @@
 	return (0);
 }
 
-static inline void stop_urb(urb_t *urb)
+static inline void stop_urb(struct urb *urb)
 {
 	if (urb && urb->status == -EINPROGRESS) {
 		urb->transfer_flags &= ~USB_ASYNC_UNLINK;
@@ -1065,11 +1065,11 @@
 }
 
 /* Helper functions used by keyspan_setup_urbs */
-static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
+static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
 				int dir, void *ctx, char *buf, int len,
-				void (*callback)(urb_t *))
+				void (*callback)(struct urb *))
 {
-	urb_t *urb;
+	struct urb *urb;
 
 	if (endpoint == -1)
 		return NULL;		/* endpoint not needed */
@@ -1090,12 +1090,12 @@
 }
 
 static struct callbacks {
-	void	(*instat_callback)(urb_t *);
-	void	(*glocont_callback)(urb_t *);
-	void	(*indat_callback)(urb_t *);
-	void	(*outdat_callback)(urb_t *);
-	void	(*inack_callback)(urb_t *);
-	void	(*outcont_callback)(urb_t *);
+	void	(*instat_callback)(struct urb *);
+	void	(*glocont_callback)(struct urb *);
+	void	(*indat_callback)(struct urb *);
+	void	(*outdat_callback)(struct urb *);
+	void	(*inack_callback)(struct urb *);
+	void	(*outcont_callback)(struct urb *);
 } keyspan_callbacks[] = {
 	{
 		/* msg_usa26 callbacks */
@@ -1319,7 +1319,7 @@
 	struct keyspan_port_private 		*p_priv;
 	const  keyspan_device_details		*d_details;
 	int 					outcont_urb;
-	urb_t *this_urb;
+	struct urb				*this_urb;
 	int err;
 
 	dbg ("%s reset=%d\n", __FUNCTION__, reset_port); 
@@ -1454,7 +1454,7 @@
 	struct keyspan_serial_private	 	*s_priv;
 	struct keyspan_port_private 		*p_priv;
 	const  keyspan_device_details		*d_details;
-	urb_t *this_urb;
+	struct urb				*this_urb;
 	int err;
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
@@ -1540,7 +1540,7 @@
 	struct keyspan_port_private 		*p_priv;
 	const  keyspan_device_details		*d_details;
 	int 					glocont_urb;
-	urb_t 					*this_urb;
+	struct urb				*this_urb;
 	int 					err;
 	int					device_port;
 
diff -urN linux-2.4.20-pre1/drivers/usb/serial/pl2303.c linux-2.4.20-pre2/drivers/usb/serial/pl2303.c
--- linux-2.4.20-pre1/drivers/usb/serial/pl2303.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/serial/pl2303.c	Mon Aug 12 16:34:16 2002
@@ -69,6 +69,7 @@
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
 	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -urN linux-2.4.20-pre1/drivers/usb/serial/pl2303.h linux-2.4.20-pre2/drivers/usb/serial/pl2303.h
--- linux-2.4.20-pre1/drivers/usb/serial/pl2303.h	Tue Oct  9 15:15:02 2001
+++ linux-2.4.20-pre2/drivers/usb/serial/pl2303.h	Mon Aug 12 16:34:16 2002
@@ -16,3 +16,6 @@
 
 #define IODATA_VENDOR_ID	0x04bb
 #define IODATA_PRODUCT_ID	0x0a03
+
+#define ELCOM_VENDOR_ID		0x056e
+#define ELCOM_PRODUCT_ID	0x5003
diff -urN linux-2.4.20-pre1/drivers/usb/serial/usbserial.c linux-2.4.20-pre2/drivers/usb/serial/usbserial.c
--- linux-2.4.20-pre1/drivers/usb/serial/usbserial.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.20-pre2/drivers/usb/serial/usbserial.c	Mon Aug 12 16:34:16 2002
@@ -1161,15 +1161,6 @@
 	/* END HORRIBLE HACK FOR PL2303 */
 #endif
 	
-	/* verify that we found all of the endpoints that we need */
-	if (!((interrupt_pipe & type->needs_interrupt_in) &&
-	      (bulk_in_pipe & type->needs_bulk_in) &&
-	      (bulk_out_pipe & type->needs_bulk_out))) {
-		/* nope, they don't match what we expected */
-		info("descriptors matched, but endpoints did not");
-		return NULL;
-	}
-
 	/* found all that we need */
 	info("%s converter detected", type->name);
 
@@ -1201,15 +1192,6 @@
 	serial->vendor = dev->descriptor.idVendor;
 	serial->product = dev->descriptor.idProduct;
 
-	/* if this device type has a startup function, call it */
-	if (type->startup) {
-		i = type->startup (serial);
-		if (i < 0)
-			goto probe_error;
-		if (i > 0)
-			return serial;
-	}
-
 	/* set up the endpoint information */
 	for (i = 0; i < num_bulk_in; ++i) {
 		endpoint = bulk_in_endpoint[i];
@@ -1298,7 +1280,16 @@
 		port->tqueue.data = port;
 		init_MUTEX (&port->sem);
 	}
-	
+
+	/* if this device type has a startup function, call it */
+	if (type->startup) {
+		i = type->startup (serial);
+		if (i < 0)
+			goto probe_error;
+		if (i > 0)
+			return serial;
+	}
+
 	/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
 	for (i = 0; i < serial->num_ports; ++i) {
 		tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number);
diff -urN linux-2.4.20-pre1/drivers/usb/storage/transport.c linux-2.4.20-pre2/drivers/usb/storage/transport.c
--- linux-2.4.20-pre1/drivers/usb/storage/transport.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/storage/transport.c	Mon Aug 12 16:34:16 2002
@@ -346,7 +346,7 @@
 /* This is the completion handler which will wake us up when an URB
  * completes.
  */
-static void usb_stor_blocking_completion(urb_t *urb)
+static void usb_stor_blocking_completion(struct urb *urb)
 {
 	struct completion *urb_done_ptr = (struct completion *)urb->context;
 
@@ -362,19 +362,19 @@
 {
 	struct completion urb_done;
 	int status;
-	devrequest *dr;
+	struct usb_ctrlrequest *dr;
 
 	/* allocate the device request structure */
-	dr = kmalloc(sizeof(devrequest), GFP_NOIO);
+	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
 	if (!dr)
 		return -ENOMEM;
 
 	/* fill in the structure */
-	dr->requesttype = requesttype;
-	dr->request = request;
-	dr->value = cpu_to_le16(value);
-	dr->index = cpu_to_le16(index);
-	dr->length = cpu_to_le16(size);
+	dr->bRequestType = requesttype;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16(value);
+	dr->wIndex = cpu_to_le16(index);
+	dr->wLength = cpu_to_le16(size);
 
 	/* set up data structures for the wakeup system */
 	init_completion(&urb_done);
diff -urN linux-2.4.20-pre1/drivers/usb/stv680.c linux-2.4.20-pre2/drivers/usb/stv680.c
--- linux-2.4.20-pre1/drivers/usb/stv680.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/stv680.c	Mon Aug 12 16:34:16 2002
@@ -772,7 +772,7 @@
 
 static int stv680_start_stream (struct usb_stv *stv680)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int err = 0, i;
 
 	stv680->streaming = 1;
diff -urN linux-2.4.20-pre1/drivers/usb/stv680.h linux-2.4.20-pre2/drivers/usb/stv680.h
--- linux-2.4.20-pre1/drivers/usb/stv680.h	Mon Feb 25 11:38:07 2002
+++ linux-2.4.20-pre2/drivers/usb/stv680.h	Mon Aug 12 16:34:16 2002
@@ -118,7 +118,7 @@
 	int removed;		/* device disconnected */
 	int streaming;		/* Are we streaming video? */
 	char *fbuf;		/* Videodev buffer area */
-	urb_t *urb[STV680_NUMSBUF];	/* # of queued bulk transfers */
+	struct urb *urb[STV680_NUMSBUF];	/* # of queued bulk transfers */
 	int curframe;		/* Current receiving frame */
 	struct stv680_frame frame[STV680_NUMFRAMES];	/* # frames supported by v4l part */
 	int readcount;
diff -urN linux-2.4.20-pre1/drivers/usb/tiglusb.c linux-2.4.20-pre2/drivers/usb/tiglusb.c
--- linux-2.4.20-pre1/drivers/usb/tiglusb.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/tiglusb.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,514 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tiglusb -- Texas Instruments' USB GraphLink (aka SilverLink) driver.
+ * Target: Texas Instruments graphing calculators (http://lpg.ticalc.org).
+ *
+ * Copyright (C) 2001-2002:
+ *   Romain Lievin <roms@lpg.ticalc.org>
+ *   Julien BLACHE <jb@technologeek.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Based on dabusb.c, printer.c & scanner.c
+ *
+ * Please see the file: linux/Documentation/usb/SilverLink.txt
+ * and the website at:  http://lpg.ticalc.org/prj_usb/
+ * for more info.
+ *
+ * History :
+ *  16/07/2002 : v1.04 -- Julien BLACHE <jb@jblache.org>
+ *    + removed useless usblp_cleanup()
+ *    + removed {un,}lock_kernel() as suggested on lkml
+ *    + inlined clear_pipes() (used once)
+ *    + inlined clear_device() (small, used twice)
+ *    + removed tiglusb_find_struct() (used once, simple code)
+ *    + replaced down() with down_interruptible() wherever possible
+ *    + fixed double unregistering wrt devfs, causing devfs
+ *      to force an oops when the device is deconnected
+ *    + removed unused fields from struct tiglusb_t
+ */
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <linux/ticable.h>
+#include "tiglusb.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.04"
+#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org> & Julien Blache <jb@jblache.org>"
+#define DRIVER_DESC    "TI-GRAPH LINK USB (aka SilverLink) driver"
+#define DRIVER_LICENSE "GPL"
+
+/* ----- global variables --------------------------------------------- */
+
+static tiglusb_t tiglusb[MAXTIGL];
+static int timeout = TIMAXTIME;	/* timeout in tenth of seconds     */
+
+static devfs_handle_t devfs_handle;
+
+/*---------- misc functions ------------------------------------------- */
+
+/*
+ * Re-initialize device
+ */
+static inline int
+clear_device (struct usb_device *dev)
+{
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+		err ("clear_device failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* 
+ * Clear input & output pipes (endpoints)
+ */
+static inline int
+clear_pipes (struct usb_device *dev)
+{
+	unsigned int pipe;
+
+	pipe = usb_sndbulkpipe (dev, 1);
+	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
+		err ("clear_pipe (r), request failed");
+		return -1;
+	}
+
+	pipe = usb_sndbulkpipe (dev, 2);
+	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
+		err ("clear_pipe (w), request failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* ----- file operations functions--------------------------------------- */
+
+static int
+tiglusb_open (struct inode *inode, struct file *filp)
+{
+	int devnum = minor (inode->i_rdev);
+	ptiglusb_t s;
+
+	if (devnum < TIUSB_MINOR || devnum >= (TIUSB_MINOR + MAXTIGL))
+		return -EIO;
+
+	s = &tiglusb[devnum - TIUSB_MINOR];
+
+	if (down_interruptible (&s->mutex)) {
+		return -ERESTARTSYS;
+	}
+
+	while (!s->dev || s->opened) {
+		up (&s->mutex);
+
+		if (filp->f_flags & O_NONBLOCK) {
+			return -EBUSY;
+		}
+
+		schedule_timeout (HZ / 2);
+
+		if (signal_pending (current)) {
+			return -EAGAIN;
+		}
+
+		if (down_interruptible (&s->mutex)) {
+			return -ERESTARTSYS;
+		}
+	}
+
+	s->opened = 1;
+	up (&s->mutex);
+
+	filp->f_pos = 0;
+	filp->private_data = s;
+
+	return 0;
+}
+
+static int
+tiglusb_release (struct inode *inode, struct file *filp)
+{
+	ptiglusb_t s = (ptiglusb_t) filp->private_data;
+
+	if (down_interruptible (&s->mutex)) {
+		return -ERESTARTSYS;
+	}
+
+	s->state = _stopped;
+	up (&s->mutex);
+
+	if (!s->remove_pending)
+		clear_device (s->dev);
+	else
+		wake_up (&s->remove_ok);
+
+	s->opened = 0;
+
+	return 0;
+}
+
+static ssize_t
+tiglusb_read (struct file *filp, char *buf, size_t count, loff_t * f_pos)
+{
+	ptiglusb_t s = (ptiglusb_t) filp->private_data;
+	ssize_t ret = 0;
+	int bytes_to_read = 0;
+	int bytes_read = 0;
+	int result = 0;
+	char buffer[BULK_RCV_MAX];
+	unsigned int pipe;
+
+	if (*f_pos)
+		return -ESPIPE;
+
+	if (s->remove_pending)
+		return -EIO;
+
+	if (!s->dev)
+		return -EIO;
+
+	bytes_to_read = (count >= BULK_RCV_MAX) ? BULK_RCV_MAX : count;
+
+	pipe = usb_rcvbulkpipe (s->dev, 1);
+	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
+			       &bytes_read, HZ / (timeout / 10));
+	if (result == -ETIMEDOUT) {	/* NAK */
+		ret = result;
+		if (!bytes_read) {
+			dbg ("quirk !");
+		}
+		warn ("tiglusb_read, NAK received.");
+		goto out;
+	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
+		warn ("clear_halt request to remove STALL condition.");
+		if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+			err ("clear_halt, request failed");
+		clear_device (s->dev);
+		ret = result;
+		goto out;
+	} else if (result < 0) {	/* We should not get any I/O errors */
+		err ("funky result: %d. Please notify maintainer.", result);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (copy_to_user (buf, buffer, bytes_read)) {
+		ret = -EFAULT;
+	}
+
+      out:
+	return ret ? ret : bytes_read;
+}
+
+static ssize_t
+tiglusb_write (struct file *filp, const char *buf, size_t count, loff_t * f_pos)
+{
+	ptiglusb_t s = (ptiglusb_t) filp->private_data;
+	ssize_t ret = 0;
+	int bytes_to_write = 0;
+	int bytes_written = 0;
+	int result = 0;
+	char buffer[BULK_SND_MAX];
+	unsigned int pipe;
+
+	if (*f_pos)
+		return -ESPIPE;
+
+	if (s->remove_pending)
+		return -EIO;
+
+	if (!s->dev)
+		return -EIO;
+
+	bytes_to_write = (count >= BULK_SND_MAX) ? BULK_SND_MAX : count;
+	if (copy_from_user (buffer, buf, bytes_to_write)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	pipe = usb_sndbulkpipe (s->dev, 2);
+	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
+			       &bytes_written, HZ / (timeout / 10));
+
+	if (result == -ETIMEDOUT) {	/* NAK */
+		warn ("tiglusb_write, NAK received.");
+		ret = result;
+		goto out;
+	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
+		warn ("clear_halt request to remove STALL condition.");
+		if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+			err ("clear_halt, request failed");
+		clear_device (s->dev);
+		ret = result;
+		goto out;
+	} else if (result < 0) {	/* We should not get any I/O errors */
+		warn ("funky result: %d. Please notify maintainer.", result);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (bytes_written != bytes_to_write) {
+		ret = -EIO;
+	}
+
+      out:
+	return ret ? ret : bytes_written;
+}
+
+static int
+tiglusb_ioctl (struct inode *inode, struct file *filp,
+	       unsigned int cmd, unsigned long arg)
+{
+	ptiglusb_t s = (ptiglusb_t) filp->private_data;
+	int ret = 0;
+
+	if (s->remove_pending)
+		return -EIO;
+
+	if (down_interruptible (&s->mutex)) {
+		return -ERESTARTSYS;
+	}
+
+	if (!s->dev) {
+		up (&s->mutex);
+		return -EIO;
+	}
+
+	switch (cmd) {
+	case IOCTL_TIUSB_TIMEOUT:
+		timeout = arg;	// timeout value in tenth of seconds
+		break;
+	case IOCTL_TIUSB_RESET_DEVICE:
+		dbg ("IOCTL_TIGLUSB_RESET_DEVICE");
+		if (clear_device (s->dev))
+			ret = -EIO;
+		break;
+	case IOCTL_TIUSB_RESET_PIPES:
+		dbg ("IOCTL_TIGLUSB_RESET_PIPES");
+		if (clear_pipes (s->dev))
+			ret = -EIO;
+		break;
+	default:
+		ret = -ENOTTY;
+		break;
+	}
+
+	up (&s->mutex);
+
+	return ret;
+}
+
+/* ----- kernel module registering ------------------------------------ */
+
+static struct file_operations tiglusb_fops = {
+	.llseek =	no_llseek,
+	.read =		tiglusb_read,
+	.write =	tiglusb_write,
+	.ioctl =	tiglusb_ioctl,
+	.open =		tiglusb_open,
+	.release =	tiglusb_release,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+static void *
+tiglusb_probe (struct usb_device *dev, unsigned int ifnum,
+	       const struct usb_device_id *id)
+{
+	int minor = -1;
+	int i;
+	ptiglusb_t s;
+	char name[8];
+
+	dbg ("probing vendor id 0x%x, device id 0x%x ifnum:%d",
+	     dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+
+	/*
+	 * We don't handle multiple configurations. As of version 0x0103 of
+	 * the TIGL hardware, there's only 1 configuration.
+	 */
+
+	if (dev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	if ((dev->descriptor.idProduct != 0xe001)
+	    && (dev->descriptor.idVendor != 0x451))
+		return NULL;
+
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+		err ("tiglusb_probe: set_configuration failed");
+		return NULL;
+	}
+
+	/*
+	 * Find a tiglusb struct
+	 */
+	for (i = 0; i < MAXTIGL; i++) {
+		ptiglusb_t s = &tiglusb[i];
+		if (!s->dev) {
+			minor = i;
+			break;
+		}
+	}
+
+	if (minor == -1)
+		return NULL;
+
+	s = &tiglusb[minor];
+
+	down (&s->mutex);
+	s->remove_pending = 0;
+	s->dev = dev;
+	up (&s->mutex);
+	dbg ("bound to interface: %d", ifnum);
+
+	sprintf (name, "%d", s->minor);
+	dbg ("registering to devfs : major = %d, minor = %d, node = %s",
+	     TIUSB_MAJOR, (TIUSB_MINOR + s->minor), name);
+	s->devfs =
+	    devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, TIUSB_MAJOR,
+			    TIUSB_MINOR + s->minor, S_IFCHR | S_IRUGO | S_IWUGO,
+			    &tiglusb_fops, NULL);
+
+	/* Display firmware version */
+	info ("link cable version %i.%02x",
+		dev->descriptor.bcdDevice >> 8,
+		dev->descriptor.bcdDevice & 0xff);
+
+	return s;
+}
+
+static void
+tiglusb_disconnect (struct usb_device *dev, void *drv_context)
+{
+	ptiglusb_t s = (ptiglusb_t) drv_context;
+
+	if (!s || !s->dev)
+		info ("bogus disconnect");
+
+	s->remove_pending = 1;
+	wake_up (&s->wait);
+	if (s->state == _started)
+		sleep_on (&s->remove_ok);
+	down (&s->mutex);
+	s->dev = NULL;
+	s->opened = 0;
+
+	devfs_unregister (s->devfs);
+	s->devfs = NULL;
+
+	info ("device %d removed", s->minor);
+
+	up (&s->mutex);
+}
+
+static struct usb_device_id tiglusb_ids[] = {
+	{USB_DEVICE (0x0451, 0xe001)},
+	{}
+};
+
+MODULE_DEVICE_TABLE (usb, tiglusb_ids);
+
+static struct usb_driver tiglusb_driver = {
+	.name =		"tiglusb",
+	.probe =	tiglusb_probe,
+	.disconnect =	tiglusb_disconnect,
+	.id_table =	tiglusb_ids,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+#ifndef MODULE
+/*
+ * You can use 'tiusb=timeout'
+ */
+static int __init
+tiglusb_setup (char *str)
+{
+	int ints[2];
+
+	str = get_options (str, ARRAY_SIZE (ints), ints);
+
+	if (ints[0] > 0) {
+		timeout = ints[1];
+	}
+
+	return 1;
+}
+#endif
+
+static int __init
+tiglusb_init (void)
+{
+	unsigned u;
+	int result;
+
+	/* initialize struct */
+	for (u = 0; u < MAXTIGL; u++) {
+		ptiglusb_t s = &tiglusb[u];
+		memset (s, 0, sizeof (tiglusb_t));
+		init_MUTEX (&s->mutex);
+		s->dev = NULL;
+		s->minor = u;
+		s->opened = 0;
+		init_waitqueue_head (&s->wait);
+		init_waitqueue_head (&s->remove_ok);
+	}
+
+	/* register device */
+	if (devfs_register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
+		err ("unable to get major %d", TIUSB_MAJOR);
+		return -EIO;
+	}
+
+	/* Use devfs, tree: /dev/ticables/usb/[0..3] */
+	devfs_handle = devfs_mk_dir (NULL, "ticables/usb", NULL);
+
+	/* register USB module */
+	result = usb_register (&tiglusb_driver);
+	if (result < 0) {
+		devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+		return -1;
+	}
+
+	info (DRIVER_DESC ", " DRIVER_VERSION);
+
+	return 0;
+}
+
+static void __exit
+tiglusb_cleanup (void)
+{
+	usb_deregister (&tiglusb_driver);
+	devfs_unregister (devfs_handle);
+	devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+}
+
+/* --------------------------------------------------------------------- */
+
+__setup ("tiusb=", tiglusb_setup);
+module_init (tiglusb_init);
+module_exit (tiglusb_cleanup);
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE (DRIVER_LICENSE);
+
+MODULE_PARM (timeout, "i");
+MODULE_PARM_DESC (timeout, "Timeout (default=1.5 seconds)");
+
+/* --------------------------------------------------------------------- */
diff -urN linux-2.4.20-pre1/drivers/usb/tiglusb.h linux-2.4.20-pre2/drivers/usb/tiglusb.h
--- linux-2.4.20-pre1/drivers/usb/tiglusb.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/tiglusb.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,48 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tiglusb - low level driver for SilverLink cable
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _TIGLUSB_H
+#define _TIGLUSB_H
+
+/*
+ * Max. number of devices supported
+ */
+#define MAXTIGL		16
+
+/*
+ * Max. packetsize for IN and OUT pipes
+ */
+#define BULK_RCV_MAX	32
+#define BULK_SND_MAX	32
+
+/*
+ * The driver context...
+ */
+
+typedef enum { _stopped=0, _started } driver_state_t;
+
+typedef struct
+{
+	struct usb_device	*dev;		/* USB device handle */
+	struct semaphore	mutex;		/* locks this struct */
+
+	wait_queue_head_t	wait;		/* for timed waits */
+	wait_queue_head_t	remove_ok;
+
+	int		minor;			/* which minor dev #? */
+	devfs_handle_t	devfs;			/* devfs device */
+
+	driver_state_t	state;			/* started/stopped */
+	int		opened;			/* tru if open */
+	int	remove_pending;
+} tiglusb_t, *ptiglusb_t;
+
+#endif
diff -urN linux-2.4.20-pre1/drivers/usb/uhci.c linux-2.4.20-pre2/drivers/usb/uhci.c
--- linux-2.4.20-pre1/drivers/usb/uhci.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/uhci.c	Mon Aug 12 16:34:17 2002
@@ -649,7 +649,7 @@
 
 		if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
 			urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
-				urb->setup_packet, sizeof(devrequest),
+				urb->setup_packet, sizeof(struct usb_ctrlrequest),
 				PCI_DMA_TODEVICE);
 			if (!urbp->setup_packet_dma_handle)
 				return NULL;
@@ -724,7 +724,7 @@
 
 	if (urbp->setup_packet_dma_handle) {
 		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(devrequest), PCI_DMA_TODEVICE);
+			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 		urbp->setup_packet_dma_handle = 0;
 	}
 
@@ -2073,7 +2073,7 @@
 {
 	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
 	unsigned int pipe = urb->pipe;
-	devrequest *cmd = (devrequest *)urb->setup_packet;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
 	void *data = urb->transfer_buffer;
 	int leni = urb->transfer_buffer_length;
 	int len = 0;
@@ -2096,10 +2096,10 @@
 		return -EINPROGRESS;
 	}
 
-	bmRType_bReq = cmd->requesttype | cmd->request << 8;
-	wValue = le16_to_cpu(cmd->value);
-	wIndex = le16_to_cpu(cmd->index);
-	wLength = le16_to_cpu(cmd->length);
+	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+	wValue = le16_to_cpu(cmd->wValue);
+	wIndex = le16_to_cpu(cmd->wIndex);
+	wLength = le16_to_cpu(cmd->wLength);
 
 	for (i = 0; i < 8; i++)
 		uhci->rh.c_p_r[i] = 0;
@@ -2340,7 +2340,7 @@
 
 	if (urbp->setup_packet_dma_handle)
 		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(devrequest), PCI_DMA_TODEVICE);
+			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 
 	status = urbp->status;
 	if (!resubmit_interrupt || killed)
diff -urN linux-2.4.20-pre1/drivers/usb/usb-debug.c linux-2.4.20-pre2/drivers/usb/usb-debug.c
--- linux-2.4.20-pre1/drivers/usb/usb-debug.c	Fri Feb  9 11:30:23 2001
+++ linux-2.4.20-pre2/drivers/usb/usb-debug.c	Mon Aug 12 16:34:17 2002
@@ -181,23 +181,23 @@
 	kfree(buf);
 }
 
-void usb_dump_urb (purb_t purb)
+void usb_dump_urb (struct urb *urb)
 {
-	printk ("urb                   :%p\n", purb);
-	printk ("next                  :%p\n", purb->next);
-	printk ("dev                   :%p\n", purb->dev);
-	printk ("pipe                  :%08X\n", purb->pipe);
-	printk ("status                :%d\n", purb->status);
-	printk ("transfer_flags        :%08X\n", purb->transfer_flags);
-	printk ("transfer_buffer       :%p\n", purb->transfer_buffer);
-	printk ("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk ("actual_length         :%d\n", purb->actual_length);
-	printk ("setup_packet          :%p\n", purb->setup_packet);
-	printk ("start_frame           :%d\n", purb->start_frame);
-	printk ("number_of_packets     :%d\n", purb->number_of_packets);
-	printk ("interval              :%d\n", purb->interval);
-	printk ("error_count           :%d\n", purb->error_count);
-	printk ("context               :%p\n", purb->context);
-	printk ("complete              :%p\n", purb->complete);
+	printk ("urb                   :%p\n", urb);
+	printk ("next                  :%p\n", urb->next);
+	printk ("dev                   :%p\n", urb->dev);
+	printk ("pipe                  :%08X\n", urb->pipe);
+	printk ("status                :%d\n", urb->status);
+	printk ("transfer_flags        :%08X\n", urb->transfer_flags);
+	printk ("transfer_buffer       :%p\n", urb->transfer_buffer);
+	printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+	printk ("actual_length         :%d\n", urb->actual_length);
+	printk ("setup_packet          :%p\n", urb->setup_packet);
+	printk ("start_frame           :%d\n", urb->start_frame);
+	printk ("number_of_packets     :%d\n", urb->number_of_packets);
+	printk ("interval              :%d\n", urb->interval);
+	printk ("error_count           :%d\n", urb->error_count);
+	printk ("context               :%p\n", urb->context);
+	printk ("complete              :%p\n", urb->complete);
 }
 
diff -urN linux-2.4.20-pre1/drivers/usb/usb-midi.c linux-2.4.20-pre2/drivers/usb/usb-midi.c
--- linux-2.4.20-pre1/drivers/usb/usb-midi.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/usb-midi.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,2228 @@
+/*
+  usb-midi.c  --  USB-MIDI driver
+
+  Copyright (C) 2001 
+      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  This driver is based on:
+    - 'Universal Serial Bus Device Class Definition for MIDI Device'
+    - linux/drivers/sound/es1371.c, linux/drivers/usb/audio.c
+    - alsa/lowlevel/pci/cs64xx.c
+    - umidi.c for NetBSD
+ */
+
+/* ------------------------------------------------------------------------- */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/wrapper.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/sound.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+
+/** This declaration is missing from linux/usb.h **/
+extern int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size);
+
+#include "usb-midi.h"
+
+/* ------------------------------------------------------------------------- */
+
+/* More verbose on syslog */
+#undef MIDI_DEBUG
+
+#define MIDI_IN_BUFSIZ 1024
+
+#define HAVE_SUPPORT_USB_MIDI_CLASS
+
+#undef HAVE_SUPPORT_ALSA
+
+#undef MOD_INC_EACH_PROBE
+
+/* ------------------------------------------------------------------------- */
+
+static int singlebyte = 0;
+MODULE_PARM(singlebyte,"i");
+MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet");
+
+static int maxdevices = 4;
+MODULE_PARM(maxdevices,"i");
+MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device");
+
+static int uvendor     = -1;
+MODULE_PARM(uvendor,"i");
+MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface");
+
+static int uproduct    = -1;
+MODULE_PARM(uproduct,"i");
+MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface");
+
+static int uinterface  = -1;
+MODULE_PARM(uinterface,"i");
+MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface");
+
+static int ualt        = -1;
+MODULE_PARM(ualt,"i");
+MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface");
+
+static int umin        = -1;
+MODULE_PARM(umin,"i");
+MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface");
+
+static int umout       = -1;
+MODULE_PARM(umout,"i");
+MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface");
+
+static int ucable      = -1;
+MODULE_PARM(ucable,"i");
+MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface");
+
+/** Note -- the usb_string() returns only Latin-1 characters.
+ * (unicode chars <= 255). To support Japanese, a unicode16LE-to-EUC or
+ * unicode16LE-to-JIS routine is needed to wrap around usb_get_string().
+ **/
+static unsigned short ulangid      = 0x0409; /** 0x0411 for Japanese **/
+MODULE_PARM(ulangid,"h");
+MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices");
+
+MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>");
+MODULE_DESCRIPTION("USB-MIDI driver");
+#if LINUX_VERSION_CODE  >= KERNEL_VERSION(2,4,14)
+MODULE_LICENSE("GPL");
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/** MIDIStreaming Class-Specific Interface Descriptor Subtypes **/
+
+#define MS_DESCRIPTOR_UNDEFINED	0
+#define MS_HEADER		1
+#define MIDI_IN_JACK		2
+#define MIDI_OUT_JACK		3
+/* Spec reads: ELEMENT */
+#define ELEMENT_DESCRIPTOR   	4
+
+#define MS_HEADER_LENGTH	7
+
+/** MIDIStreaming Class-Specific Endpoint Descriptor Subtypes **/
+
+#define DESCRIPTOR_UNDEFINED	0
+/* Spec reads: MS_GENERAL */
+#define MS_GENERAL_ENDPOINT	1
+
+/** MIDIStreaming MIDI IN and OUT Jack Types **/
+
+#define JACK_TYPE_UNDEFINED	0
+/* Spec reads: EMBEDDED */
+#define EMBEDDED_JACK		1
+/* Spec reads: EXTERNAL */
+#define EXTERNAL_JACK		2
+
+
+/* structure summary
+  
+      usb_midi_state     usb_device
+       |         |
+      *|        *|       per ep
+     in_ep     out_ep
+       |         |
+      *|        *|       per cable
+      min       mout
+       |         |       (cable to device pairing magic)
+       |         |
+       usb_midi_dev      dev_id (major,minor) == file->private_data
+
+*/
+
+/* usb_midi_state: corresponds to a USB-MIDI module */
+struct usb_midi_state {
+	struct list_head   mididev;
+	
+	struct usb_device *usbdev;
+	
+	struct list_head   midiDevList;
+	struct list_head   inEndpointList;
+	struct list_head   outEndpointList;
+	
+	spinlock_t         lock;
+	
+	unsigned int       count; /* usage counter */
+};
+
+/* midi_out_endpoint: corresponds to an output endpoint */
+struct midi_out_endpoint {
+	struct list_head  list;
+	
+	struct usb_device *usbdev;
+	int                endpoint;
+	spinlock_t         lock;
+	wait_queue_head_t  wait;
+	
+	unsigned char     *buf;
+	int                bufWrPtr;
+	int                bufSize;
+	
+	struct urb       *urb;
+};
+
+/* midi_in_endpoint: corresponds to an input endpoint */
+struct midi_in_endpoint {
+	struct list_head   list;
+
+	struct usb_device *usbdev;
+	int                endpoint;
+	spinlock_t         lock;
+	wait_queue_head_t  wait;
+
+	struct usb_mididev *cables[16];	// cables open for read
+	int                 readers;	// number of cables open for read
+
+	struct urb        *urb;
+	unsigned char     *recvBuf;
+	int                recvBufSize;
+	int                urbSubmitted;	//FIXME: == readers > 0
+};
+
+/* usb_mididev: corresponds to a logical device */
+struct usb_mididev {
+	struct list_head       list;
+
+	struct usb_midi_state *midi;
+	int                    dev_midi;
+	mode_t                 open_mode;
+
+	struct {
+		struct midi_in_endpoint *ep;
+		int              cableId;
+		
+// as we are pushing data from usb_bulk_read to usb_midi_read,
+// we need a larger, cyclic buffer here.
+		unsigned char    buf[MIDI_IN_BUFSIZ];
+		int              bufRdPtr;
+		int              bufWrPtr;
+		int              bufRemains;
+	} min;
+
+	struct {
+		struct midi_out_endpoint *ep;
+		int              cableId;
+		
+		unsigned char    buf[3];
+		int              bufPtr;
+		int              bufRemains;
+		
+		int              isInExclusive;
+		unsigned char    lastEvent;
+	} mout;
+
+	int singlebyte;
+};
+
+/** Map the high nybble of MIDI voice messages to number of Message bytes.
+ * High nyble ranges from 0x8 to 0xe
+ */
+
+static int remains_80e0[] = {
+	3,	/** 0x8X Note Off **/
+	3,	/** 0x9X Note On **/
+	3,	/** 0xAX Poly-key pressure **/
+	3,	/** 0xBX Control Change **/
+	2,	/** 0xCX Program Change **/
+	2,	/** 0xDX Channel pressure **/
+	3 	/** 0xEX PitchBend Change **/
+};
+
+/** Map the messages to a number of Message bytes.
+ *
+ **/
+static int remains_f0f6[] = {
+	0,	/** 0xF0 **/
+	2,	/** 0XF1 **/
+	3,	/** 0XF2 **/
+	2,	/** 0XF3 **/
+	2,	/** 0XF4 (Undefined by MIDI Spec, and subject to change) **/
+	2,	/** 0XF5 (Undefined by MIDI Spec, and subject to change) **/
+	1	/** 0XF6 **/
+};
+
+/** Map the messages to a CIN (Code Index Number).
+ *
+ **/
+static int cin_f0ff[] = {
+	4,	/** 0xF0 System Exclusive Message Start (special cases may be 6 or 7) */
+	2,	/** 0xF1 **/
+	3,	/** 0xF2 **/
+	2,	/** 0xF3 **/
+	2,	/** 0xF4 **/
+	2,	/** 0xF5 **/
+	5,	/** 0xF6 **/
+	5,	/** 0xF7 End of System Exclusive Message (May be 6 or 7) **/
+	5,	/** 0xF8 **/
+	5,	/** 0xF9 **/
+	5,	/** 0xFA **/
+	5,	/** 0xFB **/
+	5,	/** 0xFC **/
+	5,	/** 0xFD **/
+	5,	/** 0xFE **/
+	5	/** 0xFF **/
+};
+
+/** Map MIDIStreaming Event packet Code Index Number (low nybble of byte 0)
+ * to the number of bytes of valid MIDI data.
+ *
+ * CIN of 0 and 1 are NOT USED in MIDIStreaming 1.0.
+ *
+ **/
+static int cin_to_len[] = {
+	0, 0, 2, 3,
+	3, 1, 2, 3,
+	3, 3, 3, 3,
+	2, 2, 3, 1
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+static struct list_head mididevs = LIST_HEAD_INIT(mididevs);
+
+static DECLARE_MUTEX(open_sem);
+static DECLARE_WAIT_QUEUE_HEAD(open_wait);
+
+
+/* ------------------------------------------------------------------------- */
+
+static void usb_write_callback(struct urb *urb)
+{
+	struct midi_out_endpoint *ep = (struct midi_out_endpoint *)urb->context;
+
+	if ( waitqueue_active( &ep->wait ) )
+		wake_up_interruptible( &ep->wait );
+}
+
+
+static int usb_write( struct midi_out_endpoint *ep, unsigned char *buf, int len )
+{
+	struct usb_device *d;
+	int pipe;
+	int ret = 0;
+	int status;
+	int maxretry = 50;
+	
+	DECLARE_WAITQUEUE(wait,current);
+	init_waitqueue_head(&ep->wait);
+
+	d = ep->usbdev;
+	pipe = usb_sndbulkpipe(d, ep->endpoint);
+	FILL_BULK_URB( ep->urb, d, pipe, (unsigned char*)buf, len,
+		       (usb_complete_t)usb_write_callback, ep );
+
+	status = usb_submit_urb(ep->urb);
+    
+	if (status) {
+		printk(KERN_ERR "usbmidi: Cannot submit urb (%d)\n",status);
+		ret = -EFAULT;
+	}
+
+	add_wait_queue( &ep->wait, &wait );
+	set_current_state( TASK_INTERRUPTIBLE );
+
+	while( ep->urb->status == -EINPROGRESS ) {
+		if ( maxretry-- < 0 ) {
+			printk(KERN_ERR "usbmidi: usb_bulk_msg timed out\n");
+			ret = -ETIME;
+			break;
+		}
+		interruptible_sleep_on_timeout( &ep->wait, 10 );
+	}
+	set_current_state( TASK_RUNNING );
+	remove_wait_queue( &ep->wait, &wait );
+
+	return ret;
+}
+
+
+/** Copy data from URB to In endpoint buf.
+ * Discard if CIN == 0 or CIN = 1.
+ *
+ *
+ **/
+
+static void usb_bulk_read(struct urb *urb)
+{
+	struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
+	unsigned char *data = urb->transfer_buffer;
+	int i, l, wake;
+	unsigned long int flags;
+
+	if ( !ep->urbSubmitted ) {
+		return;
+	}
+
+	if ( (urb->status == 0) && (urb->actual_length > 0) ) {
+		wake = 0;
+		spin_lock_irqsave( &ep->lock, flags );
+
+		for(l = 0; l < urb->actual_length; l += 4) {
+			int cin = (data[l]>>0)&0xf;
+			int cab = (data[l]>>4)&0xf;
+			struct usb_mididev *cable = ep->cables[cab];
+			if ( cable ) {
+				int len = cin_to_len[cin]; /** length of MIDI data **/
+				for (i = 0; i < len; i++) {
+					cable->min.buf[cable->min.bufWrPtr] = data[1+i];
+					cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
+					if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
+						cable->min.bufRemains += 1;
+					else /** need to drop data **/
+						cable->min.bufRdPtr += (cable->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
+					wake = 1;
+				}
+			}
+		}
+
+		spin_unlock_irqrestore( &ep->lock, flags );
+		if ( wake ) {
+			wake_up( &ep->wait );
+		}
+	}
+
+	/* urb->dev must be reinitialized on 2.4.x kernels */
+	urb->dev = ep->usbdev;
+
+	urb->actual_length = 0;
+	usb_submit_urb(urb);
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+
+/* This routine must be called with spin_lock */
+
+/** Wrapper around usb_write().
+ *  This routine must be called with spin_lock held on ep.
+ *  Called by midiWrite(), putOneMidiEvent(), and  usb_midi_write();
+ **/
+static int flush_midi_buffer( struct midi_out_endpoint *ep )
+{
+	int ret=0;
+
+	if ( ep->bufWrPtr > 0 ) {
+		ret = usb_write( ep, ep->buf, ep->bufWrPtr );
+		ep->bufWrPtr = 0;
+	}
+
+	return ret;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/** Given a MIDI Event, determine size of data to be attached to 
+ * USB-MIDI packet.
+ * Returns 1, 2 or 3.
+ * Called by midiWrite();
+ * Uses remains_80e0 and remains_f0f6;
+ **/
+static int get_remains(int event)
+{
+	int ret;
+
+	if ( event  < 0x80 ) {
+		ret = 1;
+	} else if ( event < 0xf0 ) {
+		ret = remains_80e0[((event-0x80)>>4)&0x0f];
+	} else if ( event < 0xf7 ) {
+		ret = remains_f0f6[event-0xf0];
+	} else {
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/** Given the output MIDI data in the output buffer, computes a reasonable 
+ * CIN.
+ * Called by putOneMidiEvent().
+ **/
+static int get_CIN( struct usb_mididev *m )
+{
+	int cin;
+
+	if ( m->mout.buf[0] == 0xf7 ) {
+		cin = 5;
+	}
+	else if ( m->mout.buf[1] == 0xf7 ) {
+		cin = 6;
+	}
+	else if ( m->mout.buf[2] == 0xf7 ) {
+		cin = 7;
+	}
+	else {
+		if ( m->mout.isInExclusive == 1 ) {
+			cin = 4;
+		} else if ( m->mout.buf[0] < 0x80 ) {
+			/** One byte that we know nothing about. **/
+			cin = 0xF; 
+		} else if ( m->mout.buf[0] < 0xf0 ) {
+			/** MIDI Voice messages 0x8X to 0xEX map to cin 0x8 to 0xE. **/
+			cin = (m->mout.buf[0]>>4)&0x0f; 
+		}
+		else {
+			/** Special lookup table exists for real-time events. **/
+			cin = cin_f0ff[m->mout.buf[0]-0xf0];
+		}
+	}
+
+	return cin;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+
+/** Move data to USB endpoint buffer.
+ *
+ **/
+static int put_one_midi_event(struct usb_mididev *m)
+{
+	int cin;
+	unsigned long flags;
+	struct midi_out_endpoint *ep = m->mout.ep;
+	int ret=0;
+
+	cin = get_CIN( m );
+	if ( cin > 0x0f || cin < 0 ) {
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave( &ep->lock, flags );
+	ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | cin;
+	ep->buf[ep->bufWrPtr++] = m->mout.buf[0];
+	ep->buf[ep->bufWrPtr++] = m->mout.buf[1];
+	ep->buf[ep->bufWrPtr++] = m->mout.buf[2];
+	if ( ep->bufWrPtr >= ep->bufSize ) {
+		ret = flush_midi_buffer( ep );
+	}
+	spin_unlock_irqrestore( &ep->lock, flags);
+
+	m->mout.buf[0] = m->mout.buf[1] = m->mout.buf[2] = 0;
+	m->mout.bufPtr = 0;
+
+	return ret;
+}
+
+/** Write the MIDI message v on the midi device.
+ *  Called by usb_midi_write();
+ *  Responsible for packaging a MIDI data stream into USB-MIDI packets.
+ **/
+
+static int midi_write( struct usb_mididev *m, int v )
+{
+	unsigned long flags;
+	struct midi_out_endpoint *ep = m->mout.ep;
+	int ret=0;
+	unsigned char c = (unsigned char)v;
+	unsigned char sysrt_buf[4];
+
+	if ( m->singlebyte != 0 ) {
+		/** Simple code to handle the single-byte USB-MIDI protocol. */
+		spin_lock_irqsave( &ep->lock, flags );
+		if ( ep->bufWrPtr+4 > ep->bufSize ) {
+			ret = flush_midi_buffer( ep );
+			if ( !ret ) {
+				spin_unlock_irqrestore( &ep->lock, flags );
+				return ret;
+			}
+		}
+		ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) |  0x0f; /* single byte */
+		ep->buf[ep->bufWrPtr++] = c;
+		ep->buf[ep->bufWrPtr++] = 0;
+		ep->buf[ep->bufWrPtr++] = 0;
+		if ( ep->bufWrPtr >= ep->bufSize ) {
+			ret = flush_midi_buffer( ep );
+		}
+		spin_unlock_irqrestore( &ep->lock, flags );
+
+		return ret;
+	}
+	/** Normal USB-MIDI protocol begins here. */
+
+	if ( c > 0xf7 ) {	/* system: Realtime messages */
+		/** Realtime messages are written IMMEDIATELY. */
+		sysrt_buf[0] = (m->mout.cableId<<4) | 0x0f;
+		sysrt_buf[1] = c;
+		sysrt_buf[2] = 0;
+		sysrt_buf[3] = 0;
+		spin_lock_irqsave( &ep->lock, flags );
+		ret = usb_write( ep, sysrt_buf, 4 );
+		spin_unlock_irqrestore( &ep->lock, flags );
+		/* m->mout.lastEvent = 0; */
+
+		return ret;
+	}
+
+	if ( c >= 0x80 ) {
+		if ( c < 0xf0 ) {
+			m->mout.lastEvent = c;
+			m->mout.isInExclusive = 0;
+			m->mout.bufRemains = get_remains(c);
+		} else if ( c == 0xf0 ) {
+			/* m->mout.lastEvent = 0; */
+			m->mout.isInExclusive = 1;
+			m->mout.bufRemains = get_remains(c);
+		} else if ( c == 0xf7 && m->mout.isInExclusive == 1 ) {
+			/* m->mout.lastEvent = 0; */
+			m->mout.isInExclusive = 0;
+			m->mout.bufRemains = 1;
+		} else if ( c > 0xf0 ) {
+			/* m->mout.lastEvent = 0; */
+			m->mout.isInExclusive = 0;
+			m->mout.bufRemains = get_remains(c);
+		}
+    
+	} else if ( m->mout.bufRemains == 0 && m->mout.isInExclusive == 0 ) {
+		if ( m->mout.lastEvent == 0 ) {
+			return 0; /* discard, waiting for the first event */
+		}
+		/** track status **/
+		m->mout.buf[0] = m->mout.lastEvent;
+		m->mout.bufPtr = 1;
+		m->mout.bufRemains = get_remains(m->mout.lastEvent)-1;
+	}
+  
+	m->mout.buf[m->mout.bufPtr++] = c;
+	m->mout.bufRemains--;
+	if ( m->mout.bufRemains == 0 || m->mout.bufPtr >= 3) {
+		ret = put_one_midi_event(m);
+	}
+
+	return ret;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ *  Basic contract: Used to change the current read/write position in a file.
+ *  On success, the non-negative position is reported.
+ *  On failure, the negative of an error code is reported.
+ *
+ *  Because a MIDIStream is not a file, all seek operations are doomed to fail.
+ *
+ **/
+static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin)
+{
+	/** Tell user you cannot seek on a PIPE-like device. **/
+	return -ESPIPE;
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ * Basic contract: Block until count bytes have been read or an error occurs.
+ *
+ **/
+
+static ssize_t usb_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	struct midi_in_endpoint *ep = m->min.ep;
+	ssize_t ret;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if ( ppos != &file->f_pos ) {
+		return -ESPIPE;
+	}
+	if ( !access_ok(VERIFY_READ, buffer, count) ) {
+		return -EFAULT;
+	}
+	if ( count == 0 ) {
+		return 0;
+	}
+
+	add_wait_queue( &ep->wait, &wait );
+	ret = 0;
+	while( count > 0 ) {
+		int cnt;
+		int d = (int)count;
+
+		cnt = m->min.bufRemains;
+		if ( cnt > d ) {
+			cnt = d;
+		}
+
+		if ( cnt <= 0 ) {
+			if ( file->f_flags & O_NONBLOCK ) {
+				if (!ret) 
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if(!ret)
+					ret=-ERESTARTSYS;
+				break;
+			}
+			continue;
+		}
+
+		{
+			int i;
+			unsigned long flags; /* used to synchronize access to the endpoint */
+			spin_lock_irqsave( &ep->lock, flags );
+			for (i = 0; i < cnt; i++) {
+				if ( copy_to_user( buffer+i, m->min.buf+m->min.bufRdPtr, 1 ) ) {
+					if ( !ret )
+						ret = -EFAULT;
+					break;
+				}
+				m->min.bufRdPtr = (m->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
+				m->min.bufRemains -= 1;
+			}
+			spin_unlock_irqrestore( &ep->lock, flags );
+		}
+
+		count-=cnt;
+		buffer+=cnt;
+		ret+=cnt;
+
+		break;
+	}
+
+	remove_wait_queue( &ep->wait, &wait );
+	set_current_state(TASK_RUNNING);
+
+	return ret;
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ *  Basic Contract: Take MIDI data byte-by-byte and pass it to
+ *  writeMidi() which packages MIDI data into USB-MIDI stream.
+ *  Then flushMidiData() is called to ensure all bytes have been written
+ *  in a timely fashion.
+ *
+ **/
+
+static ssize_t usb_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	ssize_t ret;
+	unsigned long int flags;
+
+	if ( ppos != &file->f_pos ) {
+		return -ESPIPE;
+	}
+	if ( !access_ok(VERIFY_READ, buffer, count) ) {
+		return -EFAULT;
+	}
+	if ( count == 0 ) {
+		return 0;
+	}
+
+	ret = 0;
+	while( count > 0 ) {
+		unsigned char c;
+
+		if (copy_from_user((unsigned char *)&c, buffer, 1)) {
+			if ( ret == 0 )
+				ret = -EFAULT;
+			break;
+		}
+		if( midi_write(m, (int)c) ) {
+			if ( ret == 0 )
+				ret = -EFAULT;
+			break;
+		}
+		count--;
+		buffer++;
+		ret++;
+	}
+
+	spin_lock_irqsave( &m->mout.ep->lock, flags );
+	if ( flush_midi_buffer(m->mout.ep) < 0 ) {
+		ret = -EFAULT;
+	}
+	spin_unlock_irqrestore( &m->mout.ep->lock, flags );
+
+	return ret;
+}
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ * Basic contract:  Wait (spin) until ready to read or write on the file.
+ *
+ **/
+static unsigned int usb_midi_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	struct midi_in_endpoint *iep = m->min.ep;
+	struct midi_out_endpoint *oep = m->mout.ep;
+	unsigned long flags;
+	unsigned int mask = 0;
+  
+	if ( file->f_mode & FMODE_READ ) {
+		poll_wait( file, &iep->wait, wait );
+		spin_lock_irqsave( &iep->lock, flags );
+		if ( m->min.bufRemains > 0 )
+			mask |= POLLIN | POLLRDNORM;
+		spin_unlock_irqrestore( &iep->lock, flags );
+	}
+
+	if ( file->f_mode & FMODE_WRITE ) {
+		poll_wait( file, &oep->wait, wait );
+		spin_lock_irqsave( &oep->lock, flags );
+		if ( oep->bufWrPtr < oep->bufSize )
+			mask |= POLLOUT | POLLWRNORM;
+		spin_unlock_irqrestore( &oep->lock, flags );
+	}
+
+	return mask;
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ * Basic contract: This is always the first operation performed on the
+ * device node. If no method is defined, the open succeeds without any
+ * notification given to the module.
+ *
+ **/
+
+static int usb_midi_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	DECLARE_WAITQUEUE(wait, current);
+	struct list_head      *devs, *mdevs;
+	struct usb_midi_state *s;
+	struct usb_mididev    *m;
+	int flags;
+	int succeed = 0;
+
+#if 0
+	printk(KERN_INFO "usb-midi: Open minor= %d.\n", minor);
+#endif
+
+	for(;;) {
+		down(&open_sem);
+		for (devs = mididevs.next; devs != &mididevs; devs = devs->next) {
+			s = list_entry(devs, struct usb_midi_state, mididev);
+			for (mdevs = s->midiDevList.next; mdevs != &s->midiDevList; mdevs = mdevs->next) {
+				m = list_entry(mdevs, struct usb_mididev, list);
+				if ( !((m->dev_midi ^ minor) & ~0xf) )
+					goto device_found;
+			}
+		}
+		up(&open_sem);
+		return -ENODEV;
+
+	device_found:
+		if ( !s->usbdev ) {
+			up(&open_sem);
+			return -EIO;
+		}
+		if ( !(m->open_mode & file->f_mode) ) {
+			break;
+		}
+		if ( file->f_flags & O_NONBLOCK ) {
+			up(&open_sem);
+			return -EBUSY;
+		}
+		__set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue( &open_wait, &wait );
+		up(&open_sem);
+		schedule();
+		__set_current_state(TASK_RUNNING);
+		remove_wait_queue( &open_wait, &wait );
+		if ( signal_pending(current) ) {
+			return -ERESTARTSYS;
+		}
+	}
+
+	file->private_data = m;
+	spin_lock_irqsave( &s->lock, flags );
+
+	if ( !(m->open_mode & (FMODE_READ | FMODE_WRITE)) ) {
+		//FIXME: intented semantics unclear here
+		m->min.bufRdPtr       = 0;
+		m->min.bufWrPtr       = 0;
+		m->min.bufRemains     = 0;
+		spin_lock_init(&m->min.ep->lock);
+
+		m->mout.bufPtr        = 0;
+		m->mout.bufRemains    = 0;
+		m->mout.isInExclusive = 0;
+		m->mout.lastEvent     = 0;
+		spin_lock_init(&m->mout.ep->lock);
+	}
+
+	if ( (file->f_mode & FMODE_READ) && m->min.ep != NULL ) {
+		unsigned long int flagsep;
+		spin_lock_irqsave( &m->min.ep->lock, flagsep );
+		m->min.ep->cables[m->min.cableId] = m;
+		m->min.ep->readers += 1;
+		m->min.bufRdPtr       = 0;
+		m->min.bufWrPtr       = 0;
+		m->min.bufRemains     = 0;
+		spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
+
+		if ( !(m->min.ep->urbSubmitted)) {
+
+			/* urb->dev must be reinitialized on 2.4.x kernels */
+			m->min.ep->urb->dev = m->min.ep->usbdev;
+
+			if ( usb_submit_urb(m->min.ep->urb) ) {
+				printk(KERN_ERR "usbmidi: Cannot submit urb for MIDI-IN\n");
+			}
+			m->min.ep->urbSubmitted = 1;
+		}
+		m->open_mode |= FMODE_READ;
+		succeed = 1;
+	}
+
+	if ( (file->f_mode & FMODE_WRITE) && m->mout.ep != NULL ) {
+		m->mout.bufPtr        = 0;
+		m->mout.bufRemains    = 0;
+		m->mout.isInExclusive = 0;
+		m->mout.lastEvent     = 0;
+		m->open_mode |= FMODE_WRITE;
+		succeed = 1;
+	}
+
+	spin_unlock_irqrestore( &s->lock, flags );
+
+	s->count++;
+	up(&open_sem);
+
+	/** Changed to prevent extra increments to USE_COUNT. **/
+	if (!succeed) {
+		return -EBUSY;
+	}
+
+#if 0
+	printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor);
+#endif
+
+	/** Side-effect: module cannot be removed until USE_COUNT is 0. **/
+#ifndef MOD_INC_EACH_PROBE
+	MOD_INC_USE_COUNT;
+#endif
+
+	return 0; /** Success. **/
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ *  Basic contract: Close an opened file and deallocate anything we allocated.
+ *  Like open(), this can be missing. If open set file->private_data,
+ *  release() must clear it.
+ *
+ **/
+
+static int usb_midi_release(struct inode *inode, struct file *file)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	struct usb_midi_state *s = (struct usb_midi_state *)m->midi;
+
+#if 0
+	printk(KERN_INFO "usb-midi: Close.\n");
+#endif
+
+	down(&open_sem);
+
+	if ( m->open_mode & FMODE_WRITE ) {
+		m->open_mode &= ~FMODE_WRITE;
+		usb_unlink_urb( m->mout.ep->urb );
+	}
+
+	if ( m->open_mode & FMODE_READ ) {
+	        unsigned long int flagsep;
+	        spin_lock_irqsave( &m->min.ep->lock, flagsep );
+                m->min.ep->cables[m->min.cableId] = 0; // discard cable
+                m->min.ep->readers -= 1;
+		m->open_mode &= ~FMODE_READ;
+		if ( m->min.ep->readers == 0 &&
+                     m->min.ep->urbSubmitted ) {
+			m->min.ep->urbSubmitted = 0;
+			usb_unlink_urb(m->min.ep->urb);
+		}
+	        spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
+	}
+
+	s->count--;
+
+	up(&open_sem);
+	wake_up(&open_wait);
+
+	file->private_data = 0;
+	/** Sideeffect: Module cannot be removed until usecount is 0. */
+#ifndef MOD_INC_EACH_PROBE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return 0;
+}
+
+static struct file_operations usb_midi_fops = {
+	llseek:		usb_midi_llseek,
+	read:		usb_midi_read,
+	write:		usb_midi_write,
+	poll:		usb_midi_poll,
+	open:		usb_midi_open,
+	release:	usb_midi_release,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/** Returns filled midi_in_endpoint structure or null on failure.
+ *
+ * Parameters:
+ *	d        - a usb_device
+ *	endPoint - An usb endpoint in the range 0 to 15.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+
+static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, int endPoint )
+{
+	struct midi_in_endpoint *ep;
+	int bufSize;
+	int pipe;
+
+	endPoint &= 0x0f; /* Silently force endPoint to lie in range 0 to 15. */
+
+	pipe =  usb_rcvbulkpipe( d, endPoint );
+	bufSize = usb_maxpacket( d, pipe, usb_pipein(pipe) );
+	/* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */
+
+	ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL);
+	if ( !ep ) {
+		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint\n");
+		return NULL;
+	}
+	memset( ep, 0, sizeof(struct midi_in_endpoint) );
+//      this sets cables[] and readers to 0, too.
+//      for (i=0; i<16; i++) ep->cables[i] = 0; // discard cable
+//      ep->readers = 0;
+
+	ep->endpoint = endPoint;
+
+	ep->recvBuf = (unsigned char *)kmalloc(sizeof(unsigned char)*(bufSize), GFP_KERNEL);
+	if ( !ep->recvBuf ) {
+		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint buffer\n");
+		kfree(ep);
+		return NULL;
+	}
+
+	ep->urb = usb_alloc_urb(0); /* no ISO */
+	if ( !ep->urb ) {
+		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint urb\n");
+		kfree(ep->recvBuf);
+		kfree(ep);
+		return NULL;
+	}
+	FILL_BULK_URB( ep->urb, d, 
+		       usb_rcvbulkpipe(d, endPoint),
+		       (unsigned char *)ep->recvBuf, bufSize,
+		       (usb_complete_t)usb_bulk_read, ep );
+
+	/* ep->bufRdPtr     = 0; */
+	/* ep->bufWrPtr     = 0; */
+	/* ep->bufRemains   = 0; */
+	/* ep->urbSubmitted = 0; */
+	ep->recvBufSize  = bufSize;
+
+	init_waitqueue_head(&ep->wait);
+
+	return ep;
+}
+
+static int remove_midi_in_endpoint( struct midi_in_endpoint *min )
+{
+	usb_unlink_urb( min->urb );
+	usb_free_urb( min->urb );
+	kfree( min->recvBuf );
+	kfree( min );
+
+	return 0;
+}
+
+/** Returns filled midi_out_endpoint structure or null on failure.
+ *
+ * Parameters:
+ *	d        - a usb_device
+ *	endPoint - An usb endpoint in the range 0 to 15.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d, int endPoint )
+{
+	struct midi_out_endpoint *ep = NULL;
+	int pipe;
+	int bufSize;
+
+	endPoint &= 0x0f;
+	pipe =  usb_sndbulkpipe( d, endPoint );
+	bufSize = usb_maxpacket( d, pipe, usb_pipeout(pipe) );
+
+	ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL);
+	if ( !ep ) {
+		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint\n");
+		return NULL;
+	}
+	memset( ep, 0, sizeof(struct midi_out_endpoint) );
+
+	ep->endpoint = endPoint;
+	ep->buf = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
+	if ( !ep->buf ) {
+		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint buffer\n");
+		kfree(ep);
+		return NULL;
+	}
+
+	ep->urb = usb_alloc_urb(0); /* no ISO */
+	if ( !ep->urb ) {
+		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint urb\n");
+		kfree(ep->buf);
+		kfree(ep);
+		return NULL;
+	}
+
+	ep->bufSize       = bufSize;
+	/* ep->bufWrPtr      = 0; */
+
+	init_waitqueue_head(&ep->wait);
+
+	return ep;
+}
+
+
+static int remove_midi_out_endpoint( struct midi_out_endpoint *mout )
+{
+	usb_unlink_urb( mout->urb );
+	usb_free_urb( mout->urb );
+	kfree( mout->buf );
+	kfree( mout );
+
+	return 0;
+}
+
+
+/** Returns a filled usb_mididev structure, registered as a Linux MIDI device.
+ *
+ * Returns null if memory is not available or the device cannot be registered.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+static struct usb_mididev *allocMidiDev(
+	struct usb_midi_state *s,
+	struct midi_in_endpoint *min,
+	struct midi_out_endpoint *mout,
+	int inCableId,
+	int outCableId )
+{
+	struct usb_mididev *m;
+
+	m = (struct usb_mididev *)kmalloc(sizeof(struct usb_mididev), GFP_KERNEL);
+	if (!m) {
+		printk(KERN_ERR "usbmidi: no memory for midi device\n");
+		return NULL;
+	}
+
+	memset(m, 0, sizeof(struct usb_mididev));
+
+	if ((m->dev_midi = register_sound_midi(&usb_midi_fops, -1)) < 0) {
+		printk(KERN_ERR "usbmidi: cannot register midi device\n");
+		kfree(m);
+		return NULL;
+	}
+
+	m->midi               = s;
+	/* m->open_mode          = 0; */
+
+	if ( min ) {
+		m->min.ep             = min;
+		m->min.ep->usbdev     = s->usbdev;
+		m->min.cableId        = inCableId;
+	}
+	/* m->min.bufPtr         = 0; */
+	/* m->min.bufRemains     = 0; */
+
+	if ( mout ) {
+		m->mout.ep            = mout;
+		m->mout.ep->usbdev    = s->usbdev;
+		m->mout.cableId       = outCableId;
+	}
+	/* m->mout.bufPtr        = 0; */
+	/* m->mout.bufRemains    = 0; */
+	/* m->mout.isInExclusive = 0; */
+	/* m->mout.lastEvent     = 0; */
+
+	m->singlebyte         = singlebyte;
+
+	return m;
+}
+
+
+static void release_midi_device( struct usb_midi_state *s )
+{
+	struct usb_mididev *m;
+	struct midi_in_endpoint *min;
+	struct midi_out_endpoint *mout;
+
+	if ( s->count > 0 ) {
+		up(&open_sem);
+		return;
+	}
+	up( &open_sem );
+	wake_up( &open_wait );
+
+	while(!list_empty(&s->inEndpointList)) {
+		min = list_entry(s->inEndpointList.next, struct midi_in_endpoint, list);
+		list_del(&min->list);
+		remove_midi_in_endpoint(min);
+	}
+
+	while(!list_empty(&s->outEndpointList)) {
+		mout = list_entry(s->outEndpointList.next, struct midi_out_endpoint, list);
+		list_del(&mout->list);
+		remove_midi_out_endpoint(mout);
+	}
+
+	while(!list_empty(&s->midiDevList)) {
+		m = list_entry(s->midiDevList.next, struct usb_mididev, list);
+		list_del(&m->list);
+		kfree(m);
+	}
+
+	kfree(s);
+
+	return;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/** Utility routine to find a descriptor in a dump of many descriptors.
+ * Returns start of descriptor or NULL if not found. 
+ * descStart pointer to list of interfaces.
+ * descLength length (in bytes) of dump
+ * after (ignored if NULL) this routine returns only descriptors after "after"
+ * dtype (mandatory) The descriptor type.
+ * iface (ignored if -1) returns descriptor at/following given interface
+ * altSetting (ignored if -1) returns descriptor at/following given altSetting
+ *
+ *
+ *  Called by parseDescriptor(), find_csinterface_descriptor();
+ *
+ */
+static void *find_descriptor( void *descStart, unsigned int descLength, void *after, unsigned char dtype, int iface, int altSetting )
+{
+	unsigned char *p, *end, *next;
+	int interfaceNumber = -1, altSet = -1;
+
+	p = descStart;
+	end = p + descLength;
+	for( ; p < end; ) {
+		if ( p[0] < 2 )
+			return NULL;
+		next = p + p[0];
+		if ( next > end )
+			return NULL;
+		if ( p[1] == USB_DT_INTERFACE ) {
+			if ( p[0] < USB_DT_INTERFACE_SIZE )
+				return NULL;
+			interfaceNumber = p[2];
+			altSet = p[3];
+		}
+		if ( p[1] == dtype &&
+		     ( !after || ( p > (unsigned char *)after) ) &&
+		     ( ( iface == -1) || (iface == interfaceNumber) ) &&
+		     ( (altSetting == -1) || (altSetting == altSet) )) {
+			return p;
+		}
+		p = next;
+	}
+	return NULL;
+}
+
+/** Utility to find a class-specfic interface descriptor.
+ *  dsubtype is a descriptor subtype
+ *  Called by parseDescriptor();
+ **/
+static void *find_csinterface_descriptor(void *descStart, unsigned int descLength, void *after, u8 dsubtype, int iface, int altSetting)
+{
+	unsigned char *p;
+  
+	p = find_descriptor( descStart, descLength, after, USB_DT_CS_INTERFACE, iface, altSetting );
+	while ( p ) {
+		if ( p[0] >= 3 && p[2] == dsubtype )
+			return p;
+		p = find_descriptor( descStart, descLength, p, USB_DT_CS_INTERFACE, 
+				     iface, altSetting );
+	}
+	return NULL;
+}
+
+
+/** The magic of making a new usb_midi_device from config happens here.
+ *
+ * The caller is responsible for free-ing this return value (if not NULL).
+ *
+ **/
+static struct usb_midi_device *parse_descriptor( struct usb_device *d, unsigned char *buffer, int bufSize, unsigned int ifnum , unsigned int altSetting, int quirks)
+{
+	struct usb_midi_device *u;
+	unsigned char *p1;
+	unsigned char *p2;
+	unsigned char *next;
+	int iep, oep;
+	int length;
+	unsigned long longBits;
+	int pins, nbytes, offset, shift, jack;
+#ifdef HAVE_JACK_STRINGS
+	/** Jacks can have associated names.  **/
+	unsigned char jack2string[256];
+#endif
+
+	u = 0;
+	/* find audiocontrol interface */
+	p1 = find_csinterface_descriptor( buffer, bufSize, NULL,
+					  MS_HEADER, ifnum, altSetting);
+
+	if ( !p1 ) {
+		goto error_end;
+	}
+
+	if ( p1[0] < MS_HEADER_LENGTH ) {
+		goto error_end;
+	}
+
+	/* Assume success. Since the device corresponds to USB-MIDI spec, we assume
+	   that the rest of the USB 2.0 spec is obeyed. */
+
+	u = (struct usb_midi_device *)kmalloc( sizeof(struct usb_midi_device), GFP_KERNEL );
+	if ( !u ) {
+		return NULL;
+	}
+	u->deviceName = 0;
+	u->idVendor = d->descriptor.idVendor;
+	u->idProduct = d->descriptor.idProduct;
+	u->interface = ifnum;
+	u->altSetting = altSetting;
+	u->in[0].endpoint = -1;
+	u->in[0].cableId = -1;
+	u->out[0].endpoint = -1;
+	u->out[0].cableId = -1;
+
+
+	printk(KERN_INFO "usb-midi: Found MIDIStreaming device corresponding to Release %d.%02d of spec.\n",
+	       (p1[4] >> 4) * 10 + (p1[4] & 0x0f ),
+	       (p1[3] >> 4) * 10 + (p1[3] & 0x0f )
+		);
+
+	length = p1[5] | (p1[6] << 8);
+
+#ifdef HAVE_JACK_STRINGS
+	memset(jack2string, 0, sizeof(unsigned char) * 256);
+#endif
+
+	length -= p1[0];
+	for (p2 = p1 + p1[0]; length > 0; p2 = next) {
+		next = p2 + p2[0];
+		length -= p2[0];
+
+		if (p2[0] < 2 ) break;
+		if (p2[1] != USB_DT_CS_INTERFACE) break;
+		if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) {
+			jack = p2[4];
+#ifdef HAVE_JACK_STRINGS
+			jack2string[jack] = p2[5];
+#endif
+			printk(KERN_INFO "usb-midi: Found IN Jack 0x%02x %s\n",
+			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" );
+		} else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) {
+			pins = p2[5];
+			if ( p2[0] < (6 + 2 * pins) ) continue;
+			jack = p2[4];
+#ifdef HAVE_JACK_STRINGS
+			jack2string[jack] = p2[5 + 2 * pins];
+#endif
+			printk(KERN_INFO "usb-midi: Found OUT Jack 0x%02x %s, %d pins\n",
+			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins );
+		} else if ( p2[2] == ELEMENT_DESCRIPTOR  && p2[0]  >= 10) {
+			pins = p2[4];
+			if ( p2[0] < (9 + 2 * pins ) ) continue;
+			nbytes = p2[8 + 2 * pins ];
+			if ( p2[0] < (10 + 2 * pins + nbytes) ) continue;
+			longBits = 0L;
+			for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) {
+				longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift;
+			}
+			jack = p2[3];
+#ifdef HAVE_JACK_STRINGS
+			jack2string[jack] = p2[9 + 2 * pins + nbytes];
+#endif
+			printk(KERN_INFO "usb-midi: Found ELEMENT 0x%02x, %d/%d pins in/out, bits: 0x%016lx\n",
+			       jack, pins, (int)(p2[5 + 2 * pins]), (long)longBits );
+		} else {
+		}
+	}
+
+	iep=0;
+	oep=0;
+
+	if (quirks==0) {
+		/* MIDISTREAM */
+		p2 = 0;
+		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
+					  ifnum, altSetting ); p1; p1 = next ) {
+			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
+					       ifnum, altSetting ); 
+			p2 = find_descriptor(buffer, bufSize, p1, USB_DT_CS_ENDPOINT,
+					     ifnum, altSetting ); 
+
+			if ( p2 && next && ( p2 > next ) )
+				p2 = 0;
+
+			if ( p1[0] < 9 || !p2 || p2[0] < 4 ) continue;
+
+			if ( (p1[2] & 0x80) == 0x80 ) {
+				if ( iep < 15 ) {
+					pins = p2[3]; /* not pins -- actually "cables" */
+					if ( pins > 16 )
+						pins = 16;
+					u->in[iep].endpoint = p1[2];
+					u->in[iep].cableId = ( 1 << pins ) - 1;
+					if ( u->in[iep].cableId ) iep ++;
+					if ( iep < 15 ) {
+						u->in[iep].endpoint = -1;
+						u->in[iep].cableId = -1;
+					}
+				}
+			} else {
+				if ( oep < 15 ) {
+					pins = p2[3]; /* not pins -- actually "cables" */
+					if ( pins > 16 )
+						pins = 16;
+					u->out[oep].endpoint = p1[2];
+					u->out[oep].cableId = ( 1 << pins ) - 1;
+					if ( u->out[oep].cableId ) oep ++;
+					if ( oep < 15 ) {
+						u->out[oep].endpoint = -1;
+						u->out[oep].cableId = -1;
+					}
+				}
+			}
+	
+		}
+	} else if (quirks==1) {
+		/* YAMAHA quirks */
+		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
+					  ifnum, altSetting ); p1; p1 = next ) {
+			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
+					       ifnum, altSetting ); 
+	
+			if ( p1[0] < 7 ) continue;
+
+			if ( (p1[2] & 0x80) == 0x80 ) {
+				if ( iep < 15 ) {
+					pins = iep+1;
+					if ( pins > 16 )
+						pins = 16;
+					u->in[iep].endpoint = p1[2];
+					u->in[iep].cableId = ( 1 << pins ) - 1;
+					if ( u->in[iep].cableId ) iep ++;
+					if ( iep < 15 ) {
+						u->in[iep].endpoint = -1;
+						u->in[iep].cableId = -1;
+					}
+				}
+			} else {
+				if ( oep < 15 ) {
+					pins = oep+1;
+					if ( pins > 16 )
+						pins = 16;
+					u->out[oep].endpoint = p1[2];
+					u->out[oep].cableId = ( 1 << pins ) - 1;
+					if ( u->out[oep].cableId ) oep ++;
+					if ( oep < 15 ) {
+						u->out[oep].endpoint = -1;
+						u->out[oep].cableId = -1;
+					}
+				}
+			}
+	
+		}
+	}
+
+	if ( !iep && ! oep ) {
+		goto error_end;
+	}
+
+	return u;
+
+error_end:
+	if ( u ) kfree(u);
+	return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** Returns number between 0 and 16.
+ *
+ **/
+static int on_bits( unsigned short v )
+{
+	int i;
+	int ret=0;
+
+	for ( i=0 ; i<16 ; i++ ) {
+		if ( v & (1<<i) ) ret++;
+	}
+
+	return ret;
+}
+
+
+/** USB-device will be interrogated for altSetting.
+ *
+ * Returns negative on error.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+
+static int get_alt_setting( struct usb_device *d, int ifnum )
+{
+	int alts, alt=0;
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *ep;
+	int epin, epout;
+	int i;
+
+	alts = d->actconfig->interface[ifnum].num_altsetting;
+
+	for ( alt=0 ; alt<alts ; alt++ ) {
+		interface = &d->actconfig->interface[ifnum].altsetting[alt];
+		epin = -1;
+		epout = -1;
+
+		for ( i=0 ; i<interface->bNumEndpoints ; i++ ) {
+			ep = &interface->endpoint[i];
+			if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ) {
+				continue;
+			}
+			if ( (ep->bEndpointAddress & USB_DIR_IN) && epin < 0 ) {
+				epin = i;
+			} else if ( epout < 0 ) {
+				epout = i;
+			}
+			if ( epin >= 0 && epout >= 0 ) {
+				return alt;
+			}
+		}
+	}
+
+	return -ENODEV;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/** Returns 0 if successful in allocating and registering internal structures.
+ * Returns negative on failure.
+ * Calls allocMidiDev which additionally registers /dev/midiXX devices.
+ * Writes messages on success to indicate which /dev/midiXX is which physical
+ * endpoint.
+ *
+ **/
+static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s, struct usb_midi_device *u )
+{
+	struct usb_mididev **mdevs=NULL;
+	struct midi_in_endpoint *mins[15], *min;
+	struct midi_out_endpoint *mouts[15], *mout;
+	int inDevs=0, outDevs=0;
+	int inEndpoints=0, outEndpoints=0;
+	int inEndpoint, outEndpoint;
+	int inCableId, outCableId;
+	int i;
+	int devices = 0;
+	int alt = 0;
+
+	/* Obtain altSetting or die.. */
+	alt = u->altSetting;
+	if ( alt < 0 ) {
+		alt = get_alt_setting( d, u->interface );
+	}
+	if ( alt < 0 ) { return -ENXIO; }
+
+	/* Configure interface */
+	if ( usb_set_interface( d, u->interface, alt ) < 0 ) {
+		return -ENXIO;
+	}
+
+	for ( i = 0 ; i < 15 ; i++ ) {
+		mins[i] = NULL;
+		mouts[i] = NULL;
+	}
+
+	/* Begin Allocation */
+	while( inEndpoints < 15
+	       && inDevs < maxdevices
+	       && u->in[inEndpoints].cableId >= 0 ) {
+		inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId);
+		mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint );
+		if ( mins[inEndpoints] == NULL ) { goto error_end; }
+		inEndpoints++;
+	}
+
+	while( outEndpoints < 15
+	       && outDevs < maxdevices
+	       && u->out[outEndpoints].cableId >= 0 ) {
+		outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId);
+		mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint );
+		if ( mouts[outEndpoints] == NULL ) { goto error_end; }
+		outEndpoints++;
+	}
+
+	devices = inDevs > outDevs ? inDevs : outDevs;
+	devices = maxdevices > devices ? devices : maxdevices;
+
+	/* obtain space for device name (iProduct) if not known. */
+	if ( ! u->deviceName ) {
+		mdevs = (struct usb_mididev **)
+			kmalloc(sizeof(struct usb_mididevs *)*devices
+				+ sizeof(char) * 256, GFP_KERNEL);
+	} else {
+		mdevs = (struct usb_mididev **)
+			kmalloc(sizeof(struct usb_mididevs *)*devices, GFP_KERNEL);
+	}
+
+	if ( !mdevs ) {
+		/* devices = 0; */
+		/* mdevs = NULL; */
+		goto error_end;
+	}
+	for ( i=0 ; i<devices ; i++ ) {
+		mdevs[i] = NULL;
+	}
+
+	/* obtain device name (iProduct) if not known. */
+	if ( ! u->deviceName ) {
+		u->deviceName = (char *) (mdevs + devices);
+		if ( ! d->have_langid && d->descriptor.iProduct) {
+			alt = usb_get_string(d, 0, 0, u->deviceName, 250);
+			if (alt < 0) {
+				printk(KERN_INFO "error getting string descriptor 0 (error=%d)\n", alt);
+			} else if (u->deviceName[0] < 4) {
+				printk(KERN_INFO "string descriptor 0 too short (length = %d)\n", alt);
+			} else {
+				printk(KERN_INFO "string descriptor 0 found (length = %d)\n", alt);
+				for(; alt >= 4; alt -= 2) {
+					i = u->deviceName[alt-2] | (u->deviceName[alt-1]<< 8);
+					printk(KERN_INFO "usb-midi: langid(%d) 0x%04x\n",
+					       (alt-4) >> 1, i);
+					if ( ( ( i ^ ulangid ) & 0xff ) == 0 ) {
+						d->have_langid = 1;
+						d->string_langid = i;
+						printk(KERN_INFO "usb-midi: langid(match) 0x%04x\n", i);
+						if ( i == ulangid )
+							break;
+					}
+				}
+			}
+		}
+		u->deviceName[0] = (char) 0;
+		if (d->descriptor.iProduct) {
+			printk(KERN_INFO "usb-midi: fetchString(%d)\n", d->descriptor.iProduct);
+			alt = usb_string(d, d->descriptor.iProduct, u->deviceName, 255);
+			if( alt < 0 ) {
+				u->deviceName[0] = (char) 0;
+			}
+			printk(KERN_INFO "usb-midi: fetchString = %d\n", alt);
+		} 
+		/* Failsafe */
+		if ( !u->deviceName[0] ) {
+			if ( d->descriptor.idVendor == USB_VENDOR_ID_ROLAND ) {
+				strcpy(u->deviceName, "Unknown Roland");
+			} else if ( d->descriptor.idVendor == USB_VENDOR_ID_STEINBERG  ) {
+				strcpy(u->deviceName, "Unknown Steinberg");
+			} else if ( d->descriptor.idVendor == USB_VENDOR_ID_YAMAHA ) {
+				strcpy(u->deviceName, "Unknown Yamaha");
+			} else {
+				strcpy(u->deviceName, "Unknown");
+			}
+		}
+	}
+
+	inEndpoint  = 0; inCableId  = -1;
+	outEndpoint = 0; outCableId = -1;
+
+	for ( i=0 ; i<devices ; i++ ) {
+		for ( inCableId ++ ;
+		      inEndpoint <15
+			      && mins[inEndpoint] 
+			      && !(u->in[inEndpoint].cableId & (1<<inCableId)) ;
+		      inCableId++ ) {
+			if ( inCableId >= 16 ) {
+				inEndpoint  ++;
+				inCableId  = 0;
+			}
+		}
+		min  = mins[inEndpoint];
+		for ( outCableId ++ ;
+		      outEndpoint <15
+			      && mouts[outEndpoint] 
+			      && !(u->out[outEndpoint].cableId & (1<<outCableId)) ;
+		      outCableId++ ) {
+			if ( outCableId >= 16 ) {
+				outEndpoint  ++;
+				outCableId  = 0;
+			}
+		}
+		mout = mouts[outEndpoint];
+
+		mdevs[i] = allocMidiDev( s, min, mout, inCableId, outCableId );
+		if ( mdevs[i] == NULL ) { goto error_end; }
+
+	}
+
+	/* Success! */
+	for ( i=0 ; i<devices ; i++ ) {
+		list_add_tail( &mdevs[i]->list, &s->midiDevList );
+	}
+	for ( i=0 ; i<inEndpoints ; i++ ) {
+		list_add_tail( &mins[i]->list, &s->inEndpointList );
+	}
+	for ( i=0 ; i<outEndpoints ; i++ ) {
+		list_add_tail( &mouts[i]->list, &s->outEndpointList );
+	}
+
+	printk(KERN_INFO "usbmidi: found [ %s ] (0x%04x:0x%04x), attached:\n", u->deviceName, u->idVendor, u->idProduct );
+	for ( i=0 ; i<devices ; i++ ) {
+		int dm = (mdevs[i]->dev_midi-2)>>4;
+		if ( mdevs[i]->mout.ep != NULL && mdevs[i]->min.ep != NULL ) {
+			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%2d) out (ep:%02x cid:%2d bufsiz:%2d)\n", 
+			       dm,
+			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize,
+			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
+		} else if ( mdevs[i]->min.ep != NULL ) {
+			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%02d)\n", 
+			       dm,
+			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize);
+		} else if ( mdevs[i]->mout.ep != NULL ) {
+			printk(KERN_INFO "usbmidi: /dev/midi%02d: out (ep:%02x cid:%2d bufsiz:%02d)\n", 
+			       dm,
+			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
+		}
+	}
+
+	kfree(mdevs);
+	return 0;
+
+ error_end:
+	if ( mdevs != NULL && devices > 0 ) {
+		for ( i=0 ; i<devices ; i++ ) {
+			if ( mdevs[i] != NULL ) {
+				unregister_sound_midi( mdevs[i]->dev_midi );
+				kfree(mdevs[i]);
+			}
+		}
+		kfree(mdevs);
+	}
+
+	for ( i=0 ; i<15 ; i++ ) {
+		if ( mins[i] != NULL ) {
+			remove_midi_in_endpoint( mins[i] );
+		}
+		if ( mouts[i] != NULL ) {
+			remove_midi_out_endpoint( mouts[i] );
+		}
+	}
+
+	return -ENOMEM;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** Attempt to scan YAMAHA's device descriptor and detect correct values of
+ *  them.
+ *  Return 0 on succes, negative on failure.
+ *  Called by usb_midi_probe();
+ **/
+
+static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+{
+	struct usb_config_descriptor    *c = d->actconfig;
+	struct usb_interface_descriptor *interface;
+	struct usb_midi_device *u;
+	unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
+	int bufSize;
+	int i;
+	int alts=-1;
+	int ret;
+
+	if (d->descriptor.idVendor != USB_VENDOR_ID_YAMAHA) {
+		return -EINVAL;
+	}
+
+	for ( i=0 ; i < c->interface[ifnum].num_altsetting; i++ ) {
+		interface = c->interface[ifnum].altsetting + i;
+
+		if ( interface->bInterfaceClass != 255 ||
+		     interface->bInterfaceSubClass != 0 )
+			continue;
+		alts = i;
+	}
+	if ( alts == -1 ) {
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n",
+	       d->descriptor.idVendor, d->descriptor.idProduct, ifnum);
+
+	for ( i=0 ; i < d->descriptor.bNumConfigurations ; i++ ) {
+		if ( d->config+i == c ) goto configfound;
+	}
+
+	printk(KERN_INFO "usb-midi: Config not found.\n");
+
+	return -EINVAL;
+
+ configfound:
+
+	/* this may not be necessary. */
+	if ( usb_set_configuration( d, c->bConfigurationValue ) < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not set config.\n");
+		return -EINVAL;
+	}
+
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
+		return -EINVAL;
+	}
+	if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
+		printk(KERN_INFO "usb-midi: config not as expected.\n");
+		return -EINVAL;
+	}
+	bufSize = buf[2] | buf[3]<<8;
+	buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
+	if ( !buffer ) {
+		printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
+		return -EINVAL;
+	}
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
+		kfree(buffer);
+		return -EINVAL;
+	}
+
+	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1);
+	kfree(buffer);
+	if ( u == NULL ) {
+		return -EINVAL;
+	}
+
+	ret = alloc_usb_midi_device( d, s, u );
+
+	kfree(u);
+
+	return ret;
+}
+
+
+/** Scan table of known devices which are only partially compliant with 
+ * the MIDIStreaming specification.
+ * Called by usb_midi_probe();
+ *
+ **/
+
+static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s )
+{
+	struct usb_midi_device *u;
+	int i;
+	int ret = -ENXIO;
+
+	for ( i=0; i<VENDOR_SPECIFIC_USB_MIDI_DEVICES ; i++ ) {
+		u=&(usb_midi_devices[i]);
+    
+		if ( d->descriptor.idVendor != u->idVendor ||
+		     d->descriptor.idProduct != u->idProduct ||
+		     ifnum != u->interface )
+			continue;
+
+		ret = alloc_usb_midi_device( d, s, u );
+		break;
+	}
+
+	return ret;
+}
+
+
+/** Attempt to match any config of an interface to a MIDISTREAMING interface.
+ *  Returns 0 on success, negative on failure.
+ * Called by usb_midi_probe();
+ **/
+static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+{
+	struct usb_config_descriptor    *c = d->actconfig;
+	struct usb_interface_descriptor *interface;
+	struct usb_midi_device *u;
+	unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
+	int bufSize;
+	int i;
+	int alts=-1;
+	int ret;
+
+	for ( i=0 ; i < c->interface[ifnum].num_altsetting; i++ ) {
+		interface = c->interface[ifnum].altsetting + i;
+
+		if ( interface->bInterfaceClass != USB_CLASS_AUDIO ||
+		     interface->bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING )
+			continue;
+		alts = i;
+	}
+	if ( alts == -1 ) {
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d\n",
+	       d->descriptor.idVendor, d->descriptor.idProduct, ifnum);
+
+	for ( i=0 ; i < d->descriptor.bNumConfigurations ; i++ ) {
+		if ( d->config+i == c ) goto configfound;
+	}
+
+	printk(KERN_INFO "usb-midi: Config not found.\n");
+
+	return -EINVAL;
+
+ configfound:
+
+	/* this may not be necessary. */
+	if ( usb_set_configuration( d, c->bConfigurationValue ) < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not set config.\n");
+		return -EINVAL;
+	}
+
+	/* From USB Spec v2.0, Section 9.5.
+	   If the class or vendor specific descriptors use the same format
+	   as standard descriptors (e.g., start with a length byte and
+	   followed by a type byte), they must be returned interleaved with
+	   standard descriptors in the configuration information returned by
+	   a GetDescriptor(Configuration) request. In this case, the class
+	   or vendor-specific descriptors must follow a related standard
+	   descriptor they modify or extend.
+	*/
+
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
+		return -EINVAL;
+	}
+	if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
+		printk(KERN_INFO "usb-midi: config not as expected.\n");
+		return -EINVAL;
+	}
+	bufSize = buf[2] | buf[3]<<8;
+	buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
+	if ( !buffer ) {
+		printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
+		return -EINVAL;
+	}
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
+		kfree(buffer);
+		return -EINVAL;
+	}
+
+	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0);
+	kfree(buffer);
+	if ( u == NULL ) {
+		return -EINVAL;
+	}
+
+	ret = alloc_usb_midi_device( d, s, u );
+
+	kfree(u);
+
+	return ret;
+}
+
+
+/** When user has requested a specific device, match it exactly.
+ *
+ * Uses uvendor, uproduct, uinterface, ualt, umin, umout and ucable.
+ * Called by usb_midi_probe();
+ *
+ **/
+static int detect_by_hand(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+{
+	struct usb_midi_device u;
+
+	if ( d->descriptor.idVendor != uvendor ||
+	     d->descriptor.idProduct != uproduct ||
+	     ifnum != uinterface ) {
+		return -EINVAL;
+	}
+
+	if ( ualt < 0 ) { ualt = -1; }
+
+	if ( umin   < 0 || umin   > 15 ) { umin   = 0x01 | USB_DIR_IN; }
+	if ( umout  < 0 || umout  > 15 ) { umout  = 0x01; }
+	if ( ucable < 0 || ucable > 15 ) { ucable = 0; }
+
+	u.deviceName = 0; /* A flag for alloc_usb_midi_device to get device name
+			     from device. */
+	u.idVendor   = uvendor;
+	u.idProduct  = uproduct;
+	u.interface  = uinterface;
+	u.altSetting = ualt;
+
+	u.in[0].endpoint    = umin;
+	u.in[0].cableId     = (1<<ucable);
+
+	u.out[0].endpoint   = umout;
+	u.out[0].cableId    = (1<<ucable);
+
+	return alloc_usb_midi_device( d, s, &u );
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+
+static void *usb_midi_probe(struct usb_device *dev, unsigned int ifnum,
+			    const struct usb_device_id *id)
+{
+	struct usb_midi_state *s;
+
+	s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL);
+	if ( !s ) { return NULL; }
+
+	memset( s, 0, sizeof(struct usb_midi_state) );
+	INIT_LIST_HEAD(&s->midiDevList);
+	INIT_LIST_HEAD(&s->inEndpointList);
+	INIT_LIST_HEAD(&s->outEndpointList);
+	s->usbdev = dev;
+	s->count  = 0;
+	spin_lock_init(&s->lock);
+
+	if (
+		detect_by_hand( dev, ifnum, s ) &&
+		detect_midi_subclass( dev, ifnum, s ) &&
+		detect_vendor_specific_device( dev, ifnum, s ) &&
+		detect_yamaha_device( dev, ifnum, s) ) {
+		kfree(s);
+		return NULL;
+	}
+
+	down(&open_sem);
+	list_add_tail(&s->mididev, &mididevs);
+	up(&open_sem);
+
+#ifdef MOD_INC_EACH_PROBE
+	MOD_INC_USE_COUNT;
+#endif
+
+	return s;
+}
+
+
+static void usb_midi_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_midi_state *s = (struct usb_midi_state *)ptr;
+	struct list_head      *list;
+	struct usb_mididev    *m;
+
+	if ( s == (struct usb_midi_state *)-1 ) {
+		return;
+	}
+	if ( !s->usbdev ) {
+		return;
+	}
+	down(&open_sem);
+	list_del(&s->mididev);
+	INIT_LIST_HEAD(&s->mididev);
+	s->usbdev = NULL;
+
+	for ( list = s->midiDevList.next; list != &s->midiDevList; list = list->next ) {
+		m = list_entry(list, struct usb_mididev, list);
+		wake_up(&(m->min.ep->wait));
+		wake_up(&(m->mout.ep->wait));
+		if ( m->dev_midi >= 0 ) {
+			unregister_sound_midi(m->dev_midi);
+		}
+		m->dev_midi = -1;
+	}
+	release_midi_device(s);
+	wake_up(&open_wait);
+#ifdef MOD_INC_EACH_PROBE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return;
+}
+
+
+
+static struct usb_driver usb_midi_driver = {
+	name: "midi",
+	probe: usb_midi_probe,
+	disconnect: usb_midi_disconnect,
+	id_table:	NULL, 			/* check all devices */
+	driver_list: LIST_HEAD_INIT(usb_midi_driver.driver_list)
+};
+
+/* ------------------------------------------------------------------------- */
+
+int __init usb_midi_init(void)
+{
+	if ( usb_register(&usb_midi_driver) < 0 )
+		return -1;
+
+	return 0;
+
+}
+
+void __exit usb_midi_exit(void)
+{
+	usb_deregister(&usb_midi_driver);
+}
+
+module_init(usb_midi_init) ;
+module_exit(usb_midi_exit) ;
+
+#ifdef HAVE_ALSA_SUPPORT
+#define SNDRV_MAIN_OBJECT_FILE
+#include "../../include/driver.h"
+#include "../../include/control.h"
+#include "../../include/info.h"
+#include "../../include/cs46xx.h"
+
+/* ------------------------------------------------------------------------- */
+
+static int snd_usbmidi_input_close(snd_rawmidi_substream_t * substream)
+{
+	return 0;
+}
+
+static int snd_usbmidi_input_open(snd_rawmidi_substream_t * substream )
+{
+	return 0;
+}
+
+static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+static int snd_usbmidi_output_close(snd_rawmidi_substream_t * substream)
+{
+	return 0;
+}
+
+static int snd_usbmidi_output_open(snd_rawmidi_substream_t * substream)
+{
+	return 0;
+}
+
+static void snd_usb_midi_output_trigger(snd_rawmidi_substream_t * substream,
+					int up)
+{
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static snd_rawmidi_ops_t snd_usbmidi_output =
+{
+        open:           snd_usbmidi_output_open,
+        close:          snd_usbmidi_output_close,
+        trigger:        snd_usbmidi_output_trigger,
+};
+static snd_rawmidi_ops_t snd_usbmidi_input =
+{
+        open:           snd_usbmidi_input_open,
+        close:          snd_usbmidi_input_close,
+        trigger:        snd_usbmidi_input_trigger,
+};
+
+int snd_usbmidi_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi)
+{
+	snd_rawmidi_t *rmidi;
+	int err;
+
+	if (rrawmidi)
+		*rrawmidi = NULL;
+	if ((err = snd_rawmidi_new(chip->card, "USB-MIDI", device, 1, 1, &rmidi)) < 0)
+		return err;
+	strcpy(rmidi->name, "USB-MIDI");
+
+	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output );
+	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input );
+
+	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
+
+	rmidi->private_data = chip;
+	chip->rmidi = rmidi;
+	if (rrawmidi)
+		*rrawmidi = NULL;
+
+	return 0;
+}
+
+int snd_usbmidi_create( snd_card_t * card,
+			struct pci_dev * pci,
+			usbmidi_t ** rchip )
+{
+	usbmidi_t *chip;
+	int err, idx;
+	snd_region_t *region;
+	static snd_device_opt_t ops = {
+		dev_free: snd_usbmidi_dev_free,
+	};
+
+	*rchip = NULL;
+	chip = snd_magic_kcalloc( usbmidi_t, 0, GFP_KERNEL );
+	if ( chip == NULL )
+		return -ENOMEM;
+}
+
+EXPORT_SYMBOL(snd_usbmidi_create);
+EXPORT_SYMBOL(snd_usbmidi_midi);
+#endif /* HAVE_ALSA_SUPPORT */
+
diff -urN linux-2.4.20-pre1/drivers/usb/usb-midi.h linux-2.4.20-pre2/drivers/usb/usb-midi.h
--- linux-2.4.20-pre1/drivers/usb/usb-midi.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/drivers/usb/usb-midi.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,143 @@
+/*
+  usb-midi.h  --  USB-MIDI driver
+
+  Copyright (C) 2001
+      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* ------------------------------------------------------------------------- */
+
+#ifndef _USB_MIDI_H_
+#define _USB_MIDI_H_
+
+#ifndef USB_SUBCLASS_MIDISTREAMING
+#define USB_SUBCLASS_MIDISTREAMING	3
+#endif
+
+#define USB_DT_CS_DEVICE		0x21
+#define USB_DT_CS_CONFIG		0x22
+#define USB_DT_CS_STRING		0x23
+#define USB_DT_CS_INTERFACE		0x24
+#define USB_DT_CS_ENDPOINT		0x25
+
+/* ------------------------------------------------------------------------- */
+/* Roland MIDI Devices */
+
+#define USB_VENDOR_ID_ROLAND		0x0582
+#define USBMIDI_ROLAND_UA100G		0x0000
+#define USBMIDI_ROLAND_MPU64		0x0002
+#define USBMIDI_ROLAND_SC8850		0x0003
+#define USBMIDI_ROLAND_UM2		0x0005
+#define USBMIDI_ROLAND_UM1		0x0009
+#define USBMIDI_ROLAND_PC300		0x0008
+
+/* YAMAHA MIDI Devices */
+#define USB_VENDOR_ID_YAMAHA		0x0499
+#define USBMIDI_YAMAHA_MU1000		0x1001
+
+/* Steinberg MIDI Devices */
+#define USB_VENDOR_ID_STEINBERG		0x0763
+#define USBMIDI_STEINBERG_USB2MIDI	0x1001
+
+/* ------------------------------------------------------------------------- */
+/* Supported devices */
+
+struct usb_midi_endpoint {
+	int  endpoint;
+	int  cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */
+};
+
+struct usb_midi_device {
+	char  *deviceName;
+
+	int    idVendor;
+	int    idProduct;
+	int    interface;
+	int    altSetting; /* -1: auto detect */
+
+	struct usb_midi_endpoint in[15];
+	struct usb_midi_endpoint out[15];
+};
+
+static struct usb_midi_device usb_midi_devices[] = {
+  { /* Roland UM-1 */
+    "Roland UM-1",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1,
+    { { 0x81, 1 }, {-1, -1} },
+    { { 0x01, 1,}, {-1, -1} },
+  },
+
+  { /* Roland UM-2 */
+    "Roland UM-2" ,
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1,
+    { { 0x81, 3 }, {-1, -1} },
+    { { 0x01, 3,}, {-1, -1} },
+  },
+
+/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
+  { /* Roland UA-100 */
+    "Roland UA-100",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1,
+    { { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/
+    { { 0x02, 7 }, {-1, -1} },
+  },
+
+/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
+  { /* Roland SC8850 */
+    "Roland SC8850",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1,
+    { { 0x81, 15 }, {-1, -1} }, /** cables 0,1,2, and 3 **/
+    { { 0x01, 15 }, {-1, -1} },
+  },
+
+  { /* YAMAHA MU1000 */
+    "YAMAHA MU1000",
+    USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1, 
+    { { 0x81, 1 }, {-1, -1} },
+    { { 0x01, 15 }, {-1, -1} },
+  },
+  { /* Roland PC-300 */
+    "Roland PC-300",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1, 
+    { { 0x81, 1 }, {-1, -1} },
+    { { 0x01, 1 }, {-1, -1} },
+  }
+};
+
+#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device))
+
+/* for Hot-Plugging */
+
+static struct usb_device_id usb_midi_ids [] = {
+	{ match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
+	  bInterfaceClass: USB_CLASS_AUDIO, bInterfaceSubClass: USB_SUBCLASS_MIDISTREAMING},
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1    ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2    ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) },
+	{ USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) },
+/*	{ USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_midi_ids);
+
+/* ------------------------------------------------------------------------- */
+#endif /* _USB_MIDI_H_ */
+
+
diff -urN linux-2.4.20-pre1/drivers/usb/usb-ohci.c linux-2.4.20-pre2/drivers/usb/usb-ohci.c
--- linux-2.4.20-pre1/drivers/usb/usb-ohci.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/usb-ohci.c	Mon Aug 12 16:34:17 2002
@@ -178,7 +178,7 @@
 	kfree (urb_priv);
 }
  
-static void urb_rm_priv_locked (urb_t * urb) 
+static void urb_rm_priv_locked (struct urb * urb) 
 {
 	urb_priv_t * urb_priv = urb->hcpriv;
 	
@@ -212,7 +212,7 @@
 	}
 }
 
-static void urb_rm_priv (urb_t * urb)
+static void urb_rm_priv (struct urb * urb)
 {
 	unsigned long flags;
 
@@ -229,7 +229,7 @@
 /* debug| print the main components of an URB     
  * small: 0) header + data packets 1) just header */
  
-static void urb_print (urb_t * urb, char * str, int small)
+static void urb_print (struct urb * urb, char * str, int small)
 {
 	unsigned int pipe= urb->pipe;
 	
@@ -458,10 +458,10 @@
 
 /* return a request to the completion handler */
  
-static int sohci_return_urb (struct ohci *hc, urb_t * urb)
+static int sohci_return_urb (struct ohci *hc, struct urb * urb)
 {
 	urb_priv_t * urb_priv = urb->hcpriv;
-	urb_t * urbt;
+	struct urb * urbt;
 	unsigned long flags;
 	int i;
 	
@@ -536,7 +536,7 @@
 
 /* get a transfer request */
  
-static int sohci_submit_urb (urb_t * urb)
+static int sohci_submit_urb (struct urb * urb)
 {
 	ohci_t * ohci;
 	ed_t * ed;
@@ -720,7 +720,7 @@
 /* deactivate all TDs and remove the private part of the URB */
 /* interrupt callers must use async unlink mode */
 
-static int sohci_unlink_urb (urb_t * urb)
+static int sohci_unlink_urb (struct urb * urb)
 {
 	unsigned long flags;
 	ohci_t * ohci;
@@ -1295,7 +1295,7 @@
 static void
 td_fill (ohci_t * ohci, unsigned int info,
 	dma_addr_t data, int len,
-	urb_t * urb, int index)
+	struct urb * urb, int index)
 {
 	volatile td_t  * td, * td_pt;
 	urb_priv_t * urb_priv = urb->hcpriv;
@@ -1344,7 +1344,7 @@
  
 /* prepare all TDs of a transfer */
 
-static void td_submit_urb (urb_t * urb)
+static void td_submit_urb (struct urb * urb)
 { 
 	urb_priv_t * urb_priv = urb->hcpriv;
 	ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
@@ -1457,7 +1457,7 @@
 {
 	__u32 tdINFO, tdBE, tdCBP;
  	__u16 tdPSW;
- 	urb_t * urb = td->urb;
+ 	struct urb * urb = td->urb;
  	urb_priv_t * urb_priv = urb->hcpriv;
 	int dlen = 0;
 	int cc = 0;
@@ -1498,7 +1498,7 @@
 
 /* handle an urb that is being unlinked */
 
-static void dl_del_urb (urb_t * urb)
+static void dl_del_urb (struct urb * urb)
 {
 	wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
 
@@ -1587,7 +1587,7 @@
 		td_p = &ed->hwHeadP;
 
 		for (td = tdHeadP; td != tdTailP; td = td_next) { 
-			urb_t * urb = td->urb;
+			struct urb * urb = td->urb;
 			urb_priv_t * urb_priv = td->urb->hcpriv;
 			
 			td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
@@ -1675,7 +1675,7 @@
   	td_t * td_list_next = NULL;
 	ed_t * ed;
 	int cc = 0;
-	urb_t * urb;
+	struct urb * urb;
 	urb_priv_t * urb_priv;
  	__u32 tdINFO, edHeadP, edTailP;
  	
@@ -1851,7 +1851,7 @@
 {
 	int len; 
 
-	urb_t * urb = (urb_t *) ptr;
+	struct urb * urb = (struct urb *) ptr;
 	ohci_t * ohci = urb->dev->bus->hcpriv;
 
 	if (ohci->disabled)
@@ -1880,7 +1880,7 @@
 
 /* Root Hub INTs are polled by this timer */
 
-static int rh_init_int_timer (urb_t * urb) 
+static int rh_init_int_timer (struct urb * urb) 
 {
 	ohci_t * ohci = urb->dev->bus->hcpriv;
 
@@ -1905,12 +1905,12 @@
 
 /* request to virtual root hub */
 
-static int rh_submit_urb (urb_t * urb)
+static int rh_submit_urb (struct urb * urb)
 {
 	struct usb_device * usb_dev = urb->dev;
 	ohci_t * ohci = usb_dev->bus->hcpriv;
 	unsigned int pipe = urb->pipe;
-	devrequest * cmd = (devrequest *) urb->setup_packet;
+	struct usb_ctrlrequest * cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	void * data = urb->transfer_buffer;
 	int leni = urb->transfer_buffer_length;
 	int len = 0;
@@ -1934,10 +1934,10 @@
 		return 0;
 	}
 
-	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
-	wValue        = le16_to_cpu (cmd->value);
-	wIndex        = le16_to_cpu (cmd->index);
-	wLength       = le16_to_cpu (cmd->length);
+	bmRType_bReq  = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue        = le16_to_cpu (cmd->wValue);
+	wIndex        = le16_to_cpu (cmd->wIndex);
+	wLength       = le16_to_cpu (cmd->wLength);
 
 	switch (bmRType_bReq) {
 	/* Request Destination:
@@ -2111,7 +2111,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int rh_unlink_urb (urb_t * urb)
+static int rh_unlink_urb (struct urb * urb)
 {
 	ohci_t * ohci = urb->dev->bus->hcpriv;
  
diff -urN linux-2.4.20-pre1/drivers/usb/usb-ohci.h linux-2.4.20-pre2/drivers/usb/usb-ohci.h
--- linux-2.4.20-pre1/drivers/usb/usb-ohci.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/usb-ohci.h	Mon Aug 12 16:34:17 2002
@@ -111,7 +111,7 @@
   	__u8 index;
   	struct ed * ed;
   	struct td * next_dl_td;
-  	urb_t * urb;
+  	struct urb * urb;
 
 	dma_addr_t td_dma;
 	dma_addr_t data_dma;
@@ -430,12 +430,12 @@
 static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load, int mem_flags);
 static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
 /* td */
-static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, urb_t * urb, int index);
-static void td_submit_urb(urb_t * urb);
+static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, struct urb * urb, int index);
+static void td_submit_urb(struct urb * urb);
 /* root hub */
-static int rh_submit_urb(urb_t * urb);
-static int rh_unlink_urb(urb_t * urb);
-static int rh_init_int_timer(urb_t * urb);
+static int rh_submit_urb(struct urb * urb);
+static int rh_unlink_urb(struct urb * urb);
+static int rh_init_int_timer(struct urb * urb);
 
 /*-------------------------------------------------------------------------*/
 
diff -urN linux-2.4.20-pre1/drivers/usb/usb-uhci.c linux-2.4.20-pre2/drivers/usb/usb-uhci.c
--- linux-2.4.20-pre1/drivers/usb/usb-uhci.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/usb-uhci.c	Mon Aug 12 16:34:17 2002
@@ -117,12 +117,12 @@
 // Suppress HC interrupt error messages for 5s
 #define ERROR_SUPPRESSION_TIME (HZ*5)
 
-_static int rh_submit_urb (urb_t *urb);
-_static int rh_unlink_urb (urb_t *urb);
+_static int rh_submit_urb (struct urb *urb);
+_static int rh_unlink_urb (struct urb *urb);
 _static int delete_qh (uhci_t *s, uhci_desc_t *qh);
-_static int process_transfer (uhci_t *s, urb_t *urb, int mode);
-_static int process_interrupt (uhci_t *s, urb_t *urb);
-_static int process_iso (uhci_t *s, urb_t *urb, int force);
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode);
+_static int process_interrupt (uhci_t *s, struct urb *urb);
+_static int process_iso (uhci_t *s, struct urb *urb, int force);
 
 // How much URBs with ->next are walked
 #define MAX_NEXT_COUNT 2048
@@ -168,7 +168,7 @@
 }
 /*-------------------------------------------------------------------*/
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-_static void enable_desc_loop(uhci_t *s, urb_t *urb)
+_static void enable_desc_loop(uhci_t *s, struct urb *urb)
 {
 	unsigned long flags;
 
@@ -183,7 +183,7 @@
 	spin_unlock_irqrestore (&s->qh_lock, flags);
 }
 /*-------------------------------------------------------------------*/
-_static void disable_desc_loop(uhci_t *s, urb_t *urb)
+_static void disable_desc_loop(uhci_t *s, struct urb *urb)
 {
 	unsigned long flags;
 
@@ -204,7 +204,7 @@
 }
 #endif
 /*-------------------------------------------------------------------*/
-_static void queue_urb_unlocked (uhci_t *s, urb_t *urb)
+_static void queue_urb_unlocked (uhci_t *s, struct urb *urb)
 {
 	struct list_head *p=&urb->urb_list;
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
@@ -224,7 +224,7 @@
 	uhci_switch_timer_int(s);
 }
 /*-------------------------------------------------------------------*/
-_static void queue_urb (uhci_t *s, urb_t *urb)
+_static void queue_urb (uhci_t *s, struct urb *urb)
 {
 	unsigned long flags=0;
 
@@ -233,7 +233,7 @@
 	spin_unlock_irqrestore (&s->urb_list_lock, flags);
 }
 /*-------------------------------------------------------------------*/
-_static void dequeue_urb (uhci_t *s, urb_t *urb)
+_static void dequeue_urb (uhci_t *s, struct urb *urb)
 {
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 	int type;
@@ -698,7 +698,7 @@
 //                         LOW LEVEL STUFF
 //          assembles QHs und TDs for control, bulk and iso
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_control_urb (urb_t *urb)
+_static int uhci_submit_control_urb (struct urb *urb)
 {
 	uhci_desc_t *qh, *td;
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
@@ -815,7 +815,7 @@
 // For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
 // Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
 
-_static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
+_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
@@ -977,7 +977,7 @@
  looks a bit complicated because of all the bulk queueing goodies
 */
 
-_static void uhci_clean_transfer (uhci_t *s, urb_t *urb, uhci_desc_t *qh, int mode)
+_static void uhci_clean_transfer (uhci_t *s, struct urb *urb, uhci_desc_t *qh, int mode)
 {
 	uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
 	int now;
@@ -1031,7 +1031,7 @@
 		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
        	
 		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
-			urb_t *nurb;
+			struct urb *nurb;
 			unsigned long flags;
 
 			nurb = priv->next_queued_urb;
@@ -1069,7 +1069,7 @@
 }
 /*-------------------------------------------------------------------*/
 // Release bandwidth for Interrupt or Isoc. transfers 
-_static void uhci_release_bandwidth(urb_t *urb)
+_static void uhci_release_bandwidth(struct urb *urb)
 {       
 	if (urb->bandwidth) {
 		switch (usb_pipetype(urb->pipe)) {
@@ -1085,11 +1085,11 @@
 	}	
 }
 
-_static void uhci_urb_dma_sync(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
+_static void uhci_urb_dma_sync(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
 {
 	if (urb_priv->setup_packet_dma)
 		pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				    sizeof(devrequest), PCI_DMA_TODEVICE);
+				    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 
 	if (urb_priv->transfer_buffer_dma)
 		pci_dma_sync_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
@@ -1099,11 +1099,11 @@
 				    PCI_DMA_TODEVICE);
 }
 
-_static void uhci_urb_dma_unmap(uhci_t *s, urb_t *urb, urb_priv_t *urb_priv)
+_static void uhci_urb_dma_unmap(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
 {
 	if (urb_priv->setup_packet_dma) {
 		pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				 sizeof(devrequest), PCI_DMA_TODEVICE);
+				 sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 		urb_priv->setup_packet_dma = 0;
 	}
 	if (urb_priv->transfer_buffer_dma) {
@@ -1120,7 +1120,7 @@
    mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
          UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
 */
-_static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb, int mode)
+_static int uhci_unlink_urb_async (uhci_t *s,struct urb *urb, int mode)
 {
 	uhci_desc_t *qh;
 	urb_priv_t *urb_priv;
@@ -1165,7 +1165,7 @@
 }
 /*-------------------------------------------------------------------*/
 // kills an urb by unlinking descriptors and waiting for at least one frame
-_static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
+_static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
 {
 	uhci_desc_t *qh;
 	urb_priv_t *urb_priv;
@@ -1229,7 +1229,7 @@
 _static void uhci_cleanup_unlink(uhci_t *s, int force)
 {
 	struct list_head *q;
-	urb_t *urb;
+	struct urb *urb;
 	struct usb_device *dev;
 	int now, type;
 	urb_priv_t *urb_priv;
@@ -1239,7 +1239,7 @@
 
 	while (q != &s->urb_unlinked) {
 
-		urb = list_entry (q, urb_t, urb_list);
+		urb = list_entry (q, struct urb, urb_list);
 
 		urb_priv = (urb_priv_t*)urb->hcpriv;
 		q = urb->urb_list.next;
@@ -1308,7 +1308,7 @@
 }
  
 /*-------------------------------------------------------------------*/
-_static int uhci_unlink_urb (urb_t *urb)
+_static int uhci_unlink_urb (struct urb *urb)
 {
 	uhci_t *s;
 	unsigned long flags=0;
@@ -1341,9 +1341,9 @@
 // In case of ASAP iso transfer, search the URB-list for already queued URBs
 // for this EP and calculate the earliest start frame for the new
 // URB (easy seamless URB continuation!)
-_static int find_iso_limits (urb_t *urb, unsigned int *start, unsigned int *end)
+_static int find_iso_limits (struct urb *urb, unsigned int *start, unsigned int *end)
 {
-	urb_t *u, *last_urb = NULL;
+	struct urb *u, *last_urb = NULL;
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	struct list_head *p;
 	int ret=-1;
@@ -1353,7 +1353,7 @@
 	p=s->urb_list.prev;
 
 	for (; p != &s->urb_list; p = p->prev) {
-		u = list_entry (p, urb_t, urb_list);
+		u = list_entry (p, struct urb, urb_list);
 		// look for pending URBs with identical pipe handle
 		// works only because iso doesn't toggle the data bit!
 		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
@@ -1375,7 +1375,7 @@
 /*-------------------------------------------------------------------*/
 // adjust start_frame according to scheduling constraints (ASAP etc)
 
-_static int iso_find_start (urb_t *urb)
+_static int iso_find_start (struct urb *urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	unsigned int now;
@@ -1433,7 +1433,7 @@
 // ASAP-flag set implicitely
 // if period==0, the transfer is only done once
 
-_static int uhci_submit_int_urb (urb_t *urb)
+_static int uhci_submit_int_urb (struct urb *urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -1493,7 +1493,7 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_iso_urb (urb_t *urb)
+_static int uhci_submit_iso_urb (struct urb *urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -1586,10 +1586,10 @@
 /*-------------------------------------------------------------------*/
 // returns: 0 (no transfer queued), urb* (this urb already queued)
  
-_static urb_t* search_dev_ep (uhci_t *s, urb_t *urb)
+_static struct urb* search_dev_ep (uhci_t *s, struct urb *urb)
 {
 	struct list_head *p;
-	urb_t *tmp;
+	struct urb *tmp;
 	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
 
 	dbg("search_dev_ep:");
@@ -1597,7 +1597,7 @@
 	p=s->urb_list.next;
 
 	for (; p != &s->urb_list; p = p->next) {
-		tmp = list_entry (p, urb_t, urb_list);
+		tmp = list_entry (p, struct urb, urb_list);
 		dbg("urb: %p", tmp);
 		// we can accept this urb if it is not queued at this time 
 		// or if non-iso transfer requests should be scheduled for the same device and pipe
@@ -1610,13 +1610,13 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-_static int uhci_submit_urb (urb_t *urb)
+_static int uhci_submit_urb (struct urb *urb)
 {
 	uhci_t *s;
 	urb_priv_t *urb_priv;
 	int ret = 0, type;
 	unsigned long flags;
-	urb_t *queued_urb=NULL;
+	struct urb *queued_urb=NULL;
 	int bustime;
 		
 	if (!urb->dev || !urb->dev->bus)
@@ -1683,7 +1683,7 @@
 	
 	if (type == PIPE_CONTROL)
 		urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet,
-							    sizeof(devrequest), PCI_DMA_TODEVICE);
+							    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
 
 	if (urb->transfer_buffer_length)
 		urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci,
@@ -1770,7 +1770,7 @@
 _static void uhci_check_timeouts(uhci_t *s)
 {
 	struct list_head *p,*p2;
-	urb_t *urb;
+	struct urb *urb;
 	int type;	
 
 	p = s->urb_list.prev;	
@@ -1780,7 +1780,7 @@
 
 		p2 = p;
 		p = p->prev;
-		urb = list_entry (p2, urb_t, urb_list);
+		urb = list_entry (p2, struct urb, urb_list);
 		type = usb_pipetype (urb->pipe);
 
 		hcpriv = (urb_priv_t*)urb->hcpriv;
@@ -1878,7 +1878,7 @@
 
 /*-------------------------------------------------------------------------*/
 /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-_static int rh_send_irq (urb_t *urb)
+_static int rh_send_irq (struct urb *urb)
 {
 	int len = 1;
 	int i;
@@ -1905,12 +1905,12 @@
 
 /*-------------------------------------------------------------------------*/
 /* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-_static int rh_init_int_timer (urb_t *urb);
+_static int rh_init_int_timer (struct urb *urb);
 
 _static void rh_int_timer_do (unsigned long ptr)
 {
 	int len;
-	urb_t *urb = (urb_t*) ptr;
+	struct urb *urb = (struct urb*) ptr;
 	uhci_t *uhci = urb->dev->bus->hcpriv;
 
 	if (uhci->rh.send) {
@@ -1927,7 +1927,7 @@
 /*-------------------------------------------------------------------------*/
 /* Root Hub INTs are polled by this timer, polling interval 20ms */
 
-_static int rh_init_int_timer (urb_t *urb)
+_static int rh_init_int_timer (struct urb *urb)
 {
 	uhci_t *uhci = urb->dev->bus->hcpriv;
 
@@ -1961,12 +1961,12 @@
  *************************/
 
 
-_static int rh_submit_urb (urb_t *urb)
+_static int rh_submit_urb (struct urb *urb)
 {
 	struct usb_device *usb_dev = urb->dev;
 	uhci_t *uhci = usb_dev->bus->hcpriv;
 	unsigned int pipe = urb->pipe;
-	devrequest *cmd = (devrequest *) urb->setup_packet;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	void *data = urb->transfer_buffer;
 	int leni = urb->transfer_buffer_length;
 	int len = 0;
@@ -1992,10 +1992,10 @@
 	}
 
 
-	bmRType_bReq = cmd->requesttype | cmd->request << 8;
-	wValue = le16_to_cpu (cmd->value);
-	wIndex = le16_to_cpu (cmd->index);
-	wLength = le16_to_cpu (cmd->length);
+	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+	wValue = le16_to_cpu (cmd->wValue);
+	wIndex = le16_to_cpu (cmd->wIndex);
+	wLength = le16_to_cpu (cmd->wLength);
 
 	for (i = 0; i < 8; i++)
 		uhci->rh.c_p_r[i] = 0;
@@ -2162,7 +2162,7 @@
 }
 /*-------------------------------------------------------------------------*/
 
-_static int rh_unlink_urb (urb_t *urb)
+_static int rh_unlink_urb (struct urb *urb)
 {
 	uhci_t *uhci = urb->dev->bus->hcpriv;
 
@@ -2220,14 +2220,14 @@
 	unsigned long flags;
 	struct list_head *p;
 	struct list_head *p2;
-	urb_t *urb;
+	struct urb *urb;
 
 	spin_lock_irqsave (&s->urb_list_lock, flags);
 	p = s->urb_list.prev;	
 	while (p != &s->urb_list) {
 		p2 = p;
 		p = p->prev ;
-		urb = list_entry (p2, urb_t, urb_list);
+		urb = list_entry (p2, struct urb, urb_list);
 		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
 		
 		//urb->transfer_flags |=USB_ASYNC_UNLINK; 
@@ -2277,7 +2277,7 @@
 	uhci_unlink_urb
 };
 
-_static void correct_data_toggles(urb_t *urb)
+_static void correct_data_toggles(struct urb *urb)
 {
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
 		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
@@ -2307,7 +2307,7 @@
  *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
  */
 
-_static int process_transfer (uhci_t *s, urb_t *urb, int mode)
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode)
 {
 	int ret = 0;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -2395,7 +2395,7 @@
 	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  /* toggle correction for short bulk transfers (nonqueued/queued) */
 
 		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-		urb_t *next_queued_urb=priv->next_queued_urb;
+		struct urb *next_queued_urb=priv->next_queued_urb;
 
 		if (next_queued_urb) {
 			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
@@ -2426,7 +2426,7 @@
 	return ret;
 }
 
-_static int process_interrupt (uhci_t *s, urb_t *urb)
+_static int process_interrupt (uhci_t *s, struct urb *urb)
 {
 	int i, ret = -EINPROGRESS;
 	urb_priv_t *urb_priv = urb->hcpriv;
@@ -2525,7 +2525,7 @@
 // mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
 // mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
 
-_static int process_iso (uhci_t *s, urb_t *urb, int mode)
+_static int process_iso (uhci_t *s, struct urb *urb, int mode)
 {
 	int i;
 	int ret = 0;
@@ -2594,9 +2594,9 @@
 _static int process_urb (uhci_t *s, struct list_head *p)
 {
 	int ret = 0;
-	urb_t *urb;
+	struct urb *urb;
 
-	urb=list_entry (p, urb_t, urb_list);
+	urb=list_entry (p, struct urb, urb_list);
 	//dbg("process_urb: found queued urb: %p", urb);
 
 	switch (usb_pipetype (urb->pipe)) {
@@ -2645,7 +2645,7 @@
 #endif
 
 		if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) {  // process_interrupt does completion on its own		
-			urb_t *next_urb = urb->next;
+			struct urb *next_urb = urb->next;
 			int is_ring = 0;
 			int contains_killed = 0;
 			int loop_count=0;
diff -urN linux-2.4.20-pre1/drivers/usb/usb-uhci.h linux-2.4.20-pre2/drivers/usb/usb-uhci.h
--- linux-2.4.20-pre1/drivers/usb/usb-uhci.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/usb-uhci.h	Mon Aug 12 16:34:17 2002
@@ -158,8 +158,8 @@
 	dma_addr_t setup_packet_dma;
 	dma_addr_t transfer_buffer_dma;
 	unsigned long started;
-	urb_t *next_queued_urb;         // next queued urb for this EP
-	urb_t *prev_queued_urb;
+	struct urb *next_queued_urb;	// next queued urb for this EP
+	struct urb *prev_queued_urb;
 	uhci_desc_t *bottom_qh;
 	uhci_desc_t *next_qh;       	// next helper QH
 	char use_loop;
diff -urN linux-2.4.20-pre1/drivers/usb/usb.c linux-2.4.20-pre2/drivers/usb/usb.c
--- linux-2.4.20-pre1/drivers/usb/usb.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/usb.c	Mon Aug 12 16:34:17 2002
@@ -985,11 +985,11 @@
  *
  *	The driver should call usb_free_urb() when it is finished with the urb.
  */
-urb_t *usb_alloc_urb(int iso_packets)
+struct urb *usb_alloc_urb(int iso_packets)
 {
-	urb_t *urb;
+	struct urb *urb;
 
-	urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t),
+	urb = (struct urb *)kmalloc(sizeof(struct urb) + iso_packets * sizeof(struct iso_packet_descriptor),
 	      in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
 	if (!urb) {
 		err("alloc_urb: kmalloc failed");
@@ -1011,13 +1011,13 @@
  *	cleaned up with a call to usb_free_urb() when the driver is finished
  *	with it.
  */
-void usb_free_urb(urb_t* urb)
+void usb_free_urb(struct urb* urb)
 {
 	if (urb)
 		kfree(urb);
 }
 /*-------------------------------------------------------------------*/
-int usb_submit_urb(urb_t *urb)
+int usb_submit_urb(struct urb *urb)
 {
 	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
 		return urb->dev->bus->op->submit_urb(urb);
@@ -1026,7 +1026,7 @@
 }
 
 /*-------------------------------------------------------------------*/
-int usb_unlink_urb(urb_t *urb)
+int usb_unlink_urb(struct urb *urb)
 {
 	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
 		return urb->dev->bus->op->unlink_urb(urb);
@@ -1040,7 +1040,7 @@
 /*-------------------------------------------------------------------*
  * completion handler for compatibility wrappers (sync control/bulk) *
  *-------------------------------------------------------------------*/
-static void usb_api_blocking_completion(urb_t *urb)
+static void usb_api_blocking_completion(struct urb *urb)
 {
 	struct usb_api_data *awd = (struct usb_api_data *)urb->context;
 
@@ -1054,7 +1054,7 @@
  *-------------------------------------------------------------------*/
 
 // Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
 { 
 	DECLARE_WAITQUEUE(wait, current);
 	struct usb_api_data awd;
@@ -1110,9 +1110,9 @@
 /*-------------------------------------------------------------------*/
 // returns status (negative) or length (positive)
 int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, 
-			    devrequest *cmd,  void *data, int len, int timeout)
+			    struct usb_ctrlrequest *cmd,  void *data, int len, int timeout)
 {
-	urb_t *urb;
+	struct urb *urb;
 	int retv;
 	int length;
 
@@ -1154,17 +1154,17 @@
 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
 			 __u16 value, __u16 index, void *data, __u16 size, int timeout)
 {
-	devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
+	struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
 	int ret;
 	
 	if (!dr)
 		return -ENOMEM;
 
-	dr->requesttype = requesttype;
-	dr->request = request;
-	dr->value = cpu_to_le16p(&value);
-	dr->index = cpu_to_le16p(&index);
-	dr->length = cpu_to_le16p(&size);
+	dr->bRequestType = requesttype;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16p(&value);
+	dr->wIndex = cpu_to_le16p(&index);
+	dr->wLength = cpu_to_le16p(&size);
 
 	//dbg("usb_control_msg");	
 
@@ -1199,7 +1199,7 @@
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
 			void *data, int len, int *actual_length, int timeout)
 {
-	urb_t *urb;
+	struct urb *urb;
 
 	if (len < 0)
 		return -EINVAL;
diff -urN linux-2.4.20-pre1/drivers/usb/usbkbd.c linux-2.4.20-pre2/drivers/usb/usbkbd.c
--- linux-2.4.20-pre1/drivers/usb/usbkbd.c	Fri Sep 14 14:04:07 2001
+++ linux-2.4.20-pre2/drivers/usb/usbkbd.c	Mon Aug 12 16:34:17 2002
@@ -71,7 +71,7 @@
 	unsigned char new[8];
 	unsigned char old[8];
 	struct urb irq, led;
-	devrequest dr;
+	struct usb_ctrlrequest dr;
 	unsigned char leds, newleds;
 	char name[128];
 	int open;
@@ -215,11 +215,11 @@
 	FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
 		usb_kbd_irq, kbd, endpoint->bInterval);
 
-	kbd->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-	kbd->dr.request = USB_REQ_SET_REPORT;
-	kbd->dr.value = 0x200;
-	kbd->dr.index = interface->bInterfaceNumber;
-	kbd->dr.length = 1;
+	kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	kbd->dr.bRequest = USB_REQ_SET_REPORT;
+	kbd->dr.wValue = 0x200;
+	kbd->dr.wIndex = interface->bInterfaceNumber;
+	kbd->dr.wLength = 1;
 
 	kbd->dev.name = kbd->name;
 	kbd->dev.idbus = BUS_USB;
diff -urN linux-2.4.20-pre1/drivers/usb/usbvideo.c linux-2.4.20-pre2/drivers/usb/usbvideo.c
--- linux-2.4.20-pre1/drivers/usb/usbvideo.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/usb/usbvideo.c	Mon Aug 12 16:34:17 2002
@@ -1782,7 +1782,7 @@
 /*
  * Make all of the blocks of data contiguous
  */
-static int usbvideo_CompressIsochronous(uvd_t *uvd, urb_t *urb)
+static int usbvideo_CompressIsochronous(uvd_t *uvd, struct urb *urb)
 {
 	char *cdata;
 	int i, totlen = 0;
@@ -1897,7 +1897,7 @@
 	/* We double buffer the Iso lists */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		int j, k;
-		urb_t *urb = uvd->sbuf[i].urb;
+		struct urb *urb = uvd->sbuf[i].urb;
 		urb->dev = dev;
 		urb->context = uvd;
 		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
diff -urN linux-2.4.20-pre1/drivers/usb/usbvideo.h linux-2.4.20-pre2/drivers/usb/usbvideo.h
--- linux-2.4.20-pre1/drivers/usb/usbvideo.h	Wed Oct 10 23:42:46 2001
+++ linux-2.4.20-pre2/drivers/usb/usbvideo.h	Mon Aug 12 16:34:17 2002
@@ -165,7 +165,7 @@
 /* This structure represents one Isoc request - URB and buffer */
 typedef struct {
 	char *data;
-	urb_t *urb;
+	struct urb *urb;
 } usbvideo_sbuf_t;
 
 typedef struct {
diff -urN linux-2.4.20-pre1/drivers/usb/vicam.h linux-2.4.20-pre2/drivers/usb/vicam.h
--- linux-2.4.20-pre1/drivers/usb/vicam.h	Mon Feb 25 11:38:07 2002
+++ linux-2.4.20-pre2/drivers/usb/vicam.h	Mon Aug 12 16:34:17 2002
@@ -68,7 +68,7 @@
 	/* v4l stuff */
 	char *camera_name;
 	char *fbuf;
-	urb_t *urb[VICAM_NUMSBUF];
+	struct urb *urb[VICAM_NUMSBUF];
 	int sizes;
 	int *width;
 	int *height;
diff -urN linux-2.4.20-pre1/drivers/video/Config.in linux-2.4.20-pre2/drivers/video/Config.in
--- linux-2.4.20-pre1/drivers/video/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/drivers/video/Config.in	Mon Aug 12 16:34:17 2002
@@ -152,16 +152,16 @@
 	 tristate '  Trident support (EXPERIMENTAL)' CONFIG_FB_TRIDENT
       fi
    fi
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       bool '  SBUS and UPA framebuffers' CONFIG_FB_SBUS
       if [ "$CONFIG_FB_SBUS" != "n" ]; then
-	 if [ "$ARCH" = "sparc64" ]; then
+	 if [ "$CONFIG_SPARC64" = "y" ]; then
 	    bool '    Creator/Creator3D support' CONFIG_FB_CREATOR
 	 fi
 	 bool '    CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
 	 bool '    BWtwo support' CONFIG_FB_BWTWO
 	 bool '    CGthree support' CONFIG_FB_CGTHREE
-	 if [ "$ARCH" = "sparc" ]; then
+	 if [ "$CONFIG_SPARC32" = "y" ]; then
 	    bool '    TCX (SS4/SS5 only) support' CONFIG_FB_TCX
 	    bool '    CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN
 	    bool '    P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100
@@ -169,7 +169,7 @@
 	 bool '    Leo (ZX) support' CONFIG_FB_LEO
       fi
    fi
-   if [ "$ARCH" = "sparc" ]; then
+   if [ "$CONFIG_SPARC32" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
 	 bool '  PCI framebuffers' CONFIG_FB_PCI
 	 if [ "$CONFIG_FB_PCI" != "n" ]; then
@@ -177,7 +177,7 @@
 	 fi
       fi
    fi
-   if [ "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC64" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
 	 bool '  PCI framebuffers' CONFIG_FB_PCI
 	 if [ "$CONFIG_FB_PCI" != "n" ]; then
@@ -202,7 +202,7 @@
       bool '  TMPTX3912/PR31700 frame buffer support' CONFIG_FB_TX3912
    fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
+      tristate '  Virtual Frame Buffer support (ONLY FOR TESTING!) (EXPERIMENTAL)' CONFIG_FB_VIRTUAL
    fi
 
    bool '  Advanced low level driver options' CONFIG_FBCON_ADVANCED
@@ -274,7 +274,8 @@
 	   "$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" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
+	   "$CONFIG_FB_STI" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -295,7 +296,8 @@
 	      "$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" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
+	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \
+	      "$CONFIG_FB_STI" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
@@ -361,7 +363,8 @@
 	   "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
 	   "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
 	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
-	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
+	   "$CONFIG_FB_STI" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB32 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -374,7 +377,7 @@
 	      "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
 	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
-	      "$CONFIG_FB_CYBER2000" = "m" ]; then
+	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_STI" = "y" ]; then
 	    define_tristate CONFIG_FBCON_CFB32 m
 	 fi
       fi
@@ -426,7 +429,7 @@
       fi
    fi
    bool '  Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       bool '  Sparc console 8x16 font' CONFIG_FONT_SUN8x16
       if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
 	 bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
diff -urN linux-2.4.20-pre1/drivers/video/Makefile linux-2.4.20-pre2/drivers/video/Makefile
--- linux-2.4.20-pre1/drivers/video/Makefile	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/video/Makefile	Mon Aug 12 16:34:17 2002
@@ -4,7 +4,7 @@
 
 O_TARGET := video.o
 
-mod-subdirs	:= matrox
+mod-subdirs	:= matrox sti
 
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
@@ -22,7 +22,6 @@
 obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
 obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
 obj-$(CONFIG_PROM_CONSOLE)        += promcon.o promcon_tbl.o
-obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticon-bmode.o sticore.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
 obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
 
@@ -82,12 +81,21 @@
 obj-$(CONFIG_FB_CGFOURTEEN)       += cgfourteenfb.o sbusfb.o
 obj-$(CONFIG_FB_P9100)            += p9100fb.o sbusfb.o
 obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
-obj-$(CONFIG_FB_STI)	          += stifb.o sticore.o fbgen.o
 obj-$(CONFIG_FB_PMAG_BA)          += pmag-ba-fb.o
 obj-$(CONFIG_FB_PMAGB_B)          += pmagb-b-fb.o
 obj-$(CONFIG_FB_MAXINE)           += maxinefb.o
 obj-$(CONFIG_FB_TX3912)           += tx3912fb.o
 
+subdir-$(CONFIG_STI_CONSOLE)      += sti
+ifeq ($(CONFIG_STI_CONSOLE),y)
+obj-y                             += sti/sti.o fonts.o
+endif
+
+subdir-$(CONFIG_FB_STI)           += sti
+ifeq ($(CONFIG_FB_STI),y)
+obj-y                             += sti/sti.o fbgen.o
+endif
+
 
 subdir-$(CONFIG_FB_MATROX)	  += matrox
 ifeq ($(CONFIG_FB_MATROX),y)
diff -urN linux-2.4.20-pre1/drivers/video/fbmem.c linux-2.4.20-pre2/drivers/video/fbmem.c
--- linux-2.4.20-pre1/drivers/video/fbmem.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/video/fbmem.c	Mon Aug 12 16:34:17 2002
@@ -644,6 +644,8 @@
 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
 #elif defined(__ia64__)
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__hppa__)
+	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; 
 #else
 #warning What do we have to do here??
 #endif
diff -urN linux-2.4.20-pre1/drivers/video/pm3fb.h linux-2.4.20-pre2/drivers/video/pm3fb.h
--- linux-2.4.20-pre1/drivers/video/pm3fb.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/video/pm3fb.h	Mon Aug 12 16:34:17 2002
@@ -1283,4 +1283,4 @@
     } \
 } while (0)
 
-#endif PM3FB_H
+#endif /* PM3FB_H */
diff -urN linux-2.4.20-pre1/drivers/video/sstfb.c linux-2.4.20-pre2/drivers/video/sstfb.c
--- linux-2.4.20-pre1/drivers/video/sstfb.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/drivers/video/sstfb.c	Mon Aug 12 16:34:17 2002
@@ -774,13 +774,13 @@
 {
 #define sst_info	((struct sstfb_info *) info)
 
-	struct fb_var_screeninfo *var;
+	struct fb_var_screeninfo tmpvar;
 
 	f_dprintk("sstfb_get_fix(con: %d)\n",con);
 	if (con == -1)
-		sstfb_encode_var(var, &sst_info->current_par, sst_info);
+		sstfb_encode_var(&tmpvar, &sst_info->current_par, sst_info);
 	else
-		var = &fb_display[con].var;
+		tmpvar = fb_display[con].var;
 
 	strcpy(fix->id, sst_info->info.modename);
 	/* lfb phys address = membase + 4Mb */
@@ -793,7 +793,7 @@
 	 *   According to the specs, the linelength must be of 1024 *pixels*.
 	 * and the 24bpp mode is in fact a 32 bpp mode.
 	 */
-	fix->line_length = (var->bits_per_pixel == 16) ? 2048 : 4096 ;
+	fix->line_length = (tmpvar.bits_per_pixel == 16) ? 2048 : 4096 ;
 	return 0;
 #undef sst_info
 }
diff -urN linux-2.4.20-pre1/fs/Config.in linux-2.4.20-pre2/fs/Config.in
--- linux-2.4.20-pre1/fs/Config.in	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/Config.in	Mon Aug 12 16:34:17 2002
@@ -9,10 +9,10 @@
 tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
 
 tristate 'Reiserfs support' CONFIG_REISERFS_FS
-dep_mbool '  Have reiserfs do extra internal checking' CONFIG_REISERFS_CHECK $CONFIG_REISERFS_FS
+dep_mbool '  Enable reiserfs debug mode' CONFIG_REISERFS_CHECK $CONFIG_REISERFS_FS
 dep_mbool '  Stats in /proc/fs/reiserfs' CONFIG_REISERFS_PROC_INFO $CONFIG_REISERFS_FS
 
-dep_tristate 'ADFS file system support' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
+dep_tristate 'ADFS file system support (EXPERIMENTAL)' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 dep_mbool '  ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 
 dep_tristate 'Amiga FFS file system support (EXPERIMENTAL)' CONFIG_AFFS_FS $CONFIG_EXPERIMENTAL
@@ -92,7 +92,7 @@
    comment 'Network File Systems'
 
    dep_tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS $CONFIG_INET
-   dep_tristate 'InterMezzo file system support (experimental, replicating fs)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
+   dep_tristate 'InterMezzo file system support (replicating fs) (EXPERIMENTAL)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
    dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
    dep_mbool '  Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS
    dep_bool '  Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
@@ -146,15 +146,6 @@
 else
    define_tristate CONFIG_ZISOFS_FS n
 fi
-if [ "$CONFIG_CRAMFS" = "y" -o "$CONFIG_ZISOFS_FS" = "y" ]; then
-   define_tristate CONFIG_ZLIB_FS_INFLATE y
-else
-  if [ "$CONFIG_CRAMFS" = "m" -o "$CONFIG_ZISOFS_FS" = "m" ]; then
-     define_tristate CONFIG_ZLIB_FS_INFLATE m
-  else
-     define_tristate CONFIG_ZLIB_FS_INFLATE n
-  fi
-fi
 
 mainmenu_option next_comment
 comment 'Partition Types'
diff -urN linux-2.4.20-pre1/fs/Makefile linux-2.4.20-pre2/fs/Makefile
--- linux-2.4.20-pre1/fs/Makefile	Mon Feb 25 11:38:07 2002
+++ linux-2.4.20-pre2/fs/Makefile	Mon Aug 12 16:34:17 2002
@@ -29,7 +29,6 @@
 subdir-$(CONFIG_EXT3_FS)	+= ext3    # Before ext2 so root fs can be ext3
 subdir-$(CONFIG_JBD)		+= jbd
 subdir-$(CONFIG_EXT2_FS)	+= ext2
-subdir-$(CONFIG_ZLIB_FS_INFLATE) += inflate_fs
 subdir-$(CONFIG_CRAMFS)		+= cramfs
 subdir-$(CONFIG_RAMFS)		+= ramfs
 subdir-$(CONFIG_CODA_FS)	+= coda
diff -urN linux-2.4.20-pre1/fs/buffer.c linux-2.4.20-pre2/fs/buffer.c
--- linux-2.4.20-pre1/fs/buffer.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/buffer.c	Mon Aug 12 16:34:17 2002
@@ -47,7 +47,6 @@
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/completion.h>
-#include <linux/compiler.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -210,7 +209,7 @@
 		struct buffer_head * bh = next;
 		next = bh->b_next_free;
 
-		if (dev && bh->b_dev != dev)
+		if (dev != NODEV && bh->b_dev != dev)
 			continue;
 		if (test_and_set_bit(BH_Lock, &bh->b_state))
 			continue;
@@ -267,7 +266,7 @@
 				__refile_buffer(bh);
 			continue;
 		}
-		if (dev && bh->b_dev != dev)
+		if (dev != NODEV && bh->b_dev != dev)
 			continue;
 
 		get_bh(bh);
@@ -730,15 +729,11 @@
 
 static void free_more_memory(void)
 {
-	zone_t * zone = contig_page_data.node_zonelists[GFP_NOFS & GFP_ZONEMASK].zones[0];
-	
 	balance_dirty();
 	wakeup_bdflush();
-	try_to_free_pages(zone, GFP_NOFS, 0);
+	try_to_free_pages_nozone(GFP_NOIO);
 	run_task_queue(&tq_disk);
-	current->policy |= SCHED_YIELD;
-	__set_current_state(TASK_RUNNING);
-	schedule();
+	yield();
 }
 
 void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
@@ -958,8 +953,10 @@
 		struct buffer_head * bh;
 
 		bh = get_hash_table(dev, block, size);
-		if (bh)
+		if (bh) {
+			touch_buffer(bh);
 			return bh;
+		}
 
 		if (!grow_buffers(dev, block, size))
 			free_more_memory();
@@ -1122,7 +1119,6 @@
 	struct buffer_head * bh;
 
 	bh = getblk(dev, block, size);
-	touch_buffer(bh);
 	if (buffer_uptodate(bh))
 		return bh;
 	ll_rw_block(READ, 1, &bh);
@@ -1211,16 +1207,14 @@
 
 void set_bh_page (struct buffer_head *bh, struct page *page, unsigned long offset)
 {
-	bh->b_page = page;
 	if (offset >= PAGE_SIZE)
 		BUG();
-	if (PageHighMem(page))
-		/*
-		 * This catches illegal uses and preserves the offset:
-		 */
-		bh->b_data = (char *)(0 + offset);
-	else
-		bh->b_data = page_address(page) + offset;
+
+	/*
+	 * page_address will return NULL anyways for highmem pages
+	 */
+	bh->b_data = page_address(page) + offset;
+	bh->b_page = page;
 }
 EXPORT_SYMBOL(set_bh_page);
 
diff -urN linux-2.4.20-pre1/fs/cramfs/uncompress.c linux-2.4.20-pre2/fs/cramfs/uncompress.c
--- linux-2.4.20-pre1/fs/cramfs/uncompress.c	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/cramfs/uncompress.c	Mon Aug 12 16:34:17 2002
@@ -18,7 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/vmalloc.h>
-#include <linux/zlib_fs.h>
+#include <linux/zlib.h>
 
 static z_stream stream;
 static int initialized;
@@ -34,14 +34,14 @@
 	stream.next_out = dst;
 	stream.avail_out = dstlen;
 
-	err = zlib_fs_inflateReset(&stream);
+	err = zlib_inflateReset(&stream);
 	if (err != Z_OK) {
-		printk("zlib_fs_inflateReset error %d\n", err);
-		zlib_fs_inflateEnd(&stream);
-		zlib_fs_inflateInit(&stream);
+		printk("zlib_inflateReset error %d\n", err);
+		zlib_inflateEnd(&stream);
+		zlib_inflateInit(&stream);
 	}
 
-	err = zlib_fs_inflate(&stream, Z_FINISH);
+	err = zlib_inflate(&stream, Z_FINISH);
 	if (err != Z_STREAM_END)
 		goto err;
 	return stream.total_out;
@@ -55,14 +55,14 @@
 int cramfs_uncompress_init(void)
 {
 	if (!initialized++) {
-		stream.workspace = vmalloc(zlib_fs_inflate_workspacesize());
+		stream.workspace = vmalloc(zlib_inflate_workspacesize());
 		if ( !stream.workspace ) {
 			initialized = 0;
 			return -ENOMEM;
 		}
 		stream.next_in = NULL;
 		stream.avail_in = 0;
-		zlib_fs_inflateInit(&stream);
+		zlib_inflateInit(&stream);
 	}
 	return 0;
 }
@@ -70,7 +70,7 @@
 int cramfs_uncompress_exit(void)
 {
 	if (!--initialized) {
-		zlib_fs_inflateEnd(&stream);
+		zlib_inflateEnd(&stream);
 		vfree(stream.workspace);
 	}
 	return 0;
diff -urN linux-2.4.20-pre1/fs/dcache.c linux-2.4.20-pre2/fs/dcache.c
--- linux-2.4.20-pre1/fs/dcache.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/dcache.c	Mon Aug 12 16:34:17 2002
@@ -1251,6 +1251,7 @@
 
 extern void bdev_cache_init(void);
 extern void cdev_cache_init(void);
+extern void iobuf_cache_init(void);
 
 void __init vfs_caches_init(unsigned long mempages)
 {
@@ -1285,4 +1286,5 @@
 	mnt_init(mempages);
 	bdev_cache_init();
 	cdev_cache_init();
+	iobuf_cache_init();
 }
diff -urN linux-2.4.20-pre1/fs/ext2/ioctl.c linux-2.4.20-pre2/fs/ext2/ioctl.c
--- linux-2.4.20-pre1/fs/ext2/ioctl.c	Wed Sep 27 13:41:33 2000
+++ linux-2.4.20-pre2/fs/ext2/ioctl.c	Mon Aug 12 16:34:17 2002
@@ -31,7 +31,7 @@
 			return -EROFS;
 
 		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
-			return -EPERM;
+			return -EACCES;
 
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
diff -urN linux-2.4.20-pre1/fs/ext3/inode.c linux-2.4.20-pre2/fs/ext3/inode.c
--- linux-2.4.20-pre1/fs/ext3/inode.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/ext3/inode.c	Mon Aug 12 16:34:17 2002
@@ -2459,7 +2459,7 @@
 		/* ext3_do_update_inode() does journal_dirty_metadata */
 		brelse(iloc->bh);
 	} else {
-		printk(KERN_EMERG __FUNCTION__ ": called with no handle!\n");
+		printk(KERN_EMERG "%s: called with no handle!\n", __FUNCTION__);
 	}
 	return err;
 }
@@ -2547,7 +2547,8 @@
 	if (current_handle &&
 		current_handle->h_transaction != handle->h_transaction) {
 		/* This task has a transaction open against a different fs */
-		printk(KERN_EMERG __FUNCTION__": transactions do not match!\n");
+		printk(KERN_EMERG "%s: transactions do not match!\n",
+			__FUNCTION__);
 	} else {
 		jbd_debug(5, "marking dirty.  outer handle=%p\n",
 				current_handle);
diff -urN linux-2.4.20-pre1/fs/ext3/ioctl.c linux-2.4.20-pre2/fs/ext3/ioctl.c
--- linux-2.4.20-pre1/fs/ext3/ioctl.c	Fri Nov  9 14:25:04 2001
+++ linux-2.4.20-pre2/fs/ext3/ioctl.c	Mon Aug 12 16:34:17 2002
@@ -37,7 +37,7 @@
 			return -EROFS;
 
 		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
-			return -EPERM;
+			return -EACCES;
 
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
diff -urN linux-2.4.20-pre1/fs/ext3/super.c linux-2.4.20-pre2/fs/ext3/super.c
--- linux-2.4.20-pre1/fs/ext3/super.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.20-pre2/fs/ext3/super.c	Mon Aug 12 16:34:17 2002
@@ -838,17 +838,16 @@
 
 		list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
 		if (inode->i_nlink) {
-			printk(KERN_DEBUG __FUNCTION__
-				": truncating inode %ld to %Ld bytes\n",
-				inode->i_ino, inode->i_size);
+			printk(KERN_DEBUG "%s: truncating inode %ld to %Ld "
+				"bytes\n", __FUNCTION__, inode->i_ino,
+				inode->i_size);
 			jbd_debug(2, "truncating inode %ld to %Ld bytes\n",
 				  inode->i_ino, inode->i_size);
 			ext3_truncate(inode);
 			nr_truncates++;
 		} else {
-			printk(KERN_DEBUG __FUNCTION__
-				": deleting unreferenced inode %ld\n",
-				inode->i_ino);
+			printk(KERN_DEBUG "%s: deleting unreferenced "
+				"inode %ld\n", __FUNCTION__, inode->i_ino);
 			jbd_debug(2, "deleting unreferenced inode %ld\n",
 				  inode->i_ino);
 			nr_orphans++;
diff -urN linux-2.4.20-pre1/fs/inflate_fs/Makefile linux-2.4.20-pre2/fs/inflate_fs/Makefile
--- linux-2.4.20-pre1/fs/inflate_fs/Makefile	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,33 +0,0 @@
-#
-# This is a modified version of zlib, which does all memory
-# allocation ahead of time.
-#
-# Currently only decompression is supported.
-#
-# Decompression needs to be serialized for each memory
-# allocation.
-#
-#
-# (The upsides of the simplification is that you can't get in
-# any nasty situations wrt memory management, and that the
-# uncompression can be done without blocking on allocation).
-#
-# The modules are named *_fs.o to distinguish from other modified
-# compression libraries, like the one used by ppp.
-#
-# It is expected that when a deflate module is added it will be
-# a separate module in a deflate_fs directory, to avoid having to
-# load the deflate code for readonly filesystems.
-#
-
-O_TARGET    := inflate_fs.o
-
-export-objs := inflate_syms.o
-
-obj-y := adler32.o infblock.o infcodes.o inffast.o inflate.o \
-	 inftrees.o infutil.o inflate_syms.o
-obj-m := $(O_TARGET)
-
-EXTRA_CFLAGS += -I $(TOPDIR)/fs/inflate_fs
-
-include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/fs/inflate_fs/adler32.c linux-2.4.20-pre2/fs/inflate_fs/adler32.c
--- linux-2.4.20-pre1/fs/inflate_fs/adler32.c	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/adler32.c	Wed Dec 31 16:00:00 1969
@@ -1,48 +0,0 @@
-/* adler32.c -- compute the Adler-32 checksum of a data stream
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* @(#) $Id$ */
-
-#include <linux/zlib_fs.h>
-
-#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,i)  {s1 += buf[i]; s2 += s1;}
-#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf)   DO8(buf,0); DO8(buf,8);
-
-/* ========================================================================= */
-uLong ZEXPORT zlib_fs_adler32(adler, buf, len)
-    uLong adler;
-    const 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);
-	    buf += 16;
-            k -= 16;
-        }
-        if (k != 0) do {
-            s1 += *buf++;
-	    s2 += s1;
-        } while (--k);
-        s1 %= BASE;
-        s2 %= BASE;
-    }
-    return (s2 << 16) | s1;
-}
diff -urN linux-2.4.20-pre1/fs/inflate_fs/infblock.c linux-2.4.20-pre2/fs/inflate_fs/infblock.c
--- linux-2.4.20-pre1/fs/inflate_fs/infblock.c	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/infblock.c	Wed Dec 31 16:00:00 1969
@@ -1,355 +0,0 @@
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "infblock.h"
-#include "inftrees.h"
-#include "infcodes.h"
-#include "infutil.h"
-
-struct inflate_codes_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* Table for deflate from PKZIP's appnote.txt. */
-local const 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.
- */
-
-
-void zlib_fs_inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  if (c != Z_NULL)
-    *c = s->check;
-  if (s->mode == CODES)
-    zlib_fs_inflate_codes_free(s->sub.decode.codes, z);
-  s->mode = TYPE;
-  s->bitk = 0;
-  s->bitb = 0;
-  s->read = s->write = s->window;
-  if (s->checkfn != Z_NULL)
-    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
-}
-
-inflate_blocks_statef *zlib_fs_inflate_blocks_new(z, c, w)
-z_streamp z;
-check_func c;
-uInt w;
-{
-  inflate_blocks_statef *s;
-
-  s = &WS(z)->working_blocks_state;
-  s->hufts = WS(z)->working_hufts;
-  s->window = WS(z)->working_window;
-  s->end = s->window + w;
-  s->checkfn = c;
-  s->mode = TYPE;
-  zlib_fs_inflate_blocks_reset(s, z, Z_NULL);
-  return s;
-}
-
-
-int zlib_fs_inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_streamp 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 */
-          DUMPBITS(3)
-          t = k & 7;                    /* go to byte boundary */
-          DUMPBITS(t)
-          s->mode = LENS;               /* get length of stored block */
-          break;
-        case 1:                         /* fixed */
-          {
-            uInt bl, bd;
-            inflate_huft *tl, *td;
-
-            zlib_fs_inflate_trees_fixed(&bl, &bd, &tl, &td, z);
-            s->sub.decode.codes = zlib_fs_inflate_codes_new(bl, bd, tl, td, z);
-            if (s->sub.decode.codes == Z_NULL)
-            {
-              r = Z_MEM_ERROR;
-              LEAVE
-            }
-          }
-          DUMPBITS(3)
-          s->mode = CODES;
-          break;
-        case 2:                         /* dynamic */
-          DUMPBITS(3)
-          s->mode = TABLE;
-          break;
-        case 3:                         /* illegal */
-          DUMPBITS(3)
-          s->mode = B_BAD;
-          z->msg = (char*)"invalid block type";
-          r = Z_DATA_ERROR;
-          LEAVE
-      }
-      break;
-    case LENS:
-      NEEDBITS(32)
-      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-      {
-        s->mode = B_BAD;
-        z->msg = (char*)"invalid stored block lengths";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-      s->sub.left = (uInt)b & 0xffff;
-      b = k = 0;                      /* dump bits */
-      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
-      break;
-    case STORED:
-      if (n == 0)
-        LEAVE
-      NEEDOUT
-      t = s->sub.left;
-      if (t > n) t = n;
-      if (t > m) t = m;
-      memcpy(q, p, t);
-      p += t;  n -= t;
-      q += t;  m -= t;
-      if ((s->sub.left -= t) != 0)
-        break;
-      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 = B_BAD;
-        z->msg = (char*)"too many length or distance symbols";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-#endif
-      {
-      	s->sub.trees.blens = WS(z)->working_blens;
-      }
-      DUMPBITS(14)
-      s->sub.trees.index = 0;
-      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 = zlib_fs_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
-                             &s->sub.trees.tb, s->hufts, z);
-      if (t != Z_OK)
-      {
-        r = t;
-        if (r == Z_DATA_ERROR)
-          s->mode = B_BAD;
-        LEAVE
-      }
-      s->sub.trees.index = 0;
-      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 & zlib_fs_inflate_mask[t]);
-        t = h->bits;
-        c = h->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 & zlib_fs_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 = B_BAD;
-            z->msg = (char*)"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;
-        }
-      }
-      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 = zlib_fs_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
-                                  s->sub.trees.blens, &bl, &bd, &tl, &td,
-                                  s->hufts, z);
-        if (t != Z_OK)
-        {
-          if (t == (uInt)Z_DATA_ERROR)
-            s->mode = B_BAD;
-          r = t;
-          LEAVE
-        }
-        if ((c = zlib_fs_inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
-        {
-          r = Z_MEM_ERROR;
-          LEAVE
-        }
-        s->sub.decode.codes = c;
-      }
-      s->mode = CODES;
-    case CODES:
-      UPDATE
-      if ((r = zlib_fs_inflate_codes(s, z, r)) != Z_STREAM_END)
-        return zlib_fs_inflate_flush(s, z, r);
-      r = Z_OK;
-      zlib_fs_inflate_codes_free(s->sub.decode.codes, z);
-      LOAD
-      if (!s->last)
-      {
-        s->mode = TYPE;
-        break;
-      }
-      s->mode = DRY;
-    case DRY:
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      s->mode = B_DONE;
-    case B_DONE:
-      r = Z_STREAM_END;
-      LEAVE
-    case B_BAD:
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-int zlib_fs_inflate_blocks_free(s, z)
-inflate_blocks_statef *s;
-z_streamp z;
-{
-  zlib_fs_inflate_blocks_reset(s, z, Z_NULL);
-  return Z_OK;
-}
-
-
-void zlib_fs_inflate_set_dictionary(s, d, n)
-inflate_blocks_statef *s;
-const Bytef *d;
-uInt  n;
-{
-  memcpy(s->window, d, n);
-  s->read = s->write = s->window + n;
-}
-
-
-/* Returns true if inflate is currently at the end of a block generated
- * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
- * IN assertion: s != Z_NULL
- */
-int zlib_fs_inflate_blocks_sync_point(s)
-inflate_blocks_statef *s;
-{
-  return s->mode == LENS;
-}
diff -urN linux-2.4.20-pre1/fs/inflate_fs/infblock.h linux-2.4.20-pre2/fs/inflate_fs/infblock.h
--- linux-2.4.20-pre1/fs/inflate_fs/infblock.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/infblock.h	Wed Dec 31 16:00:00 1969
@@ -1,44 +0,0 @@
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1998 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.
- */
-
-#ifndef _INFBLOCK_H
-#define _INFBLOCK_H
-
-struct inflate_blocks_state;
-typedef struct inflate_blocks_state FAR inflate_blocks_statef;
-
-extern inflate_blocks_statef * zlib_fs_inflate_blocks_new OF((
-    z_streamp z,
-    check_func c,               /* check function */
-    uInt w));                   /* window size */
-
-extern int zlib_fs_inflate_blocks OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));                      /* initial return code */
-
-extern void zlib_fs_inflate_blocks_reset OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern int zlib_fs_inflate_blocks_free OF((
-    inflate_blocks_statef *,
-    z_streamp));
-
-extern void zlib_fs_inflate_set_dictionary OF((
-    inflate_blocks_statef *s,
-    const Bytef *d,  /* dictionary */
-    uInt  n));       /* dictionary length */
-
-extern int zlib_fs_inflate_blocks_sync_point OF((
-    inflate_blocks_statef *s));
-
-#endif /* _INFBLOCK_H */
diff -urN linux-2.4.20-pre1/fs/inflate_fs/infcodes.c linux-2.4.20-pre2/fs/inflate_fs/infcodes.c
--- linux-2.4.20-pre1/fs/inflate_fs/infcodes.c	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/infcodes.c	Wed Dec 31 16:00:00 1969
@@ -1,204 +0,0 @@
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "inftrees.h"
-#include "infblock.h"
-#include "infcodes.h"
-#include "infutil.h"
-#include "inffast.h"
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-inflate_codes_statef *zlib_fs_inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-z_streamp z;
-{
-  inflate_codes_statef *c;
-
-  c = &WS(z)->working_state;
-  {
-    c->mode = START;
-    c->lbits = (Byte)bl;
-    c->dbits = (Byte)bd;
-    c->ltree = tl;
-    c->dtree = td;
-  }
-  return c;
-}
-
-
-int zlib_fs_inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_streamp 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 = zlib_fs_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 & zlib_fs_inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e == 0)               /* literal */
-      {
-        c->sub.lit = 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 + t->base;
-        break;
-      }
-      if (e & 32)               /* end of block */
-      {
-        c->mode = WASH;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"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 & zlib_fs_inflate_mask[j];
-      DUMPBITS(j)
-      c->sub.code.need = c->dbits;
-      c->sub.code.tree = c->dtree;
-      c->mode = DIST;
-    case DIST:          /* i: get distance next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & zlib_fs_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 + t->base;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"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 & zlib_fs_inflate_mask[j];
-      DUMPBITS(j)
-      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 - (uInt)(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 */
-      if (k > 7)        /* return unused byte, if any */
-      {
-        k -= 8;
-        n++;
-        p--;            /* can always return one */
-      }
-      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
-  }
-#ifdef NEED_DUMMY_RETURN
-  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
-#endif
-}
-
-
-void zlib_fs_inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_streamp z;
-{
-}
diff -urN linux-2.4.20-pre1/fs/inflate_fs/infcodes.h linux-2.4.20-pre2/fs/inflate_fs/infcodes.h
--- linux-2.4.20-pre1/fs/inflate_fs/infcodes.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/infcodes.h	Wed Dec 31 16:00:00 1969
@@ -1,33 +0,0 @@
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1998 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.
- */
-
-#ifndef _INFCODES_H
-#define _INFCODES_H
-
-#include "infblock.h"
-
-struct inflate_codes_state;
-typedef struct inflate_codes_state FAR inflate_codes_statef;
-
-extern inflate_codes_statef *zlib_fs_inflate_codes_new OF((
-    uInt, uInt,
-    inflate_huft *, inflate_huft *,
-    z_streamp ));
-
-extern int zlib_fs_inflate_codes OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-extern void zlib_fs_inflate_codes_free OF((
-    inflate_codes_statef *,
-    z_streamp ));
-
-#endif /* _INFCODES_H */
diff -urN linux-2.4.20-pre1/fs/inflate_fs/inffast.c linux-2.4.20-pre2/fs/inflate_fs/inffast.c
--- linux-2.4.20-pre1/fs/inflate_fs/inffast.c	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/inffast.c	Wed Dec 31 16:00:00 1969
@@ -1,161 +0,0 @@
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "inftrees.h"
-#include "infblock.h"
-#include "infcodes.h"
-#include "infutil.h"
-#include "inffast.h"
-
-struct inflate_codes_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#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 {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
-
-/* 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. */
-
-int zlib_fs_inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-inflate_blocks_statef *s;
-z_streamp 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 = zlib_fs_inflate_mask[bl];
-  md = zlib_fs_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)
-      *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 & zlib_fs_inflate_mask[e]);
-        DUMPBITS(e)
-
-        /* 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 & zlib_fs_inflate_mask[e]);
-            DUMPBITS(e)
-
-            /* 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 - (uInt)(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)
-          {
-            t += t->base;
-            e = (t += ((uInt)b & zlib_fs_inflate_mask[e]))->exop;
-          }
-          else
-          {
-            z->msg = (char*)"invalid distance code";
-            UNGRAB
-            UPDATE
-            return Z_DATA_ERROR;
-          }
-        } while (1);
-        break;
-      }
-      if ((e & 64) == 0)
-      {
-        t += t->base;
-        if ((e = (t += ((uInt)b & zlib_fs_inflate_mask[e]))->exop) == 0)
-        {
-          DUMPBITS(t->bits)
-          *q++ = (Byte)t->base;
-          m--;
-          break;
-        }
-      }
-      else if (e & 32)
-      {
-        UNGRAB
-        UPDATE
-        return Z_STREAM_END;
-      }
-      else
-      {
-        z->msg = (char*)"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;
-}
diff -urN linux-2.4.20-pre1/fs/inflate_fs/inffast.h linux-2.4.20-pre2/fs/inflate_fs/inffast.h
--- linux-2.4.20-pre1/fs/inflate_fs/inffast.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/inffast.h	Wed Dec 31 16:00:00 1969
@@ -1,17 +0,0 @@
-/* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1998 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.
- */
-
-extern int zlib_fs_inflate_fast OF((
-    uInt,
-    uInt,
-    inflate_huft *,
-    inflate_huft *,
-    inflate_blocks_statef *,
-    z_streamp ));
diff -urN linux-2.4.20-pre1/fs/inflate_fs/inffixed.h linux-2.4.20-pre2/fs/inflate_fs/inffixed.h
--- linux-2.4.20-pre1/fs/inflate_fs/inffixed.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/inffixed.h	Wed Dec 31 16:00:00 1969
@@ -1,151 +0,0 @@
-/* inffixed.h -- table for decoding fixed codes
- * Generated automatically by the maketree.c program
- */
-
-/* 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 uInt fixed_bl = 9;
-local uInt fixed_bd = 5;
-local inflate_huft fixed_tl[] = {
-    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
-    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
-    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
-    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
-    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
-    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
-    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
-    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
-    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
-    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
-    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
-    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
-    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
-    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
-    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
-    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
-    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
-    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
-    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
-    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
-    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
-    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
-    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
-    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
-    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
-    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
-    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
-    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
-    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
-    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
-    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
-    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
-    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
-    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
-    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
-    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
-    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
-    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
-    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
-    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
-    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
-    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
-    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
-    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
-    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
-    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
-    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
-    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
-    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
-    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
-    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
-    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
-    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
-    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
-    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
-    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
-    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
-    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
-    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
-    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
-    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
-    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
-    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
-    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
-    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
-    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
-    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
-    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
-    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
-    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
-    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
-    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
-    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
-    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
-    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
-    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
-    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
-    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
-    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
-    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
-    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
-    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
-    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
-    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
-    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
-    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
-    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
-    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
-    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
-    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
-    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
-    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
-    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
-    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
-    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
-    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
-    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
-    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
-    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
-    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
-    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
-    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
-    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
-    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
-    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
-    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
-    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
-    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
-    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
-    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
-    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
-    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
-    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
-    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
-    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
-    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
-    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
-    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
-    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
-    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
-    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
-    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
-    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
-    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
-    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
-    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
-    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
-    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
-  };
-local inflate_huft fixed_td[] = {
-    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
-    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
-    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
-    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
-    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
-    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
-    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
-    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
-  };
diff -urN linux-2.4.20-pre1/fs/inflate_fs/inflate.c linux-2.4.20-pre2/fs/inflate_fs/inflate.c
--- linux-2.4.20-pre1/fs/inflate_fs/inflate.c	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/inflate.c	Wed Dec 31 16:00:00 1969
@@ -1,293 +0,0 @@
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include <linux/module.h>
-#include "zutil.h"
-#include "infblock.h"
-#include "infutil.h"
-
-int ZEXPORT zlib_fs_inflate_workspacesize(void)
-{
-  return sizeof(struct inflate_workspace);
-}
-
-
-int ZEXPORT zlib_fs_inflateReset(z)
-z_streamp z;
-{
-  if (z == Z_NULL || z->state == Z_NULL || z->workspace == 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;
-  zlib_fs_inflate_blocks_reset(z->state->blocks, z, Z_NULL);
-  return Z_OK;
-}
-
-
-int ZEXPORT zlib_fs_inflateEnd(z)
-z_streamp z;
-{
-  if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->blocks != Z_NULL)
-    zlib_fs_inflate_blocks_free(z->state->blocks, z);
-  z->state = Z_NULL;
-  return Z_OK;
-}
-
-
-int ZEXPORT zlib_fs_inflateInit2_(z, w, version, stream_size)
-z_streamp z;
-int w;
-const char *version;
-int stream_size;
-{
-  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-      stream_size != sizeof(z_stream) || z->workspace == Z_NULL)
-      return Z_VERSION_ERROR;
-
-  /* initialize state */
-  if (z == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->msg = Z_NULL;
-  z->state = &WS(z)->internal_state;
-  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)
-  {
-    zlib_fs_inflateEnd(z);
-    return Z_STREAM_ERROR;
-  }
-  z->state->wbits = (uInt)w;
-
-  /* create inflate_blocks state */
-  if ((z->state->blocks =
-      zlib_fs_inflate_blocks_new(z, z->state->nowrap ? Z_NULL : zlib_fs_adler32, (uInt)1 << w))
-      == Z_NULL)
-  {
-    zlib_fs_inflateEnd(z);
-    return Z_MEM_ERROR;
-  }
-
-  /* reset state */
-  zlib_fs_inflateReset(z);
-  return Z_OK;
-}
-
-
-int ZEXPORT zlib_fs_inflateInit_(z, version, stream_size)
-z_streamp z;
-const char *version;
-int stream_size;
-{
-  return zlib_fs_inflateInit2_(z, DEF_WBITS, version, stream_size);
-}
-
-#undef NEEDBYTE
-#undef NEXTBYTE
-#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
-#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
-
-int ZEXPORT zlib_fs_inflate(z, f)
-z_streamp z;
-int f;
-{
-  int r;
-  uInt b;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
-    return Z_STREAM_ERROR;
-  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
-  r = Z_BUF_ERROR;
-  while (1) switch (z->state->mode)
-  {
-    case METHOD:
-      NEEDBYTE
-      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"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 = I_BAD;
-        z->msg = (char*)"invalid window size";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = FLAG;
-    case FLAG:
-      NEEDBYTE
-      b = NEXTBYTE;
-      if (((z->state->sub.method << 8) + b) % 31)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"incorrect header check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      if (!(b & PRESET_DICT))
-      {
-        z->state->mode = BLOCKS;
-        break;
-      }
-      z->state->mode = DICT4;
-    case DICT4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = DICT3;
-    case DICT3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = DICT2;
-    case DICT2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = DICT1;
-    case DICT1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-      z->adler = z->state->sub.check.need;
-      z->state->mode = DICT0;
-      return Z_NEED_DICT;
-    case DICT0:
-      z->state->mode = I_BAD;
-      z->msg = (char*)"need dictionary";
-      z->state->sub.marker = 0;       /* can try inflateSync */
-      return Z_STREAM_ERROR;
-    case BLOCKS:
-      r = zlib_fs_inflate_blocks(z->state->blocks, z, r);
-      if (r == Z_DATA_ERROR)
-      {
-        z->state->mode = I_BAD;
-        z->state->sub.marker = 0;       /* can try inflateSync */
-        break;
-      }
-      if (r == Z_OK)
-        r = f;
-      if (r != Z_STREAM_END)
-        return r;
-      r = f;
-      zlib_fs_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
-      if (z->state->nowrap)
-      {
-        z->state->mode = I_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 = I_BAD;
-        z->msg = (char*)"incorrect data check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = I_DONE;
-    case I_DONE:
-      return Z_STREAM_END;
-    case I_BAD:
-      return Z_DATA_ERROR;
-    default:
-      return Z_STREAM_ERROR;
-  }
-#ifdef NEED_DUMMY_RETURN
-  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
-#endif
-}
-
-
-int ZEXPORT zlib_fs_inflateSync(z)
-z_streamp 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 != I_BAD)
-  {
-    z->state->mode = I_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)
-  {
-    static const Byte mark[4] = {0, 0, 0xff, 0xff};
-    if (*p == mark[m])
-      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;
-  zlib_fs_inflateReset(z);
-  z->total_in = r;  z->total_out = w;
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-
-
-/* Returns true if inflate is currently at the end of a block generated
- * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
- * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
- * but removes the length bytes of the resulting empty stored block. When
- * decompressing, PPP checks that at the end of input packet, inflate is
- * waiting for these length bytes.
- */
-int ZEXPORT zlib_fs_inflateSyncPoint(z)
-z_streamp z;
-{
-  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
-    return Z_STREAM_ERROR;
-  return zlib_fs_inflate_blocks_sync_point(z->state->blocks);
-}
diff -urN linux-2.4.20-pre1/fs/inflate_fs/inflate_syms.c linux-2.4.20-pre2/fs/inflate_fs/inflate_syms.c
--- linux-2.4.20-pre1/fs/inflate_fs/inflate_syms.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/inflate_syms.c	Wed Dec 31 16:00:00 1969
@@ -1,22 +0,0 @@
-/*
- * linux/fs/zlib/inflate_syms.c
- *
- * Exported symbols for the inflate functionality.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/zlib_fs.h>
-
-EXPORT_SYMBOL(zlib_fs_inflate_workspacesize);
-EXPORT_SYMBOL(zlib_fs_inflate);
-EXPORT_SYMBOL(zlib_fs_inflateInit_);
-EXPORT_SYMBOL(zlib_fs_inflateInit2_);
-EXPORT_SYMBOL(zlib_fs_inflateEnd);
-EXPORT_SYMBOL(zlib_fs_inflateSync);
-EXPORT_SYMBOL(zlib_fs_inflateReset);
-EXPORT_SYMBOL(zlib_fs_adler32);
-EXPORT_SYMBOL(zlib_fs_inflateSyncPoint);
-MODULE_LICENSE("GPL");
diff -urN linux-2.4.20-pre1/fs/inflate_fs/inftrees.c linux-2.4.20-pre2/fs/inflate_fs/inftrees.c
--- linux-2.4.20-pre1/fs/inflate_fs/inftrees.c	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/inftrees.c	Wed Dec 31 16:00:00 1969
@@ -1,391 +0,0 @@
-/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "inftrees.h"
-#include "infutil.h"
-
-static const char inflate_copyright[] =
-   " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-struct internal_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#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 */
-    const uIntf *,      /* list of base values for non-simple codes */
-    const uIntf *,      /* list of extra bits for non-simple codes */
-    inflate_huft * FAR*,/* result: starting table */
-    uIntf *,            /* maximum lookup bits (returns actual) */
-    inflate_huft *,     /* space for trees */
-    uInt *,             /* hufts used in space */
-    uIntf * ));         /* space for values */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-local const uInt cplens[31] = { /* 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};
-        /* see note #13 above about 258 */
-local const uInt cplext[31] = { /* 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, 112, 112}; /* 112==invalid */
-local const uInt cpdist[30] = { /* 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 const uInt cpdext[30] = { /* 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 */
-
-local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
-uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
-uInt n;                 /* number of codes (assumed <= 288) */
-uInt s;                 /* number of simple-valued codes (0..s-1) */
-const uIntf *d;         /* list of base values for non-simple codes */
-const uIntf *e;         /* list of extra bits for non-simple codes */
-inflate_huft * FAR *t;  /* result: starting table */
-uIntf *m;               /* maximum lookup bits, returns actual */
-inflate_huft *hp;       /* space for trees */
-uInt *hn;               /* hufts used in space */
-uIntf *v;               /* working area: values in order of bit length */
-/* 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 (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) */
-  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
-  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 */
-  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);
-  n = x[g];                     /* set n to length of v */
-
-
-  /* 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 = g - w;
-        z = z > (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 new table */
-        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
-          return Z_MEM_ERROR;   /* not enough memory */
-        u[h] = q = hp + *hn;
-        *hn += z;
-
-        /* 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 */
-          j = i >> (w - l);
-          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
-          u[h-1][j] = r;        /* connect to last table */
-        }
-        else
-          *t = q;               /* first table is returned result */
-      }
-
-      /* 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 */
-      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
-      while ((i & mask) != x[h])
-      {
-        h--;                    /* don't need to update q */
-        w -= l;
-        mask = (1 << w) - 1;
-      }
-    }
-  }
-
-
-  /* Return Z_BUF_ERROR if we were given an incomplete table */
-  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-}
-
-
-int zlib_fs_inflate_trees_bits(c, bb, tb, hp, z)
-uIntf *c;               /* 19 code lengths */
-uIntf *bb;              /* bits tree desired/actual depth */
-inflate_huft * FAR *tb; /* bits tree result */
-inflate_huft *hp;       /* space for trees */
-z_streamp z;            /* for messages */
-{
-  int r;
-  uInt hn = 0;          /* hufts used in space */
-  uIntf *v;             /* work area for huft_build */
-  
-  v = WS(z)->tree_work_area_1;
-  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
-                 tb, bb, hp, &hn, v);
-  if (r == Z_DATA_ERROR)
-    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
-  else if (r == Z_BUF_ERROR || *bb == 0)
-  {
-    z->msg = (char*)"incomplete dynamic bit lengths tree";
-    r = Z_DATA_ERROR;
-  }
-  return r;
-}
-
-int zlib_fs_inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, 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 */
-inflate_huft *hp;       /* space for trees */
-z_streamp z;            /* for messages */
-{
-  int r;
-  uInt hn = 0;          /* hufts used in space */
-  uIntf *v;             /* work area for huft_build */
-
-  /* allocate work area */
-  v = WS(z)->tree_work_area_2;
-
-  /* build literal/length tree */
-  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
-  if (r != Z_OK || *bl == 0)
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed literal/length tree";
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"incomplete literal/length tree";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-  }
-
-  /* build distance tree */
-  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
-  if (r != Z_OK || (*bd == 0 && nl > 257))
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed distance tree";
-    else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
-      r = Z_OK;
-    }
-#else
-      z->msg = (char*)"incomplete distance tree";
-      r = Z_DATA_ERROR;
-    }
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"empty distance tree with lengths";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-#endif
-  }
-
-  /* done */
-  return Z_OK;
-}
-
-
-/* build fixed tables only once--keep them here */
-#include "inffixed.h"
-
-
-int zlib_fs_inflate_trees_fixed(bl, bd, tl, td, z)
-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_streamp z;             /* for memory allocation */
-{
-  *bl = fixed_bl;
-  *bd = fixed_bd;
-  *tl = fixed_tl;
-  *td = fixed_td;
-  return Z_OK;
-}
diff -urN linux-2.4.20-pre1/fs/inflate_fs/inftrees.h linux-2.4.20-pre2/fs/inflate_fs/inftrees.h
--- linux-2.4.20-pre1/fs/inflate_fs/inftrees.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/inftrees.h	Wed Dec 31 16:00:00 1969
@@ -1,63 +0,0 @@
-/* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1998 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). */
-
-#ifndef _INFTREES_H
-#define _INFTREES_H
-
-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 pad;           /* pad structure to a power of 2 (4 bytes for */
-  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
-  uInt base;            /* literal, length base, distance base,
-                           or table offset */
-};
-
-/* Maximum size of dynamic tree.  The maximum found in a long but non-
-   exhaustive search was 1004 huft structures (850 for length/literals
-   and 154 for distances, the latter actually the result of an
-   exhaustive search).  The actual maximum is not known, but the
-   value below is more than safe. */
-#define MANY 1440
-
-extern int zlib_fs_inflate_trees_bits OF((
-    uIntf *,                    /* 19 code lengths */
-    uIntf *,                    /* bits tree desired/actual depth */
-    inflate_huft * FAR *,       /* bits tree result */
-    inflate_huft *,             /* space for trees */
-    z_streamp));                /* for messages */
-
-extern int zlib_fs_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 */
-    inflate_huft *,             /* space for trees */
-    z_streamp));                /* for messages */
-
-extern int zlib_fs_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 */
-    z_streamp));                /* for memory allocation */
-
-#endif /* _INFTREES_H */
diff -urN linux-2.4.20-pre1/fs/inflate_fs/infutil.c linux-2.4.20-pre2/fs/inflate_fs/infutil.c
--- linux-2.4.20-pre1/fs/inflate_fs/infutil.c	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/infutil.c	Wed Dec 31 16:00:00 1969
@@ -1,87 +0,0 @@
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include "zutil.h"
-#include "infblock.h"
-#include "inftrees.h"
-#include "infcodes.h"
-#include "infutil.h"
-
-struct inflate_codes_state;
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt zlib_fs_inflate_mask[17] = {
-    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 */
-int zlib_fs_inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt n;
-  Bytef *p;
-  Bytef *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)
-    z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-  /* copy as far as end of window */
-  memcpy(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)
-      z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-    /* copy */
-    memcpy(p, q, n);
-    p += n;
-    q += n;
-  }
-
-  /* update pointers */
-  z->next_out = p;
-  s->read = q;
-
-  /* done */
-  return r;
-}
diff -urN linux-2.4.20-pre1/fs/inflate_fs/infutil.h linux-2.4.20-pre2/fs/inflate_fs/infutil.h
--- linux-2.4.20-pre1/fs/inflate_fs/infutil.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/infutil.h	Wed Dec 31 16:00:00 1969
@@ -1,197 +0,0 @@
-/* infutil.h -- types and macros common to blocks and codes
- * Copyright (C) 1995-1998 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.
- */
-
-#ifndef _INFUTIL_H
-#define _INFUTIL_H
-
-#include "zconf.h"
-#include "inftrees.h"
-#include "infcodes.h"
-
-typedef 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 */
-      B_DONE,   /* finished last block, done */
-      B_BAD}    /* got a data error--stuck here */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
-  /* mode */
-  inflate_block_mode  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 */
-    } trees;            /* if DTREE, decoding info for trees */
-    struct {
-      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 */
-  inflate_huft *hufts;  /* single malloc for tree space */
-  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 zlib_fs_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 (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=zlib_fs_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}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt zlib_fs_inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int zlib_fs_inflate_flush OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-/* inflate private state */
-typedef enum {
-      METHOD,   /* waiting for method byte */
-      FLAG,     /* waiting for flag byte */
-      DICT4,    /* four dictionary check bytes to go */
-      DICT3,    /* three dictionary check bytes to go */
-      DICT2,    /* two dictionary check bytes to go */
-      DICT1,    /* one dictionary check byte to go */
-      DICT0,    /* waiting for inflateSetDictionary */
-      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 */
-      I_DONE,   /* finished check, done */
-      I_BAD}    /* got an error--stay here */
-inflate_mode;
-
-struct internal_state {
-
-  /* mode */
-  inflate_mode  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 */
-
-};
-
-/* inflate codes private state */
-typedef 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 */
-inflate_codes_mode;
-
-struct inflate_codes_state {
-
-  /* mode */
-  inflate_codes_mode 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 */
-
-};
-
-/* memory allocation for inflation */
-
-struct inflate_workspace {
-	inflate_codes_statef working_state;
-	struct inflate_blocks_state working_blocks_state;
-	struct internal_state internal_state;
-	unsigned int tree_work_area_1[19];
-	unsigned int tree_work_area_2[288];
-	unsigned working_blens[258 + 0x1f + 0x1f];
-	inflate_huft working_hufts[MANY];
-	unsigned char working_window[1 << MAX_WBITS];
-};
-
-#define WS(z) ((struct inflate_workspace *)(z->workspace))
-
-#endif
diff -urN linux-2.4.20-pre1/fs/inflate_fs/zconf.h linux-2.4.20-pre2/fs/inflate_fs/zconf.h
--- linux-2.4.20-pre1/fs/inflate_fs/zconf.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/zconf.h	Wed Dec 31 16:00:00 1969
@@ -1,90 +0,0 @@
-/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-1998 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* @(#) $Id$ */
-
-#ifndef _ZCONF_H
-#define _ZCONF_H
-
-#if defined(__GNUC__) || defined(__386__) || defined(i386)
-#  ifndef __32BIT__
-#    define __32BIT__
-#  endif
-#endif
-
-#if defined(__STDC__) || defined(__cplusplus)
-#  ifndef STDC
-#    define STDC
-#  endif
-#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.
-*/
-
-/* Maximum value for memLevel in deflateInit2 */
-#ifndef MAX_MEM_LEVEL
-#  define MAX_MEM_LEVEL 9
-#endif
-
-/* Maximum value for windowBits in deflateInit2 and inflateInit2.
- * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
- * created by gzip. (Files created by minigzip can still be extracted by
- * gzip.)
- */
-#ifndef MAX_WBITS
-#  define MAX_WBITS   15 /* 32K LZ77 window */
-#endif
-
-                        /* Type declarations */
-
-#ifndef OF /* function prototypes */
-#  ifdef STDC
-#    define OF(args)  args
-#  else
-#    define OF(args)  ()
-#  endif
-#endif
-
-#ifndef ZEXPORT
-#  define ZEXPORT
-#endif
-#ifndef ZEXPORTVA
-#  define ZEXPORTVA
-#endif
-#ifndef ZEXTERN
-#  define ZEXTERN extern
-#endif
-#ifndef FAR
-#   define FAR
-#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;
-
-typedef void FAR *voidpf;
-typedef void     *voidp;
-
-#include <linux/types.h> /* for off_t */
-#include <linux/unistd.h>    /* for SEEK_* and off_t */
-#define z_off_t  off_t
-
-#endif /* _ZCONF_H */
diff -urN linux-2.4.20-pre1/fs/inflate_fs/zutil.h linux-2.4.20-pre2/fs/inflate_fs/zutil.h
--- linux-2.4.20-pre1/fs/inflate_fs/zutil.h	Thu Oct 25 13:53:53 2001
+++ linux-2.4.20-pre2/fs/inflate_fs/zutil.h	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
-/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-1998 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.
- */
-
-/* @(#) $Id: zutil.h,v 1.1 2000/01/01 03:32:23 davem Exp $ */
-
-#ifndef _Z_UTIL_H
-#define _Z_UTIL_H
-
-#include <linux/zlib_fs.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-typedef unsigned char  uch;
-typedef uch FAR uchf;
-typedef unsigned short ush;
-typedef ush FAR ushf;
-typedef unsigned long  ulg;
-
-        /* common constants */
-
-#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 */
-
-#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
-
-        /* target dependencies */
-
-        /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03  /* assume Unix */
-#endif
-
-         /* functions */
-
-typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
-				       uInt len));
-
-#endif /* _Z_UTIL_H */
diff -urN linux-2.4.20-pre1/fs/iobuf.c linux-2.4.20-pre2/fs/iobuf.c
--- linux-2.4.20-pre1/fs/iobuf.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/iobuf.c	Mon Aug 12 16:34:17 2002
@@ -10,6 +10,9 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 
+
+static kmem_cache_t *kiobuf_cachep;
+
 void end_kio_request(struct kiobuf *kiobuf, int uptodate)
 {
 	if ((!uptodate) && !kiobuf->errno)
@@ -22,39 +25,67 @@
 	}
 }
 
-static void kiobuf_init(struct kiobuf *iobuf)
+static int kiobuf_init(struct kiobuf *iobuf)
 {
 	init_waitqueue_head(&iobuf->wait_queue);
-	iobuf->array_len = KIO_STATIC_PAGES;
-	iobuf->maplist = iobuf->map_array;
+	iobuf->array_len = 0;
 	iobuf->nr_pages = 0;
 	iobuf->locked = 0;
+	iobuf->bh = NULL;
+	iobuf->blocks = NULL;
 	atomic_set(&iobuf->io_count, 0);
 	iobuf->end_io = NULL;
+	return expand_kiobuf(iobuf, KIO_STATIC_PAGES);
 }
 
 int alloc_kiobuf_bhs(struct kiobuf * kiobuf)
 {
 	int i;
 
-	for (i = 0; i < KIO_MAX_SECTORS; i++)
-		if (!(kiobuf->bh[i] = kmem_cache_alloc(bh_cachep, SLAB_KERNEL))) {
-			while (i--) {
-				kmem_cache_free(bh_cachep, kiobuf->bh[i]);
-				kiobuf->bh[i] = NULL;
-			}
-			return -ENOMEM;
-		}
+	kiobuf->blocks =
+		kmalloc(sizeof(*kiobuf->blocks) * KIO_MAX_SECTORS, GFP_KERNEL);
+	if (unlikely(!kiobuf->blocks))
+		goto nomem;
+	kiobuf->bh =
+		kmalloc(sizeof(*kiobuf->bh) * KIO_MAX_SECTORS, GFP_KERNEL);
+	if (unlikely(!kiobuf->bh))
+		goto nomem;
+
+	for (i = 0; i < KIO_MAX_SECTORS; i++) {
+		kiobuf->bh[i] = kmem_cache_alloc(bh_cachep, GFP_KERNEL);
+		if (unlikely(!kiobuf->bh[i]))
+			goto nomem2;
+	}
+
 	return 0;
+
+nomem2:
+	while (i--) {
+		kmem_cache_free(bh_cachep, kiobuf->bh[i]);
+		kiobuf->bh[i] = NULL;
+	}
+	memset(kiobuf->bh, 0, sizeof(*kiobuf->bh) * KIO_MAX_SECTORS);
+
+nomem:
+	free_kiobuf_bhs(kiobuf);
+	return -ENOMEM;
 }
 
 void free_kiobuf_bhs(struct kiobuf * kiobuf)
 {
 	int i;
 
-	for (i = 0; i < KIO_MAX_SECTORS; i++) {
-		kmem_cache_free(bh_cachep, kiobuf->bh[i]);
-		kiobuf->bh[i] = NULL;
+	if (kiobuf->bh) {
+		for (i = 0; i < KIO_MAX_SECTORS; i++)
+			if (kiobuf->bh[i])
+				kmem_cache_free(bh_cachep, kiobuf->bh[i]);
+		kfree(kiobuf->bh);
+		kiobuf->bh = NULL;
+	}
+
+	if (kiobuf->blocks) {
+		kfree(kiobuf->blocks);
+		kiobuf->blocks = NULL;
 	}
 }
 
@@ -64,21 +95,23 @@
 	struct kiobuf *iobuf;
 	
 	for (i = 0; i < nr; i++) {
-		iobuf = vmalloc(sizeof(struct kiobuf));
-		if (!iobuf) {
-			free_kiovec(i, bufp);
-			return -ENOMEM;
-		}
-		kiobuf_init(iobuf);
- 		if (alloc_kiobuf_bhs(iobuf)) {
-			vfree(iobuf);
- 			free_kiovec(i, bufp);
- 			return -ENOMEM;
- 		}
+		iobuf = kmem_cache_alloc(kiobuf_cachep, GFP_KERNEL);
+		if (unlikely(!iobuf))
+			goto nomem;
+		if (unlikely(kiobuf_init(iobuf)))
+			goto nomem2;
+ 		if (unlikely(alloc_kiobuf_bhs(iobuf)))
+			goto nomem2;
 		bufp[i] = iobuf;
 	}
 	
 	return 0;
+
+nomem2:
+	kmem_cache_free(kiobuf_cachep, iobuf);
+nomem:
+	free_kiovec(i, bufp);
+	return -ENOMEM;
 }
 
 void free_kiovec(int nr, struct kiobuf **bufp) 
@@ -90,10 +123,9 @@
 		iobuf = bufp[i];
 		if (iobuf->locked)
 			unlock_kiovec(1, &iobuf);
-		if (iobuf->array_len > KIO_STATIC_PAGES)
-			kfree (iobuf->maplist);
+		kfree(iobuf->maplist);
 		free_kiobuf_bhs(iobuf);
-		vfree(bufp[i]);
+		kmem_cache_free(kiobuf_cachep, bufp[i]);
 	}
 }
 
@@ -104,28 +136,26 @@
 	if (iobuf->array_len >= wanted)
 		return 0;
 	
-	maplist = (struct page **) 
-		kmalloc(wanted * sizeof(struct page **), GFP_KERNEL);
-	if (!maplist)
+	maplist = kmalloc(wanted * sizeof(struct page **), GFP_KERNEL);
+	if (unlikely(!maplist))
 		return -ENOMEM;
 
 	/* Did it grow while we waited? */
-	if (iobuf->array_len >= wanted) {
+	if (unlikely(iobuf->array_len >= wanted)) {
 		kfree(maplist);
 		return 0;
 	}
-	
-	memcpy (maplist, iobuf->maplist, iobuf->array_len * sizeof(struct page **));
 
-	if (iobuf->array_len > KIO_STATIC_PAGES)
-		kfree (iobuf->maplist);
+	if (iobuf->array_len) {
+		memcpy(maplist, iobuf->maplist, iobuf->array_len * sizeof(*maplist));
+		kfree(iobuf->maplist);
+	}
 	
 	iobuf->maplist   = maplist;
 	iobuf->array_len = wanted;
 	return 0;
 }
 
-
 void kiobuf_wait_for_io(struct kiobuf *kiobuf)
 {
 	struct task_struct *tsk = current;
@@ -147,5 +177,10 @@
 	remove_wait_queue(&kiobuf->wait_queue, &wait);
 }
 
-
-
+void __init iobuf_cache_init(void)
+{
+	kiobuf_cachep = kmem_cache_create("kiobuf", sizeof(struct kiobuf),
+					  0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!kiobuf_cachep)
+		panic("Cannot create kiobuf SLAB cache");
+}
diff -urN linux-2.4.20-pre1/fs/isofs/compress.c linux-2.4.20-pre2/fs/isofs/compress.c
--- linux-2.4.20-pre1/fs/isofs/compress.c	Tue Nov  6 08:34:40 2001
+++ linux-2.4.20-pre2/fs/isofs/compress.c	Mon Aug 12 16:34:17 2002
@@ -36,7 +36,7 @@
 #include <linux/smp_lock.h>
 #include <linux/blkdev.h>
 #include <linux/vmalloc.h>
-#include <linux/zlib_fs.h>
+#include <linux/zlib.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -209,7 +209,7 @@
 		stream.workspace = zisofs_zlib_workspace;
 		down(&zisofs_zlib_semaphore);
 		
-		zerr = zlib_fs_inflateInit(&stream);
+		zerr = zlib_inflateInit(&stream);
 		if ( zerr != Z_OK ) {
 			if ( err && zerr == Z_MEM_ERROR )
 				err = -ENOMEM;
@@ -250,7 +250,7 @@
 					}
 				}
 				ao = stream.avail_out;  ai = stream.avail_in;
-				zerr = zlib_fs_inflate(&stream, Z_SYNC_FLUSH);
+				zerr = zlib_inflate(&stream, Z_SYNC_FLUSH);
 				left_out = stream.avail_out;
 				if ( zerr == Z_BUF_ERROR && stream.avail_in == 0 )
 					continue;
@@ -291,7 +291,7 @@
 				fpage++;
 			}
 		}
-		zlib_fs_inflateEnd(&stream);
+		zlib_inflateEnd(&stream);
 
 	z_eio:
 		up(&zisofs_zlib_semaphore);
@@ -339,7 +339,7 @@
 		return 0;
 	}
 
-	zisofs_zlib_workspace = vmalloc(zlib_fs_inflate_workspacesize());
+	zisofs_zlib_workspace = vmalloc(zlib_inflate_workspacesize());
 	if ( !zisofs_zlib_workspace )
 		return -ENOMEM;
 	init_MUTEX(&zisofs_zlib_semaphore);
diff -urN linux-2.4.20-pre1/fs/jbd/journal.c linux-2.4.20-pre2/fs/jbd/journal.c
--- linux-2.4.20-pre1/fs/jbd/journal.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/jbd/journal.c	Mon Aug 12 16:34:17 2002
@@ -459,9 +459,9 @@
 	do {
 		new_bh = get_unused_buffer_head(0);
 		if (!new_bh) {
-			printk (KERN_NOTICE __FUNCTION__
-				": ENOMEM at get_unused_buffer_head, "
-				"trying again.\n");
+			printk (KERN_NOTICE "%s: ENOMEM at "
+				"get_unused_buffer_head, trying again.\n",
+				__FUNCTION__);
 			current->policy |= SCHED_YIELD;
 			schedule();
 		}
@@ -588,9 +588,8 @@
 #ifdef CONFIG_JBD_DEBUG
 	lock_journal(journal);
 	if (!tid_geq(journal->j_commit_request, tid)) {
-		printk(KERN_EMERG __FUNCTION__
-			": error: j_commit_request=%d, tid=%d\n",
-			journal->j_commit_request, tid);
+		printk(KERN_EMERG "%s: error: j_commit_request=%d, tid=%d\n",
+			__FUNCTION__, journal->j_commit_request, tid);
 	}
 	unlock_journal(journal);
 #endif
@@ -639,9 +638,8 @@
 		if (ret)
 			*retp = ret;
 		else {
-			printk (KERN_ALERT __FUNCTION__ 
-				": journal block not found "
-				"at offset %lu on %s\n",
+			printk (KERN_ALERT "%s: journal block not found "
+				"at offset %lu on %s\n", __FUNCTION__,
 				blocknr, bdevname(journal->j_dev));
 			err = -EIO;
 			__journal_abort_soft(journal, err);
@@ -788,8 +786,8 @@
 	err = journal_bmap(journal, 0, &blocknr);
 	/* If that failed, give up */
 	if (err) {
-		printk(KERN_ERR __FUNCTION__ ": Cannnot locate journal "
-		       "superblock\n");
+		printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
+			__FUNCTION__);
 		kfree(journal);
 		return NULL;
 	}
@@ -875,8 +873,8 @@
 		/*
 		 * We don't know what block to start at!
 		 */
-		printk(KERN_EMERG __FUNCTION__
-			": creation of journal on external device!\n");
+		printk(KERN_EMERG "%s: creation of journal on external "
+			"device!\n", __FUNCTION__);
 		BUG();
 	}
 
@@ -1597,8 +1595,8 @@
 	if (ret == 0) {
 		jbd_debug(1, "out of memory for journal_head\n");
 		if (time_after(jiffies, last_warning + 5*HZ)) {
-			printk(KERN_NOTICE "ENOMEM in " __FUNCTION__
-			       ", retrying.\n");
+			printk(KERN_NOTICE "ENOMEM in %s, retrying.\n",
+				__FUNCTION__);
 			last_warning = jiffies;
 		}
 		while (ret == 0) {
diff -urN linux-2.4.20-pre1/fs/jbd/transaction.c linux-2.4.20-pre2/fs/jbd/transaction.c
--- linux-2.4.20-pre1/fs/jbd/transaction.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.20-pre2/fs/jbd/transaction.c	Mon Aug 12 16:34:17 2002
@@ -688,8 +688,9 @@
 							    GFP_NOFS);
 				lock_journal(journal);
 				if (!frozen_buffer) {
-					printk(KERN_EMERG __FUNCTION__
-						"OOM for frozen_buffer\n");
+					printk(KERN_EMERG
+						"%s: OOM for frozen_buffer\n",
+						__FUNCTION__);
 					JBUFFER_TRACE(jh, "oom!");
 					error = -ENOMEM;
 					spin_lock(&journal_datalist_lock);
@@ -887,8 +888,8 @@
 		jh->b_committed_data = jbd_kmalloc(jh2bh(jh)->b_size, 
 						   GFP_NOFS);
 		if (!jh->b_committed_data) {
-			printk(KERN_EMERG __FUNCTION__
-				": No memory for committed data!\n");
+			printk(KERN_EMERG "%s: No memory for committed data!\n",
+				__FUNCTION__);
 			err = -ENOMEM;
 			goto out;
 		}
diff -urN linux-2.4.20-pre1/fs/jffs2/Makefile linux-2.4.20-pre2/fs/jffs2/Makefile
--- linux-2.4.20-pre1/fs/jffs2/Makefile	Thu Oct  4 15:13:18 2001
+++ linux-2.4.20-pre2/fs/jffs2/Makefile	Mon Aug 12 16:34:17 2002
@@ -11,7 +11,7 @@
 
 
 COMPR_OBJS	:= compr.o compr_rubin.o compr_rtime.o pushpull.o \
-			compr_zlib.o zlib.o
+			compr_zlib.o
 JFFS2_OBJS	:= crc32.o dir.o file.o ioctl.o nodelist.o malloc.o \
 	read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
 	symlink.o build.o erase.o background.o
diff -urN linux-2.4.20-pre1/fs/jffs2/compr_zlib.c linux-2.4.20-pre2/fs/jffs2/compr_zlib.c
--- linux-2.4.20-pre1/fs/jffs2/compr_zlib.c	Thu Oct  4 15:13:18 2001
+++ linux-2.4.20-pre2/fs/jffs2/compr_zlib.c	Mon Aug 12 16:34:17 2002
@@ -1,7 +1,7 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
  *
@@ -31,42 +31,22 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: compr_zlib.c,v 1.8 2001/09/20 15:28:31 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.15 2002/03/04 09:35:48 dwmw2 Exp $
  *
  */
 
-#include "zlib.h"
+#ifndef __KERNEL__
+#error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
+#endif
 
-#ifdef __KERNEL__
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/mtd/compatmac.h> /* for min() */
 #include <linux/slab.h>
 #include <linux/jffs2.h>
+#include <linux/zlib.h>
 #include "nodelist.h"
 
-static void *zalloc(void *opaque, unsigned nr, unsigned size)
-{
-	/* How much does it request? Should we use vmalloc? Or be dynamic? */
-	return kmalloc(nr * size, GFP_KERNEL);
-}
-
-static void zfree(void *opaque, void *addr)
-{
-	kfree(addr);
-}
-#else
-#define min(x,y) ((x)<(y)?(x):(y))
-#ifndef D1
-#define D1(x)
-#endif
-#define KERN_DEBUG
-#define KERN_NOTICE
-#define KERN_WARNING
-#define printk printf
-#include <stdio.h>
-#include <asm/types.h>
-#endif
-
 	/* Plan: call deflate() with avail_in == *sourcelen, 
 		avail_out = *dstlen - 12 and flush == Z_FINISH. 
 		If it doesn't manage to finish,	call it again with
@@ -76,8 +56,37 @@
 	*/
 #define STREAM_END_SPACE 12
 
+static DECLARE_MUTEX(deflate_sem);
+static DECLARE_MUTEX(inflate_sem);
+static void *deflate_workspace;
+static void *inflate_workspace;
+
+int __init jffs2_zlib_init(void)
+{
+	deflate_workspace = vmalloc(zlib_deflate_workspacesize());
+	if (!deflate_workspace) {
+		printk("Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
+		return -ENOMEM;
+	}
+	D1(printk("Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
+	inflate_workspace = vmalloc(zlib_inflate_workspacesize());
+	if (!inflate_workspace) {
+		printk("Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
+		vfree(deflate_workspace);
+		return -ENOMEM;
+	}
+	D1(printk("Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
+	return 0;
+}
+
+void __exit jffs2_zlib_exit(void)
+{
+	vfree(deflate_workspace);
+	vfree(inflate_workspace);
+}
+
 int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   __u32 *sourcelen, __u32 *dstlen)
+		   uint32_t *sourcelen, uint32_t *dstlen)
 {
 	z_stream strm;
 	int ret;
@@ -85,18 +94,15 @@
 	if (*dstlen <= STREAM_END_SPACE)
 		return -1;
 
-#ifdef __KERNEL__
-	strm.zalloc = zalloc;
-	strm.zfree = zfree;
-#else
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-#endif
+	down(&deflate_sem);
+	strm.workspace = deflate_workspace;
 
-	if (Z_OK != deflateInit(&strm, 3)) {
+	if (Z_OK != zlib_deflateInit(&strm, 3)) {
 		printk(KERN_WARNING "deflateInit failed\n");
+		up(&deflate_sem);
 		return -1;
 	}
+
 	strm.next_in = data_in;
 	strm.total_in = 0;
 	
@@ -108,52 +114,49 @@
 		strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
 		D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n",
 			  strm.avail_in, strm.avail_out));
-		ret = deflate(&strm, Z_PARTIAL_FLUSH);
+		ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH);
 		D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", 
 			  strm.avail_in, strm.avail_out, strm.total_in, strm.total_out));
 		if (ret != Z_OK) {
 			D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
-			deflateEnd(&strm);
+			zlib_deflateEnd(&strm);
+			up(&deflate_sem);
 			return -1;
 		}
 	}
 	strm.avail_out += STREAM_END_SPACE;
 	strm.avail_in = 0;
-	ret = deflate(&strm, Z_FINISH);
+	ret = zlib_deflate(&strm, Z_FINISH);
+	zlib_deflateEnd(&strm);
+	up(&deflate_sem);
 	if (ret != Z_STREAM_END) {
 		D1(printk(KERN_DEBUG "final deflate returned %d\n", ret));
-		deflateEnd(&strm);
 		return -1;
 	}
-	deflateEnd(&strm);
 
-	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", strm.total_in, strm.total_out));
+	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
+		  strm.total_in, strm.total_out));
 
 	if (strm.total_out >= strm.total_in)
 		return -1;
 
-
 	*dstlen = strm.total_out;
 	*sourcelen = strm.total_in;
 	return 0;
 }
 
 void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      __u32 srclen, __u32 destlen)
+		      uint32_t srclen, uint32_t destlen)
 {
 	z_stream strm;
 	int ret;
 
-#ifdef __KERNEL__
-	strm.zalloc = zalloc;
-	strm.zfree = zfree;
-#else
-	strm.zalloc = (void *)0;
-	strm.zfree = (void *)0;
-#endif
+	down(&inflate_sem);
+	strm.workspace = inflate_workspace;
 
-	if (Z_OK != inflateInit(&strm)) {
+	if (Z_OK != zlib_inflateInit(&strm)) {
 		printk(KERN_WARNING "inflateInit failed\n");
+		up(&inflate_sem);
 		return;
 	}
 	strm.next_in = data_in;
@@ -164,10 +167,11 @@
 	strm.avail_out = destlen;
 	strm.total_out = 0;
 
-	while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
+	while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK)
 		;
 	if (ret != Z_STREAM_END) {
 		printk(KERN_NOTICE "inflate returned %d\n", ret);
 	}
-	inflateEnd(&strm);
+	zlib_inflateEnd(&strm);
+	up(&inflate_sem);
 }
diff -urN linux-2.4.20-pre1/fs/jffs2/nodelist.h linux-2.4.20-pre2/fs/jffs2/nodelist.h
--- linux-2.4.20-pre1/fs/jffs2/nodelist.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/jffs2/nodelist.h	Mon Aug 12 16:34:17 2002
@@ -32,6 +32,7 @@
  * under either the RHEPL or the GPL.
  *
  * $Id: nodelist.h,v 1.46.2.1 2002/02/23 14:04:44 dwmw2 Exp $
+ * + zlib_init calls from v1.65
  *
  */
 
@@ -349,3 +350,7 @@
 void jffs2_erase_pending_blocks(struct jffs2_sb_info *c);
 void jffs2_mark_erased_blocks(struct jffs2_sb_info *c);
 void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
+
+/* compr_zlib.c */
+int jffs2_zlib_init(void);
+void jffs2_zlib_exit(void);
diff -urN linux-2.4.20-pre1/fs/jffs2/scan.c linux-2.4.20-pre2/fs/jffs2/scan.c
--- linux-2.4.20-pre1/fs/jffs2/scan.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/jffs2/scan.c	Mon Aug 12 16:34:17 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: scan.c,v 1.51.2.2 2002/02/23 13:34:31 dwmw2 Exp $
+ * $Id: scan.c,v 1.51.2.3 2002/07/25 20:49:06 dwmw2 Exp $
  *
  */
 #include <linux/kernel.h>
@@ -259,6 +259,16 @@
 			DIRTY_SPACE(4);
 			ofs += 4;
 			continue;
+		}
+
+		if (ofs + node.totlen > jeb->offset + c->sector_size) {
+			/* Eep. Node goes over the end of the erase block. */
+			printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
+			       ofs, node.totlen);
+			printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
+			DIRTY_SPACE(4);
+			ofs += 4;
+			continue;
 		}
 
 		switch(node.nodetype | JFFS2_NODE_ACCURATE) {
diff -urN linux-2.4.20-pre1/fs/jffs2/super.c linux-2.4.20-pre2/fs/jffs2/super.c
--- linux-2.4.20-pre1/fs/jffs2/super.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/jffs2/super.c	Mon Aug 12 16:34:17 2002
@@ -32,6 +32,7 @@
  * under either the RHEPL or the GPL.
  *
  * $Id: super.c,v 1.48.2.2 2002/03/12 15:36:43 dwmw2 Exp $
+ * + zlib_init calls from v1.56
  *
  */
 
@@ -361,6 +362,11 @@
 	}
 #endif
 
+	ret = jffs2_zlib_init();
+	if (ret) {
+		printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
+		return ret;
+	}
 	ret = jffs2_create_slab_caches();
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
@@ -377,6 +383,7 @@
 static void __exit exit_jffs2_fs(void)
 {
 	jffs2_destroy_slab_caches();
+	jffs2_zlib_exit();
 	unregister_filesystem(&jffs2_fs_type);
 }
 
diff -urN linux-2.4.20-pre1/fs/jffs2/zlib.c linux-2.4.20-pre2/fs/jffs2/zlib.c
--- linux-2.4.20-pre1/fs/jffs2/zlib.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/jffs2/zlib.c	Wed Dec 31 16:00:00 1969
@@ -1,5376 +0,0 @@
-/*
- * This file is derived from various .h and .c files from the zlib-1.0.4
- * 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:
- * - added Z_PACKET_FLUSH (see zlib.h for details)
- * - added inflateIncomp and deflateOutputPending
- * - allow strm->next_out to be NULL, meaning discard the output
- *
- * $Id: zlib.c,v 1.3 1997/12/23 10:47:42 paulus Exp $
- */
-
-/* 
- *  ==FILEVERSION 20020318==
- *
- * This marker is used by the Linux installation script to determine
- * whether an up-to-date version of this file is already installed.
- */
-
-#define NO_DUMMY_DECL
-#define NO_ZCFUNCS
-#define MY_ZCALLOC
-
-#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
-#define inflate	inflate_ppp	/* FreeBSD already has an inflate :-( */
-#endif
-
-
-/* +++ zutil.h */
-/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-1996 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.16 1996/07/24 13:41:13 me Exp $ */
-
-#ifndef _Z_UTIL_H
-#define _Z_UTIL_H
-
-#include "zlib.h"
-
-#if defined(KERNEL) || defined(_KERNEL)
-/* Assume this is a *BSD or SVR4 kernel */
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/systm.h>
-#  define HAVE_MEMCPY
-#  define memcpy(d, s, n)	bcopy((s), (d), (n))
-#  define memset(d, v, n)	bzero((d), (n))
-#  define memcmp		bcmp
-
-#else
-#if defined(__KERNEL__)
-/* Assume this is a Linux kernel */
-#include <linux/string.h>
-#define HAVE_MEMCPY
-
-#else /* not kernel */
-
-#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
-#   include <stddef.h>
-#   include <errno.h>
-#else
-    extern int errno;
-#endif
-#ifdef STDC
-#  include <string.h>
-#  include <stdlib.h>
-#endif
-#endif /* __KERNEL__ */
-#endif /* _KERNEL || KERNEL */
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-typedef unsigned char  uch;
-typedef uch FAR uchf;
-typedef unsigned short ush;
-typedef ush FAR ushf;
-typedef unsigned long  ulg;
-
-extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
-/* (size given to avoid silly warnings with Visual C++) */
-
-#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
-
-#define ERR_RETURN(strm,err) \
-  return (strm->msg = (char*)ERR_MSG(err), (err))
-/* To be used only when the state is known to be valid */
-
-        /* common constants */
-
-#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 */
-
-#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
-
-        /* target dependencies */
-
-#ifdef MSDOS
-#  define OS_CODE  0x00
-#  ifdef __TURBOC__
-#    include <alloc.h>
-#  else /* MSC or DJGPP */
-#    include <malloc.h>
-#  endif
-#endif
-
-#ifdef OS2
-#  define OS_CODE  0x06
-#endif
-
-#ifdef WIN32 /* Window 95 & Windows NT */
-#  define OS_CODE  0x0b
-#endif
-
-#if defined(VAXC) || defined(VMS)
-#  define OS_CODE  0x02
-#  define FOPEN(name, mode) \
-     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
-#endif
-
-#ifdef AMIGA
-#  define OS_CODE  0x01
-#endif
-
-#if defined(ATARI) || defined(atarist)
-#  define OS_CODE  0x05
-#endif
-
-#ifdef MACOS
-#  define OS_CODE  0x07
-#endif
-
-#ifdef __50SERIES /* Prime/PRIMOS */
-#  define OS_CODE  0x0F
-#endif
-
-#ifdef TOPS20
-#  define OS_CODE  0x0a
-#endif
-
-#if defined(_BEOS_) || defined(RISCOS)
-#  define fdopen(fd,mode) NULL /* No fdopen() */
-#endif
-
-        /* Common defaults */
-
-#ifndef OS_CODE
-#  define OS_CODE  0x03  /* assume Unix */
-#endif
-
-#ifndef FOPEN
-#  define FOPEN(name, mode) fopen((name), (mode))
-#endif
-
-         /* functions */
-
-#ifdef HAVE_STRERROR
-   extern char *strerror OF((int));
-#  define zstrerror(errnum) strerror(errnum)
-#else
-#  define zstrerror(errnum) ""
-#endif
-
-#if defined(pyr)
-#  define NO_MEMCPY
-#endif
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
- /* Use our own functions for small and medium model with MSC <= 5.0.
-  * You may have to use the same strategy for Borland C (untested).
-  */
-#  define NO_MEMCPY
-#endif
-#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
-#  define HAVE_MEMCPY
-#endif
-#ifdef HAVE_MEMCPY
-#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
-#    define zmemcpy _fmemcpy
-#    define zmemcmp _fmemcmp
-#    define zmemzero(dest, len) _fmemset(dest, 0, len)
-#  else
-#    define zmemcpy memcpy
-#    define zmemcmp memcmp
-#    define zmemzero(dest, len) memset(dest, 0, len)
-#  endif
-#else
-   extern void zmemcpy  OF((Bytef* dest, Bytef* source, uInt len));
-   extern int  zmemcmp  OF((Bytef* s1,   Bytef* s2, uInt len));
-   extern void zmemzero OF((Bytef* dest, uInt len));
-#endif
-
-/* Diagnostic functions */
-#ifdef DEBUG_ZLIB
-#  include <stdio.h>
-#  ifndef verbose
-#    define verbose 0
-#  endif
-   extern void z_error    OF((char *m));
-#  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, const 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)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
-#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
-
-#endif /* _Z_UTIL_H */
-/* --- zutil.h */
-
-/* +++ deflate.h */
-/* deflate.h -- internal compression state
- * Copyright (C) 1995-1996 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: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
-
-#ifndef _DEFLATE_H
-#define _DEFLATE_H
-
-/* #include "zutil.h" */
-
-/* ===========================================================================
- * Internal compression state.
- */
-
-#define LENGTH_CODES 29
-/* number of length codes, not counting the special END_BLOCK code */
-
-#define LITERALS  256
-/* number of literal bytes 0..255 */
-
-#define L_CODES (LITERALS+1+LENGTH_CODES)
-/* number of Literal or Length codes, including the END_BLOCK code */
-
-#define D_CODES   30
-/* number of distance codes */
-
-#define BL_CODES  19
-/* number of codes used to transfer the bit lengths */
-
-#define HEAP_SIZE (2*L_CODES+1)
-/* maximum heap size */
-
-#define MAX_BITS 15
-/* All codes must not exceed MAX_BITS bits */
-
-#define INIT_STATE    42
-#define BUSY_STATE   113
-#define FINISH_STATE 666
-/* Stream status */
-
-
-/* Data structure describing a single value and its code string. */
-typedef struct ct_data_s {
-    union {
-        ush  freq;       /* frequency count */
-        ush  code;       /* bit string */
-    } fc;
-    union {
-        ush  dad;        /* father node in Huffman tree */
-        ush  len;        /* length of bit string */
-    } dl;
-} FAR ct_data;
-
-#define Freq fc.freq
-#define Code fc.code
-#define Dad  dl.dad
-#define Len  dl.len
-
-typedef struct static_tree_desc_s  static_tree_desc;
-
-typedef struct tree_desc_s {
-    ct_data *dyn_tree;           /* the dynamic tree */
-    int     max_code;            /* largest code with non zero frequency */
-    static_tree_desc *stat_desc; /* the corresponding static tree */
-} FAR tree_desc;
-
-typedef ush Pos;
-typedef Pos FAR Posf;
-typedef unsigned IPos;
-
-/* A Pos is an index in the character window. We use short instead of int to
- * save space in the various tables. IPos is used only for parameter passing.
- */
-
-typedef struct deflate_state {
-    z_streamp strm;      /* pointer back to this zlib stream */
-    int   status;        /* as the name implies */
-    Bytef *pending_buf;  /* output still pending */
-    ulg   pending_buf_size; /* size of pending_buf */
-    Bytef *pending_out;  /* next pending byte to output to the stream */
-    int   pending;       /* nb of bytes in the pending buffer */
-    int   noheader;      /* suppress zlib header and adler32 */
-    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
-    Byte  method;        /* STORED (for zip only) or DEFLATED */
-    int   last_flush;    /* value of flush param for previous deflate call */
-
-                /* used by deflate.c: */
-
-    uInt  w_size;        /* LZ77 window size (32K by default) */
-    uInt  w_bits;        /* log2(w_size)  (8..16) */
-    uInt  w_mask;        /* w_size - 1 */
-
-    Bytef *window;
-    /* Sliding window. Input bytes are read into the second half of the window,
-     * and move to the first half later to keep a dictionary of at least wSize
-     * bytes. With this organization, matches are limited to a distance of
-     * wSize-MAX_MATCH bytes, but this ensures that IO is always
-     * performed with a length multiple of the block size. Also, it limits
-     * the window size to 64K, which is quite useful on MSDOS.
-     * To do: use the user input buffer as sliding window.
-     */
-
-    ulg window_size;
-    /* Actual size of window: 2*wSize, except when the user input buffer
-     * is directly used as sliding window.
-     */
-
-    Posf *prev;
-    /* Link to older string with same hash index. To limit the size of this
-     * array to 64K, this link is maintained only for the last 32K strings.
-     * An index in this array is thus a window index modulo 32K.
-     */
-
-    Posf *head; /* Heads of the hash chains or NIL. */
-
-    uInt  ins_h;          /* hash index of string to be inserted */
-    uInt  hash_size;      /* number of elements in hash table */
-    uInt  hash_bits;      /* log2(hash_size) */
-    uInt  hash_mask;      /* hash_size-1 */
-
-    uInt  hash_shift;
-    /* Number of bits by which ins_h must be shifted at each input
-     * step. It must be such that after MIN_MATCH steps, the oldest
-     * byte no longer takes part in the hash key, that is:
-     *   hash_shift * MIN_MATCH >= hash_bits
-     */
-
-    long block_start;
-    /* Window position at the beginning of the current output block. Gets
-     * negative when the window is moved backwards.
-     */
-
-    uInt match_length;           /* length of best match */
-    IPos prev_match;             /* previous match */
-    int match_available;         /* set if previous match exists */
-    uInt strstart;               /* start of string to insert */
-    uInt match_start;            /* start of matching string */
-    uInt lookahead;              /* number of valid bytes ahead in window */
-
-    uInt prev_length;
-    /* Length of the best match at previous step. Matches not greater than this
-     * are discarded. This is used in the lazy match evaluation.
-     */
-
-    uInt max_chain_length;
-    /* To speed up deflation, hash chains are never searched beyond this
-     * length.  A higher limit improves compression ratio but degrades the
-     * speed.
-     */
-
-    uInt max_lazy_match;
-    /* Attempt to find a better match only when the current match is strictly
-     * smaller than this value. This mechanism is used only for compression
-     * levels >= 4.
-     */
-#   define max_insert_length  max_lazy_match
-    /* Insert new strings in the hash table only if the match length is not
-     * greater than this length. This saves time but degrades compression.
-     * max_insert_length is used only for compression levels <= 3.
-     */
-
-    int level;    /* compression level (1..9) */
-    int strategy; /* favor or force Huffman coding*/
-
-    uInt good_match;
-    /* Use a faster search when the previous match is longer than this */
-
-    int nice_match; /* Stop searching when current match exceeds this */
-
-                /* used by trees.c: */
-    /* Didn't use ct_data typedef below to supress compiler warning */
-    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
-    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
-    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
-
-    struct tree_desc_s l_desc;               /* desc. for literal tree */
-    struct tree_desc_s d_desc;               /* desc. for distance tree */
-    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
-
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
-    int heap_len;               /* number of elements in the heap */
-    int heap_max;               /* element of largest frequency */
-    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
-     * The same heap array is used to build all trees.
-     */
-
-    uch depth[2*L_CODES+1];
-    /* Depth of each subtree used as tie breaker for trees of equal frequency
-     */
-
-    uchf *l_buf;          /* buffer for literals or lengths */
-
-    uInt  lit_bufsize;
-    /* Size of match buffer for literals/lengths.  There are 4 reasons for
-     * limiting lit_bufsize to 64K:
-     *   - frequencies can be kept in 16 bit counters
-     *   - if compression is not successful for the first block, all input
-     *     data is still in the window so we can still emit a stored block even
-     *     when input comes from standard input.  (This can also be done for
-     *     all blocks if lit_bufsize is not greater than 32K.)
-     *   - if compression is not successful for a file smaller than 64K, we can
-     *     even emit a stored file instead of a stored block (saving 5 bytes).
-     *     This is applicable only for zip (not gzip or zlib).
-     *   - creating new Huffman trees less frequently may not provide fast
-     *     adaptation to changes in the input data statistics. (Take for
-     *     example a binary file with poorly compressible code followed by
-     *     a highly compressible string table.) Smaller buffer sizes give
-     *     fast adaptation but have of course the overhead of transmitting
-     *     trees more frequently.
-     *   - I can't count above 4
-     */
-
-    uInt last_lit;      /* running index in l_buf */
-
-    ushf *d_buf;
-    /* Buffer for distances. To simplify the code, d_buf and l_buf have
-     * the same number of elements. To use different lengths, an extra flag
-     * array would be necessary.
-     */
-
-    ulg opt_len;        /* bit length of current block with optimal trees */
-    ulg static_len;     /* bit length of current block with static trees */
-    ulg compressed_len; /* total bit length of compressed file */
-    uInt matches;       /* number of string matches in current block */
-    int last_eob_len;   /* bit length of EOB code for last block */
-
-#ifdef DEBUG_ZLIB
-    ulg bits_sent;      /* bit length of the compressed data */
-#endif
-
-    ush bi_buf;
-    /* Output buffer. bits are inserted starting at the bottom (least
-     * significant bits).
-     */
-    int bi_valid;
-    /* Number of valid bits in bi_buf.  All bits above the last valid bit
-     * are always zero.
-     */
-
-} FAR deflate_state;
-
-/* Output a byte on the stream.
- * IN assertion: there is enough room in pending_buf.
- */
-#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
-
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-        /* in trees.c */
-void _tr_init         OF((deflate_state *s));
-int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
-ulg  _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
-			  int eof));
-void _tr_align        OF((deflate_state *s));
-void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
-                          int eof));
-void _tr_stored_type_only OF((deflate_state *));
-
-#endif
-/* --- deflate.h */
-
-/* +++ deflate.c */
-/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process depends on being able to identify portions
- *      of the input text which are identical to earlier input (within a
- *      sliding window trailing behind the input currently being processed).
- *
- *      The most straightforward technique turns out to be the fastest for
- *      most input files: try all possible matches and select the longest.
- *      The key feature of this algorithm is that insertions into the string
- *      dictionary are very simple and thus fast, and deletions are avoided
- *      completely. Insertions are performed at each input character, whereas
- *      string matches are performed only when the previous match ends. So it
- *      is preferable to spend more time in matches to allow very fast string
- *      insertions and avoid deletions. The matching algorithm for small
- *      strings is inspired from that of Rabin & Karp. A brute force approach
- *      is used to find longer strings when a small match has been found.
- *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
- *      (by Leonid Broukhis).
- *         A previous version of this file used a more sophisticated algorithm
- *      (by Fiala and Greene) which is guaranteed to run in linear amortized
- *      time, but has a larger average cost, uses more memory and is patented.
- *      However the F&G algorithm may be faster for some highly redundant
- *      files if the parameter max_chain_length (described below) is too large.
- *
- *  ACKNOWLEDGEMENTS
- *
- *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
- *      I found it in 'freeze' written by Leonid Broukhis.
- *      Thanks to many people for bug reports and testing.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
- *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
- *
- *      A description of the Rabin and Karp algorithm is given in the book
- *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
- *
- *      Fiala,E.R., and Greene,D.H.
- *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
- *
- */
-
-/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
-
-/* #include "deflate.h" */
-
-char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-/* ===========================================================================
- *  Function prototypes.
- */
-typedef enum {
-    need_more,      /* block not completed, need more input or more output */
-    block_done,     /* block flush performed */
-    finish_started, /* finish started, need only more output at next deflate */
-    finish_done     /* finish done, accept no more input or output */
-} block_state;
-
-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
-/* Compression function. Returns the block state after the call. */
-
-local void fill_window    OF((deflate_state *s));
-local block_state deflate_stored OF((deflate_state *s, int flush));
-local block_state deflate_fast   OF((deflate_state *s, int flush));
-local block_state deflate_slow   OF((deflate_state *s, int flush));
-local void lm_init        OF((deflate_state *s));
-local void putShortMSB    OF((deflate_state *s, uInt b));
-local void flush_pending  OF((z_streamp strm));
-local int read_buf        OF((z_streamp strm, charf *buf, unsigned size));
-#ifdef ASMV
-      void match_init OF((void)); /* asm code initialization */
-      uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#else
-local uInt longest_match  OF((deflate_state *s, IPos cur_match));
-#endif
-
-#ifdef DEBUG_ZLIB
-local  void check_match OF((deflate_state *s, IPos start, IPos match,
-                            int length));
-#endif
-
-/* ===========================================================================
- * Local data
- */
-
-#define NIL 0
-/* Tail of hash chains */
-
-#ifndef TOO_FAR
-#  define TOO_FAR 4096
-#endif
-/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-/* Values for max_lazy_match, good_match and max_chain_length, depending on
- * the desired pack level (0..9). The values given below have been tuned to
- * exclude worst case performance for pathological files. Better values may be
- * found for specific files.
- */
-typedef struct config_s {
-   ush good_length; /* reduce lazy search above this match length */
-   ush max_lazy;    /* do not perform lazy search above this match length */
-   ush nice_length; /* quit search above this match length */
-   ush max_chain;
-   compress_func func;
-} config;
-
-local config configuration_table[10] = {
-/*      good lazy nice chain */
-/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
-/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
-/* 2 */ {4,    5, 16,    8, deflate_fast},
-/* 3 */ {4,    6, 32,   32, deflate_fast},
-
-/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
-/* 5 */ {8,   16, 32,   32, deflate_slow},
-/* 6 */ {8,   16, 128, 128, deflate_slow},
-/* 7 */ {8,   32, 128, 256, deflate_slow},
-/* 8 */ {32, 128, 258, 1024, deflate_slow},
-/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
-
-/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
- * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
- * meaning.
- */
-
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
-#ifndef NO_DUMMY_DECL
-struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
-#endif
-
-/* ===========================================================================
- * Update a hash value with the given input byte
- * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
- *    input characters, so that a running hash key can be computed from the
- *    previous key instead of complete recalculation each time.
- */
-#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
-
-
-/* ===========================================================================
- * Insert string str in the dictionary and set match_head to the previous head
- * of the hash chain (the most recent string with same hash key). Return
- * the previous length of the hash chain.
- * IN  assertion: all calls to to INSERT_STRING are made with consecutive
- *    input characters and the first MIN_MATCH bytes of str are valid
- *    (except for the last MIN_MATCH-1 bytes of the input file).
- */
-#define INSERT_STRING(s, str, match_head) \
-   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
-    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
-    s->head[s->ins_h] = (Pos)(str))
-
-/* ===========================================================================
- * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
- * prev[] will be initialized on the fly.
- */
-#define CLEAR_HASH(s) \
-    s->head[s->hash_size-1] = NIL; \
-    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
-
-/* ========================================================================= */
-int deflateInit_(strm, level, version, stream_size)
-    z_streamp strm;
-    int level;
-    const char *version;
-    int stream_size;
-{
-    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
-			 Z_DEFAULT_STRATEGY, version, stream_size);
-    /* To do: ignore strm->next_in if we use it as window */
-}
-
-/* ========================================================================= */
-int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
-		  version, stream_size)
-    z_streamp strm;
-    int  level;
-    int  method;
-    int  windowBits;
-    int  memLevel;
-    int  strategy;
-    const char *version;
-    int stream_size;
-{
-    deflate_state *s;
-    int noheader = 0;
-    static char* my_version = ZLIB_VERSION;
-
-    ushf *overlay;
-    /* We overlay pending_buf and d_buf+l_buf. This works since the average
-     * output size for (length,distance) codes is <= 24 bits.
-     */
-
-    if (version == Z_NULL || version[0] != my_version[0] ||
-        stream_size != sizeof(z_stream)) {
-	return Z_VERSION_ERROR;
-    }
-    if (strm == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-    if (strm->zalloc == Z_NULL) {
-	strm->zalloc = zcalloc;
-	strm->opaque = (voidpf)0;
-    }
-    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
-#endif
-
-    if (level == Z_DEFAULT_COMPRESSION) level = 6;
-
-    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
-        noheader = 1;
-        windowBits = -windowBits;
-    }
-    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
-        windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
-	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
-    if (s == Z_NULL) return Z_MEM_ERROR;
-    strm->state = (struct internal_state FAR *)s;
-    s->strm = strm;
-
-    s->noheader = noheader;
-    s->w_bits = windowBits;
-    s->w_size = 1 << s->w_bits;
-    s->w_mask = s->w_size - 1;
-
-    s->hash_bits = memLevel + 7;
-    s->hash_size = 1 << s->hash_bits;
-    s->hash_mask = s->hash_size - 1;
-    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
-
-    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
-    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
-    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
-
-    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
-
-    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
-    s->pending_buf = (uchf *) overlay;
-    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
-
-    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
-        s->pending_buf == Z_NULL) {
-        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
-        deflateEnd (strm);
-        return Z_MEM_ERROR;
-    }
-    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
-    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
-
-    s->level = level;
-    s->strategy = strategy;
-    s->method = (Byte)method;
-
-    return deflateReset(strm);
-}
-
-/* ========================================================================= */
-int deflateSetDictionary (strm, dictionary, dictLength)
-    z_streamp strm;
-    const Bytef *dictionary;
-    uInt  dictLength;
-{
-    deflate_state *s;
-    uInt length = dictLength;
-    uInt n;
-    IPos hash_head = 0;
-
-    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
-	return Z_STREAM_ERROR;
-
-    s = (deflate_state *) strm->state;
-    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
-
-    strm->adler = adler32(strm->adler, dictionary, dictLength);
-
-    if (length < MIN_MATCH) return Z_OK;
-    if (length > MAX_DIST(s)) {
-	length = MAX_DIST(s);
-#ifndef USE_DICT_HEAD
-	dictionary += dictLength - length; /* use the tail of the dictionary */
-#endif
-    }
-    zmemcpy((charf *)s->window, dictionary, length);
-    s->strstart = length;
-    s->block_start = (long)length;
-
-    /* Insert all strings in the hash table (except for the last two bytes).
-     * s->lookahead stays null, so s->ins_h will be recomputed at the next
-     * call of fill_window.
-     */
-    s->ins_h = s->window[0];
-    UPDATE_HASH(s, s->ins_h, s->window[1]);
-    for (n = 0; n <= length - MIN_MATCH; n++) {
-	INSERT_STRING(s, n, hash_head);
-    }
-    if (hash_head) hash_head = 0;  /* to make compiler happy */
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateReset (strm)
-    z_streamp strm;
-{
-    deflate_state *s;
-    
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
-
-    strm->total_in = strm->total_out = 0;
-    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
-    strm->data_type = Z_UNKNOWN;
-
-    s = (deflate_state *)strm->state;
-    s->pending = 0;
-    s->pending_out = s->pending_buf;
-
-    if (s->noheader < 0) {
-        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
-    }
-    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
-    strm->adler = 1;
-    s->last_flush = Z_NO_FLUSH;
-
-    _tr_init(s);
-    lm_init(s);
-
-    return Z_OK;
-}
-
-/* ========================================================================= */
-int deflateParams(strm, level, strategy)
-    z_streamp strm;
-    int level;
-    int strategy;
-{
-    deflate_state *s;
-    compress_func func;
-    int err = Z_OK;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    if (level == Z_DEFAULT_COMPRESSION) {
-	level = 6;
-    }
-    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-	return Z_STREAM_ERROR;
-    }
-    func = configuration_table[s->level].func;
-
-    if (func != configuration_table[level].func && strm->total_in != 0) {
-	/* Flush the last buffer: */
-	err = deflate(strm, Z_PARTIAL_FLUSH);
-    }
-    if (s->level != level) {
-	s->level = level;
-	s->max_lazy_match   = configuration_table[level].max_lazy;
-	s->good_match       = configuration_table[level].good_length;
-	s->nice_match       = configuration_table[level].nice_length;
-	s->max_chain_length = configuration_table[level].max_chain;
-    }
-    s->strategy = strategy;
-    return err;
-}
-
-/* =========================================================================
- * Put a short in the pending buffer. The 16-bit value is put in MSB order.
- * IN assertion: the stream state is correct and there is enough room in
- * pending_buf.
- */
-local void putShortMSB (s, b)
-    deflate_state *s;
-    uInt b;
-{
-    put_byte(s, (Byte)(b >> 8));
-    put_byte(s, (Byte)(b & 0xff));
-}   
-
-/* =========================================================================
- * Flush as much pending output as possible. All deflate() output goes
- * through this function so some applications may wish to modify it
- * to avoid allocating a large strm->next_out buffer and copying into it.
- * (See also read_buf()).
- */
-local void flush_pending(strm)
-    z_streamp strm;
-{
-    deflate_state *s = (deflate_state *) strm->state;
-    unsigned len = s->pending;
-
-    if (len > strm->avail_out) len = strm->avail_out;
-    if (len == 0) return;
-
-    if (strm->next_out != Z_NULL) {
-	zmemcpy(strm->next_out, s->pending_out, len);
-	strm->next_out += len;
-    }
-    s->pending_out += len;
-    strm->total_out += len;
-    strm->avail_out  -= len;
-    s->pending -= len;
-    if (s->pending == 0) {
-        s->pending_out = s->pending_buf;
-    }
-}
-
-/* ========================================================================= */
-int deflate (strm, flush)
-    z_streamp strm;
-    int flush;
-{
-    int old_flush; /* value of flush param for previous deflate call */
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL ||
-	flush > Z_FINISH || flush < 0) {
-        return Z_STREAM_ERROR;
-    }
-    s = (deflate_state *) strm->state;
-
-    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
-	(s->status == FINISH_STATE && flush != Z_FINISH)) {
-        ERR_RETURN(strm, Z_STREAM_ERROR);
-    }
-    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
-
-    s->strm = strm; /* just in case */
-    old_flush = s->last_flush;
-    s->last_flush = flush;
-
-    /* Write the zlib header */
-    if (s->status == INIT_STATE) {
-
-        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
-        uInt level_flags = (s->level-1) >> 1;
-
-        if (level_flags > 3) level_flags = 3;
-        header |= (level_flags << 6);
-	if (s->strstart != 0) header |= PRESET_DICT;
-        header += 31 - (header % 31);
-
-        s->status = BUSY_STATE;
-        putShortMSB(s, header);
-
-	/* Save the adler32 of the preset dictionary: */
-	if (s->strstart != 0) {
-	    putShortMSB(s, (uInt)(strm->adler >> 16));
-	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-	}
-	strm->adler = 1L;
-    }
-
-    /* Flush as much pending output as possible */
-    if (s->pending != 0) {
-        flush_pending(strm);
-        if (strm->avail_out == 0) {
-	    /* Since avail_out is 0, deflate will be called again with
-	     * more output space, but possibly with both pending and
-	     * avail_in equal to zero. There won't be anything to do,
-	     * but this is not an error situation so make sure we
-	     * return OK instead of BUF_ERROR at next call of deflate:
-             */
-	    s->last_flush = -1;
-	    return Z_OK;
-	}
-
-    /* Make sure there is something to do and avoid duplicate consecutive
-     * flushes. For repeated and useless calls with Z_FINISH, we keep
-     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
-     */
-    } else if (strm->avail_in == 0 && flush <= old_flush &&
-	       flush != Z_FINISH) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* User must not provide more input after the first FINISH: */
-    if (s->status == FINISH_STATE && strm->avail_in != 0) {
-        ERR_RETURN(strm, Z_BUF_ERROR);
-    }
-
-    /* Start a new block or continue the current one.
-     */
-    if (strm->avail_in != 0 || s->lookahead != 0 ||
-        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
-        block_state bstate;
-
-	bstate = (*(configuration_table[s->level].func))(s, flush);
-
-        if (bstate == finish_started || bstate == finish_done) {
-            s->status = FINISH_STATE;
-        }
-        if (bstate == need_more || bstate == finish_started) {
-	    if (strm->avail_out == 0) {
-	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
-	    }
-	    return Z_OK;
-	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
-	     * of deflate should use the same flush parameter to make sure
-	     * that the flush is complete. So we don't have to output an
-	     * empty block here, this will be done at next call. This also
-	     * ensures that for a very small output buffer, we emit at most
-	     * one empty block.
-	     */
-	}
-        if (bstate == block_done) {
-            if (flush == Z_PARTIAL_FLUSH) {
-                _tr_align(s);
-	    } else if (flush == Z_PACKET_FLUSH) {
-		/* Output just the 3-bit `stored' block type value,
-		   but not a zero length. */
-		_tr_stored_type_only(s);
-            } else { /* FULL_FLUSH or SYNC_FLUSH */
-                _tr_stored_block(s, (char*)0, 0L, 0);
-                /* For a full flush, this empty block will be recognized
-                 * as a special marker by inflate_sync().
-                 */
-                if (flush == Z_FULL_FLUSH) {
-                    CLEAR_HASH(s);             /* forget history */
-                }
-            }
-            flush_pending(strm);
-	    if (strm->avail_out == 0) {
-	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
-	      return Z_OK;
-	    }
-        }
-    }
-    Assert(strm->avail_out > 0, "bug2");
-
-    if (flush != Z_FINISH) return Z_OK;
-    if (s->noheader) return Z_STREAM_END;
-
-    /* Write the zlib trailer (adler32) */
-    putShortMSB(s, (uInt)(strm->adler >> 16));
-    putShortMSB(s, (uInt)(strm->adler & 0xffff));
-    flush_pending(strm);
-    /* If avail_out is zero, the application will call deflate again
-     * to flush the rest.
-     */
-    s->noheader = -1; /* write the trailer only once! */
-    return s->pending != 0 ? Z_OK : Z_STREAM_END;
-}
-
-/* ========================================================================= */
-int deflateEnd (strm)
-    z_streamp strm;
-{
-    int status;
-    deflate_state *s;
-
-    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-    s = (deflate_state *) strm->state;
-
-    status = s->status;
-    if (status != INIT_STATE && status != BUSY_STATE &&
-	status != FINISH_STATE) {
-      return Z_STREAM_ERROR;
-    }
-
-    /* Deallocate in reverse order of allocations: */
-    TRY_FREE(strm, s->pending_buf);
-    TRY_FREE(strm, s->head);
-    TRY_FREE(strm, s->prev);
-    TRY_FREE(strm, s->window);
-
-    ZFREE(strm, s);
-    strm->state = Z_NULL;
-
-    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
-}
-
-/* =========================================================================
- * Copy the source state to the destination state.
- */
-int deflateCopy (dest, source)
-    z_streamp dest;
-    z_streamp source;
-{
-    deflate_state *ds;
-    deflate_state *ss;
-    ushf *overlay;
-
-    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
-        return Z_STREAM_ERROR;
-    ss = (deflate_state *) source->state;
-
-    *dest = *source;
-
-    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
-    if (ds == Z_NULL) return Z_MEM_ERROR;
-    dest->state = (struct internal_state FAR *) ds;
-    *ds = *ss;
-    ds->strm = dest;
-
-    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
-    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
-    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
-    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
-    ds->pending_buf = (uchf *) overlay;
-
-    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
-        ds->pending_buf == Z_NULL) {
-        deflateEnd (dest);
-        return Z_MEM_ERROR;
-    }
-    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
-    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
-    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
-    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
-    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
-
-    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
-    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
-    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
-
-    ds->l_desc.dyn_tree = ds->dyn_ltree;
-    ds->d_desc.dyn_tree = ds->dyn_dtree;
-    ds->bl_desc.dyn_tree = ds->bl_tree;
-
-    return Z_OK;
-}
-
-/* ===========================================================================
- * Return the number of bytes of output which are immediately available
- * for output from the decompressor.
- */
-int deflateOutputPending (strm)
-    z_streamp strm;
-{
-    if (strm == Z_NULL || strm->state == Z_NULL) return 0;
-    
-    return ((deflate_state *)(strm->state))->pending;
-}
-
-/* ===========================================================================
- * Read a new buffer from the current input stream, update the adler32
- * and total number of bytes read.  All deflate() input goes through
- * this function so some applications may wish to modify it to avoid
- * allocating a large strm->next_in buffer and copying from it.
- * (See also flush_pending()).
- */
-local int read_buf(strm, buf, size)
-    z_streamp strm;
-    charf *buf;
-    unsigned size;
-{
-    unsigned len = strm->avail_in;
-
-    if (len > size) len = size;
-    if (len == 0) return 0;
-
-    strm->avail_in  -= len;
-
-    if (!((deflate_state *)(strm->state))->noheader) {
-        strm->adler = adler32(strm->adler, strm->next_in, len);
-    }
-    zmemcpy(buf, strm->next_in, len);
-    strm->next_in  += len;
-    strm->total_in += len;
-
-    return (int)len;
-}
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new zlib stream
- */
-local void lm_init (s)
-    deflate_state *s;
-{
-    s->window_size = (ulg)2L*s->w_size;
-
-    CLEAR_HASH(s);
-
-    /* Set the default configuration parameters:
-     */
-    s->max_lazy_match   = configuration_table[s->level].max_lazy;
-    s->good_match       = configuration_table[s->level].good_length;
-    s->nice_match       = configuration_table[s->level].nice_length;
-    s->max_chain_length = configuration_table[s->level].max_chain;
-
-    s->strstart = 0;
-    s->block_start = 0L;
-    s->lookahead = 0;
-    s->match_length = s->prev_length = MIN_MATCH-1;
-    s->match_available = 0;
-    s->ins_h = 0;
-#ifdef ASMV
-    match_init(); /* initialize the asm code */
-#endif
-}
-
-/* ===========================================================================
- * Set match_start to the longest match starting at the given string and
- * return its length. Matches shorter or equal to prev_length are discarded,
- * in which case the result is equal to prev_length and match_start is
- * garbage.
- * IN assertions: cur_match is the head of the hash chain for the current
- *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
- * OUT assertion: the match length is not greater than s->lookahead.
- */
-#ifndef ASMV
-/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
- * match.S. The code will be functionally equivalent.
- */
-local uInt longest_match(s, cur_match)
-    deflate_state *s;
-    IPos cur_match;                             /* current match */
-{
-    unsigned chain_length = s->max_chain_length;/* max hash chain length */
-    register Bytef *scan = s->window + s->strstart; /* current string */
-    register Bytef *match;                       /* matched string */
-    register int len;                           /* length of current match */
-    int best_len = s->prev_length;              /* best match length so far */
-    int nice_match = s->nice_match;             /* stop if match long enough */
-    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
-        s->strstart - (IPos)MAX_DIST(s) : NIL;
-    /* Stop when cur_match becomes <= limit. To simplify the code,
-     * we prevent matches with the string of window index 0.
-     */
-    Posf *prev = s->prev;
-    uInt wmask = s->w_mask;
-
-#ifdef UNALIGNED_OK
-    /* Compare two bytes at a time. Note: this is not always beneficial.
-     * Try with and without -DUNALIGNED_OK to check.
-     */
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
-    register ush scan_start = *(ushf*)scan;
-    register ush scan_end   = *(ushf*)(scan+best_len-1);
-#else
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
-    register Byte scan_end1  = scan[best_len-1];
-    register Byte scan_end   = scan[best_len];
-#endif
-
-    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
-     * It is easy to get rid of this optimization if necessary.
-     */
-    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-
-    /* Do not waste too much time if we already have a good match: */
-    if (s->prev_length >= s->good_match) {
-        chain_length >>= 2;
-    }
-    /* Do not look for matches beyond the end of the input. This is necessary
-     * to make deflate deterministic.
-     */
-    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
-
-    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-
-    do {
-        Assert(cur_match < s->strstart, "no future");
-        match = s->window + cur_match;
-
-        /* Skip to next match if the match length cannot increase
-         * or if the match length is less than 2:
-         */
-#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
-        /* This code assumes sizeof(unsigned short) == 2. Do not use
-         * UNALIGNED_OK if your compiler uses a different size.
-         */
-        if (*(ushf*)(match+best_len-1) != scan_end ||
-            *(ushf*)match != scan_start) continue;
-
-        /* It is not necessary to compare scan[2] and match[2] since they are
-         * always equal when the other bytes match, given that the hash keys
-         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
-         * strstart+3, +5, ... up to strstart+257. We check for insufficient
-         * lookahead only every 4th comparison; the 128th check will be made
-         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
-         * necessary to put more guard bytes at the end of the window, or
-         * to check more often for insufficient lookahead.
-         */
-        Assert(scan[2] == match[2], "scan[2]?");
-        scan++, match++;
-        do {
-        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-                 scan < strend);
-        /* The funny "do {}" generates better code on most compilers */
-
-        /* Here, scan <= window+strstart+257 */
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-        if (*scan == *match) scan++;
-
-        len = (MAX_MATCH - 1) - (int)(strend-scan);
-        scan = strend - (MAX_MATCH-1);
-
-#else /* UNALIGNED_OK */
-
-        if (match[best_len]   != scan_end  ||
-            match[best_len-1] != scan_end1 ||
-            *match            != *scan     ||
-            *++match          != scan[1])      continue;
-
-        /* The check at best_len-1 can be removed because it will be made
-         * again later. (This heuristic is not always a win.)
-         * It is not necessary to compare scan[2] and match[2] since they
-         * are always equal when the other bytes match, given that
-         * the hash keys are equal and that HASH_BITS >= 8.
-         */
-        scan += 2, match++;
-        Assert(*scan == *match, "match[2]?");
-
-        /* We check for insufficient lookahead only every 8th comparison;
-         * the 256th check will be made at strstart+258.
-         */
-        do {
-        } while (*++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 *++scan == *++match && *++scan == *++match &&
-                 scan < strend);
-
-        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-
-        len = MAX_MATCH - (int)(strend - scan);
-        scan = strend - MAX_MATCH;
-
-#endif /* UNALIGNED_OK */
-
-        if (len > best_len) {
-            s->match_start = cur_match;
-            best_len = len;
-            if (len >= nice_match) break;
-#ifdef UNALIGNED_OK
-            scan_end = *(ushf*)(scan+best_len-1);
-#else
-            scan_end1  = scan[best_len-1];
-            scan_end   = scan[best_len];
-#endif
-        }
-    } while ((cur_match = prev[cur_match & wmask]) > limit
-             && --chain_length != 0);
-
-    if ((uInt)best_len <= s->lookahead) return best_len;
-    return s->lookahead;
-}
-#endif /* ASMV */
-
-#ifdef DEBUG_ZLIB
-/* ===========================================================================
- * Check that the match at match_start is indeed a match.
- */
-local void check_match(s, start, match, length)
-    deflate_state *s;
-    IPos start, match;
-    int length;
-{
-    /* check that the match is indeed a match */
-    if (zmemcmp((charf *)s->window + match,
-                (charf *)s->window + start, length) != EQUAL) {
-        fprintf(stderr, " start %u, match %u, length %d\n",
-		start, match, length);
-        do {
-	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
-	} while (--length != 0);
-        z_error("invalid match");
-    }
-    if (z_verbose > 1) {
-        fprintf(stderr,"\\[%d,%d]", start-match, length);
-        do { putc(s->window[start++], stderr); } while (--length != 0);
-    }
-}
-#else
-#  define check_match(s, start, match, length)
-#endif
-
-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead.
- *
- * IN assertion: lookahead < MIN_LOOKAHEAD
- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- *    At least one byte has been read, or avail_in == 0; reads are
- *    performed for at least two bytes (required for the zip translate_eol
- *    option -- not supported here).
- */
-local void fill_window(s)
-    deflate_state *s;
-{
-    register unsigned n, m;
-    register Posf *p;
-    unsigned more;    /* Amount of free space at the end of the window. */
-    uInt wsize = s->w_size;
-
-    do {
-        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
-
-        /* Deal with !@#$% 64K limit: */
-        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
-            more = wsize;
-
-        } else if (more == (unsigned)(-1)) {
-            /* Very unlikely, but possible on 16 bit machine if strstart == 0
-             * and lookahead == 1 (input done one byte at time)
-             */
-            more--;
-
-        /* If the window is almost full and there is insufficient lookahead,
-         * move the upper half to the lower one to make room in the upper half.
-         */
-        } else if (s->strstart >= wsize+MAX_DIST(s)) {
-
-            zmemcpy((charf *)s->window, (charf *)s->window+wsize,
-                   (unsigned)wsize);
-            s->match_start -= wsize;
-            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
-            s->block_start -= (long) wsize;
-
-            /* Slide the hash table (could be avoided with 32 bit values
-               at the expense of memory usage). We slide even when level == 0
-               to keep the hash table consistent if we switch back to level > 0
-               later. (Using level 0 permanently is not an optimal usage of
-               zlib, so we don't care about this pathological case.)
-             */
-            n = s->hash_size;
-            p = &s->head[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-            } while (--n);
-
-            n = wsize;
-            p = &s->prev[n];
-            do {
-                m = *--p;
-                *p = (Pos)(m >= wsize ? m-wsize : NIL);
-                /* If n is not on any hash chain, prev[n] is garbage but
-                 * its value will never be used.
-                 */
-            } while (--n);
-            more += wsize;
-        }
-        if (s->strm->avail_in == 0) return;
-
-        /* If there was no sliding:
-         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
-         *    more == window_size - lookahead - strstart
-         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
-         * => more >= window_size - 2*WSIZE + 2
-         * In the BIG_MEM or MMAP case (not yet supported),
-         *   window_size == input_size + MIN_LOOKAHEAD  &&
-         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
-         * Otherwise, window_size == 2*WSIZE so more >= 2.
-         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
-         */
-        Assert(more >= 2, "more < 2");
-
-        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
-                     more);
-        s->lookahead += n;
-
-        /* Initialize the hash value now that we have some input: */
-        if (s->lookahead >= MIN_MATCH) {
-            s->ins_h = s->window[s->strstart];
-            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-            Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-        }
-        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
-         * but this is not important since only literal bytes will be emitted.
-         */
-
-    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
-}
-
-/* ===========================================================================
- * Flush the current block, with given end-of-file flag.
- * IN assertion: strstart is set to the end of the current match.
- */
-#define FLUSH_BLOCK_ONLY(s, eof) { \
-   _tr_flush_block(s, (s->block_start >= 0L ? \
-                   (charf *)&s->window[(unsigned)s->block_start] : \
-                   (charf *)Z_NULL), \
-		(ulg)((long)s->strstart - s->block_start), \
-		(eof)); \
-   s->block_start = s->strstart; \
-   flush_pending(s->strm); \
-   Tracev((stderr,"[FLUSH]")); \
-}
-
-/* Same but force premature exit if necessary. */
-#define FLUSH_BLOCK(s, eof) { \
-   FLUSH_BLOCK_ONLY(s, eof); \
-   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
-}
-
-/* ===========================================================================
- * Copy without compression as much as possible from the input stream, return
- * the current block state.
- * This function does not insert new strings in the dictionary since
- * uncompressible data is probably not useful. This function is used
- * only for the level=0 compression option.
- * NOTE: this function should be optimized to avoid extra copying from
- * window to pending_buf.
- */
-local block_state deflate_stored(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
-     * to pending_buf_size, and each stored block has a 5 byte header:
-     */
-    ulg max_block_size = 0xffff;
-    ulg max_start;
-
-    if (max_block_size > s->pending_buf_size - 5) {
-        max_block_size = s->pending_buf_size - 5;
-    }
-
-    /* Copy as much as possible from input to output: */
-    for (;;) {
-        /* Fill the window as much as possible: */
-        if (s->lookahead <= 1) {
-
-            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
-		   s->block_start >= (long)s->w_size, "slide too late");
-
-            fill_window(s);
-            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
-
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-	Assert(s->block_start >= 0L, "block gone");
-
-	s->strstart += s->lookahead;
-	s->lookahead = 0;
-
-	/* Emit a stored block if pending_buf will be full: */
- 	max_start = s->block_start + max_block_size;
-        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
-	    /* strstart == 0 is possible when wraparound on 16-bit machine */
-	    s->lookahead = (uInt)(s->strstart - max_start);
-	    s->strstart = (uInt)max_start;
-            FLUSH_BLOCK(s, 0);
-	}
-	/* Flush if we may have to slide, otherwise block_start may become
-         * negative and the data will be gone:
-         */
-        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
-            FLUSH_BLOCK(s, 0);
-	}
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Compress as much as possible from the input stream, return the current
- * block state.
- * This function does not perform lazy evaluation of matches and inserts
- * new strings in the dictionary only for unmatched strings or for short
- * matches. It is used only for the fast compression options.
- */
-local block_state deflate_fast(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL; /* head of the hash chain */
-    int bflush;           /* set if current block must be flushed */
-
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         * At this point we have always match_length < MIN_MATCH
-         */
-        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-        }
-        if (s->match_length >= MIN_MATCH) {
-            check_match(s, s->strstart, s->match_start, s->match_length);
-
-            bflush = _tr_tally(s, s->strstart - s->match_start,
-                               s->match_length - MIN_MATCH);
-
-            s->lookahead -= s->match_length;
-
-            /* Insert new strings in the hash table only if the match length
-             * is not too large. This saves time but degrades compression.
-             */
-            if (s->match_length <= s->max_insert_length &&
-                s->lookahead >= MIN_MATCH) {
-                s->match_length--; /* string at strstart already in hash table */
-                do {
-                    s->strstart++;
-                    INSERT_STRING(s, s->strstart, hash_head);
-                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                     * always MIN_MATCH bytes ahead.
-                     */
-                } while (--s->match_length != 0);
-                s->strstart++; 
-            } else {
-                s->strstart += s->match_length;
-                s->match_length = 0;
-                s->ins_h = s->window[s->strstart];
-                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-#if MIN_MATCH != 3
-                Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
-                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
-                 * matter since it will be recomputed at next deflate call.
-                 */
-            }
-        } else {
-            /* No match, output a literal byte */
-            Tracevv((stderr,"%c", s->window[s->strstart]));
-            bflush = _tr_tally (s, 0, s->window[s->strstart]);
-            s->lookahead--;
-            s->strstart++; 
-        }
-        if (bflush) FLUSH_BLOCK(s, 0);
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-local block_state deflate_slow(s, flush)
-    deflate_state *s;
-    int flush;
-{
-    IPos hash_head = NIL;    /* head of hash chain */
-    int bflush;              /* set if current block must be flushed */
-
-    /* Process the input block. */
-    for (;;) {
-        /* Make sure that we always have enough lookahead, except
-         * at the end of the input file. We need MAX_MATCH bytes
-         * for the next match, plus MIN_MATCH bytes to insert the
-         * string following the next match.
-         */
-        if (s->lookahead < MIN_LOOKAHEAD) {
-            fill_window(s);
-            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-	        return need_more;
-	    }
-            if (s->lookahead == 0) break; /* flush the current block */
-        }
-
-        /* Insert the string window[strstart .. strstart+2] in the
-         * dictionary, and set hash_head to the head of the hash chain:
-         */
-        if (s->lookahead >= MIN_MATCH) {
-            INSERT_STRING(s, s->strstart, hash_head);
-        }
-
-        /* Find the longest match, discarding those <= prev_length.
-         */
-        s->prev_length = s->match_length, s->prev_match = s->match_start;
-        s->match_length = MIN_MATCH-1;
-
-        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
-            s->strstart - hash_head <= MAX_DIST(s)) {
-            /* To simplify the code, we prevent matches with the string
-             * of window index 0 (in particular we have to avoid a match
-             * of the string with itself at the start of the input file).
-             */
-            if (s->strategy != Z_HUFFMAN_ONLY) {
-                s->match_length = longest_match (s, hash_head);
-            }
-            /* longest_match() sets match_start */
-
-            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
-                 (s->match_length == MIN_MATCH &&
-                  s->strstart - s->match_start > TOO_FAR))) {
-
-                /* If prev_match is also MIN_MATCH, match_start is garbage
-                 * but we will ignore the current match anyway.
-                 */
-                s->match_length = MIN_MATCH-1;
-            }
-        }
-        /* If there was a match at the previous step and the current
-         * match is not better, output the previous match:
-         */
-        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
-            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
-            /* Do not insert strings in hash table beyond this. */
-
-            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
-
-            bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
-                               s->prev_length - MIN_MATCH);
-
-            /* Insert in hash table all strings up to the end of the match.
-             * strstart-1 and strstart are already inserted. If there is not
-             * enough lookahead, the last two strings are not inserted in
-             * the hash table.
-             */
-            s->lookahead -= s->prev_length-1;
-            s->prev_length -= 2;
-            do {
-                if (++s->strstart <= max_insert) {
-                    INSERT_STRING(s, s->strstart, hash_head);
-                }
-            } while (--s->prev_length != 0);
-            s->match_available = 0;
-            s->match_length = MIN_MATCH-1;
-            s->strstart++;
-
-            if (bflush) FLUSH_BLOCK(s, 0);
-
-        } else if (s->match_available) {
-            /* If there was no match at the previous position, output a
-             * single literal. If there was a match but the current match
-             * is longer, truncate the previous match to a single literal.
-             */
-            Tracevv((stderr,"%c", s->window[s->strstart-1]));
-            if (_tr_tally (s, 0, s->window[s->strstart-1])) {
-                FLUSH_BLOCK_ONLY(s, 0);
-            }
-            s->strstart++;
-            s->lookahead--;
-            if (s->strm->avail_out == 0) return need_more;
-        } else {
-            /* There is no previous match to compare with, wait for
-             * the next step to decide.
-             */
-            s->match_available = 1;
-            s->strstart++;
-            s->lookahead--;
-        }
-    }
-    Assert (flush != Z_NO_FLUSH, "no flush?");
-    if (s->match_available) {
-        Tracevv((stderr,"%c", s->window[s->strstart-1]));
-        _tr_tally (s, 0, s->window[s->strstart-1]);
-        s->match_available = 0;
-    }
-    FLUSH_BLOCK(s, flush == Z_FINISH);
-    return flush == Z_FINISH ? finish_done : block_done;
-}
-/* --- deflate.c */
-
-/* +++ trees.c */
-/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-1996 Jean-loup Gailly
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/*
- *  ALGORITHM
- *
- *      The "deflation" process uses several Huffman trees. The more
- *      common source values are represented by shorter bit sequences.
- *
- *      Each code tree is stored in a compressed form which is itself
- * a Huffman encoding of the lengths of all the code strings (in
- * ascending order by source values).  The actual code strings are
- * reconstructed from the lengths in the inflate process, as described
- * in the deflate specification.
- *
- *  REFERENCES
- *
- *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
- *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
- *
- *      Storer, James A.
- *          Data Compression:  Methods and Theory, pp. 49-50.
- *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
- *
- *      Sedgewick, R.
- *          Algorithms, p290.
- *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
- */
-
-/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
-
-/* #include "deflate.h" */
-
-#ifdef DEBUG_ZLIB
-#  include <ctype.h>
-#endif
-
-/* ===========================================================================
- * Constants
- */
-
-#define MAX_BL_BITS 7
-/* Bit length codes must not exceed MAX_BL_BITS bits */
-
-#define END_BLOCK 256
-/* end of block literal code */
-
-#define REP_3_6      16
-/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-
-#define REPZ_3_10    17
-/* repeat a zero length 3-10 times  (3 bits of repeat count) */
-
-#define REPZ_11_138  18
-/* repeat a zero length 11-138 times  (7 bits of repeat count) */
-
-local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
-   = {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};
-
-local int extra_dbits[D_CODES] /* extra bits for each distance code */
-   = {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};
-
-local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
-   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
-
-local uch bl_order[BL_CODES]
-   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
-/* The lengths of the bit length codes are sent in order of decreasing
- * probability, to avoid transmitting the lengths for unused bit length codes.
- */
-
-#define Buf_size (8 * 2*sizeof(char))
-/* Number of bits used within bi_buf. (bi_buf might be implemented on
- * more than 16 bits on some systems.)
- */
-
-/* ===========================================================================
- * Local data. These are initialized only once.
- */
-
-local ct_data static_ltree[L_CODES+2];
-/* The static literal tree. Since the bit lengths are imposed, there is no
- * need for the L_CODES extra codes used during heap construction. However
- * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
- * below).
- */
-
-local ct_data static_dtree[D_CODES];
-/* The static distance tree. (Actually a trivial tree since all codes use
- * 5 bits.)
- */
-
-local uch dist_code[512];
-/* distance codes. The first 256 values correspond to the distances
- * 3 .. 258, the last 256 values correspond to the top 8 bits of
- * the 15 bit distances.
- */
-
-local uch length_code[MAX_MATCH-MIN_MATCH+1];
-/* length code for each normalized match length (0 == MIN_MATCH) */
-
-local int base_length[LENGTH_CODES];
-/* First normalized length for each code (0 = MIN_MATCH) */
-
-local int base_dist[D_CODES];
-/* First normalized distance for each code (0 = distance of 1) */
-
-struct static_tree_desc_s {
-    ct_data *static_tree;        /* static tree or NULL */
-    intf    *extra_bits;         /* extra bits for each code or NULL */
-    int     extra_base;          /* base index for extra_bits */
-    int     elems;               /* max number of elements in the tree */
-    int     max_length;          /* max bit length for the codes */
-};
-
-local static_tree_desc  static_l_desc =
-{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
-
-local static_tree_desc  static_d_desc =
-{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
-
-local static_tree_desc  static_bl_desc =
-{(ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS};
-
-/* ===========================================================================
- * Local (static) routines in this file.
- */
-
-local void tr_static_init OF((void));
-local void init_block     OF((deflate_state *s));
-local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
-local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
-local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
-local void build_tree     OF((deflate_state *s, tree_desc *desc));
-local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
-local int  build_bl_tree  OF((deflate_state *s));
-local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
-                              int blcodes));
-local void compress_block OF((deflate_state *s, ct_data *ltree,
-                              ct_data *dtree));
-local void set_data_type  OF((deflate_state *s));
-local unsigned bi_reverse OF((unsigned value, int length));
-local void bi_windup      OF((deflate_state *s));
-local void bi_flush       OF((deflate_state *s));
-local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
-                              int header));
-
-#ifndef DEBUG_ZLIB
-#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
-   /* Send a code of the given tree. c and tree must not have side effects */
-
-#else /* DEBUG_ZLIB */
-#  define send_code(s, c, tree) \
-     { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
-       send_bits(s, tree[c].Code, tree[c].Len); }
-#endif
-
-#define d_code(dist) \
-   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
-/* Mapping from a distance to a distance code. dist is the distance - 1 and
- * must not have side effects. dist_code[256] and dist_code[257] are never
- * used.
- */
-
-/* ===========================================================================
- * Output a short LSB first on the stream.
- * IN assertion: there is enough room in pendingBuf.
- */
-#define put_short(s, w) { \
-    put_byte(s, (uch)((w) & 0xff)); \
-    put_byte(s, (uch)((ush)(w) >> 8)); \
-}
-
-/* ===========================================================================
- * Send a value on a given number of bits.
- * IN assertion: length <= 16 and value fits in length bits.
- */
-#ifdef DEBUG_ZLIB
-local void send_bits      OF((deflate_state *s, int value, int length));
-
-local void send_bits(s, value, length)
-    deflate_state *s;
-    int value;  /* value to send */
-    int length; /* number of bits */
-{
-    Tracevv((stderr," l %2d v %4x ", length, value));
-    Assert(length > 0 && length <= 15, "invalid length");
-    s->bits_sent += (ulg)length;
-
-    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-     * unused bits in value.
-     */
-    if (s->bi_valid > (int)Buf_size - length) {
-        s->bi_buf |= (value << s->bi_valid);
-        put_short(s, s->bi_buf);
-        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
-        s->bi_valid += length - Buf_size;
-    } else {
-        s->bi_buf |= value << s->bi_valid;
-        s->bi_valid += length;
-    }
-}
-#else /* !DEBUG_ZLIB */
-
-#define send_bits(s, value, length) \
-{ int len = length;\
-  if (s->bi_valid > (int)Buf_size - len) {\
-    int val = value;\
-    s->bi_buf |= (val << s->bi_valid);\
-    put_short(s, s->bi_buf);\
-    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
-    s->bi_valid += len - Buf_size;\
-  } else {\
-    s->bi_buf |= (value) << s->bi_valid;\
-    s->bi_valid += len;\
-  }\
-}
-#endif /* DEBUG_ZLIB */
-
-
-#define MAX(a,b) (a >= b ? a : b)
-/* the arguments must not have side effects */
-
-/* ===========================================================================
- * Initialize the various 'constant' tables. In a multi-threaded environment,
- * this function may be called by two threads concurrently, but this is
- * harmless since both invocations do exactly the same thing.
- */
-local void tr_static_init()
-{
-    static int static_init_done = 0;
-    int n;        /* iterates over tree elements */
-    int bits;     /* bit counter */
-    int length;   /* length value */
-    int code;     /* code value */
-    int dist;     /* distance index */
-    ush bl_count[MAX_BITS+1];
-    /* number of codes at each bit length for an optimal tree */
-
-    if (static_init_done) return;
-
-    /* Initialize the mapping length (0..255) -> length code (0..28) */
-    length = 0;
-    for (code = 0; code < LENGTH_CODES-1; code++) {
-        base_length[code] = length;
-        for (n = 0; n < (1<<extra_lbits[code]); n++) {
-            length_code[length++] = (uch)code;
-        }
-    }
-    Assert (length == 256, "tr_static_init: length != 256");
-    /* Note that the length 255 (match length 258) can be represented
-     * in two different ways: code 284 + 5 bits or code 285, so we
-     * overwrite length_code[255] to use the best encoding:
-     */
-    length_code[length-1] = (uch)code;
-
-    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-    dist = 0;
-    for (code = 0 ; code < 16; code++) {
-        base_dist[code] = dist;
-        for (n = 0; n < (1<<extra_dbits[code]); n++) {
-            dist_code[dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: dist != 256");
-    dist >>= 7; /* from now on, all distances are divided by 128 */
-    for ( ; code < D_CODES; code++) {
-        base_dist[code] = dist << 7;
-        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
-            dist_code[256 + dist++] = (uch)code;
-        }
-    }
-    Assert (dist == 256, "tr_static_init: 256+dist != 512");
-
-    /* Construct the codes of the static literal tree */
-    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
-    n = 0;
-    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
-    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
-    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
-    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
-    /* Codes 286 and 287 do not exist, but we must include them in the
-     * tree construction to get a canonical Huffman tree (longest code
-     * all ones)
-     */
-    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
-
-    /* The static distance tree is trivial: */
-    for (n = 0; n < D_CODES; n++) {
-        static_dtree[n].Len = 5;
-        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
-    }
-    static_init_done = 1;
-}
-
-/* ===========================================================================
- * Initialize the tree data structures for a new zlib stream.
- */
-void _tr_init(s)
-    deflate_state *s;
-{
-    tr_static_init();
-
-    s->compressed_len = 0L;
-
-    s->l_desc.dyn_tree = s->dyn_ltree;
-    s->l_desc.stat_desc = &static_l_desc;
-
-    s->d_desc.dyn_tree = s->dyn_dtree;
-    s->d_desc.stat_desc = &static_d_desc;
-
-    s->bl_desc.dyn_tree = s->bl_tree;
-    s->bl_desc.stat_desc = &static_bl_desc;
-
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-#ifdef DEBUG_ZLIB
-    s->bits_sent = 0L;
-#endif
-
-    /* Initialize the first block of the first file: */
-    init_block(s);
-}
-
-/* ===========================================================================
- * Initialize a new block.
- */
-local void init_block(s)
-    deflate_state *s;
-{
-    int n; /* iterates over tree elements */
-
-    /* Initialize the trees. */
-    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
-    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
-    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
-
-    s->dyn_ltree[END_BLOCK].Freq = 1;
-    s->opt_len = s->static_len = 0L;
-    s->last_lit = s->matches = 0;
-}
-
-#define SMALLEST 1
-/* Index within the heap array of least frequent node in the Huffman tree */
-
-
-/* ===========================================================================
- * Remove the smallest element from the heap and recreate the heap with
- * one less element. Updates heap and heap_len.
- */
-#define pqremove(s, tree, top) \
-{\
-    top = s->heap[SMALLEST]; \
-    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
-    pqdownheap(s, tree, SMALLEST); \
-}
-
-/* ===========================================================================
- * Compares to subtrees, using the tree depth as tie breaker when
- * the subtrees have equal frequency. This minimizes the worst case length.
- */
-#define smaller(tree, n, m, depth) \
-   (tree[n].Freq < tree[m].Freq || \
-   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
-
-/* ===========================================================================
- * Restore the heap property by moving down the tree starting at node k,
- * exchanging a node with the smallest of its two sons if necessary, stopping
- * when the heap property is re-established (each father smaller than its
- * two sons).
- */
-local void pqdownheap(s, tree, k)
-    deflate_state *s;
-    ct_data *tree;  /* the tree to restore */
-    int k;               /* node to move down */
-{
-    int v = s->heap[k];
-    int j = k << 1;  /* left son of k */
-    while (j <= s->heap_len) {
-        /* Set j to the smallest of the two sons: */
-        if (j < s->heap_len &&
-            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
-            j++;
-        }
-        /* Exit if v is smaller than both sons */
-        if (smaller(tree, v, s->heap[j], s->depth)) break;
-
-        /* Exchange v with the smallest son */
-        s->heap[k] = s->heap[j];  k = j;
-
-        /* And continue down the tree, setting j to the left son of k */
-        j <<= 1;
-    }
-    s->heap[k] = v;
-}
-
-/* ===========================================================================
- * Compute the optimal bit lengths for a tree and update the total bit length
- * for the current block.
- * IN assertion: the fields freq and dad are set, heap[heap_max] and
- *    above are the tree nodes sorted by increasing frequency.
- * OUT assertions: the field len is set to the optimal bit length, the
- *     array bl_count contains the frequencies for each bit length.
- *     The length opt_len is updated; static_len is also updated if stree is
- *     not null.
- */
-local void gen_bitlen(s, desc)
-    deflate_state *s;
-    tree_desc *desc;    /* the tree descriptor */
-{
-    ct_data *tree  = desc->dyn_tree;
-    int max_code   = desc->max_code;
-    ct_data *stree = desc->stat_desc->static_tree;
-    intf *extra    = desc->stat_desc->extra_bits;
-    int base       = desc->stat_desc->extra_base;
-    int max_length = desc->stat_desc->max_length;
-    int h;              /* heap index */
-    int n, m;           /* iterate over the tree elements */
-    int bits;           /* bit length */
-    int xbits;          /* extra bits */
-    ush f;              /* frequency */
-    int overflow = 0;   /* number of elements with bit length too large */
-
-    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
-
-    /* In a first pass, compute the optimal bit lengths (which may
-     * overflow in the case of the bit length tree).
-     */
-    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
-
-    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
-        n = s->heap[h];
-        bits = tree[tree[n].Dad].Len + 1;
-        if (bits > max_length) bits = max_length, overflow++;
-        tree[n].Len = (ush)bits;
-        /* We overwrite tree[n].Dad which is no longer needed */
-
-        if (n > max_code) continue; /* not a leaf node */
-
-        s->bl_count[bits]++;
-        xbits = 0;
-        if (n >= base) xbits = extra[n-base];
-        f = tree[n].Freq;
-        s->opt_len += (ulg)f * (bits + xbits);
-        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
-    }
-    if (overflow == 0) return;
-
-    Trace((stderr,"\nbit length overflow\n"));
-    /* This happens for example on obj2 and pic of the Calgary corpus */
-
-    /* Find the first bit length which could increase: */
-    do {
-        bits = max_length-1;
-        while (s->bl_count[bits] == 0) bits--;
-        s->bl_count[bits]--;      /* move one leaf down the tree */
-        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
-        s->bl_count[max_length]--;
-        /* The brother of the overflow item also moves one step up,
-         * but this does not affect bl_count[max_length]
-         */
-        overflow -= 2;
-    } while (overflow > 0);
-
-    /* Now recompute all bit lengths, scanning in increasing frequency.
-     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-     * lengths instead of fixing only the wrong ones. This idea is taken
-     * from 'ar' written by Haruhiko Okumura.)
-     */
-    for (bits = max_length; bits != 0; bits--) {
-        n = s->bl_count[bits];
-        while (n != 0) {
-            m = s->heap[--h];
-            if (m > max_code) continue;
-            if (tree[m].Len != (unsigned) bits) {
-                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
-                s->opt_len += ((long)bits - (long)tree[m].Len)
-                              *(long)tree[m].Freq;
-                tree[m].Len = (ush)bits;
-            }
-            n--;
-        }
-    }
-}
-
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- *     zero code length.
- */
-local void gen_codes (tree, max_code, bl_count)
-    ct_data *tree;             /* the tree to decorate */
-    int max_code;              /* largest code with non zero frequency */
-    ushf *bl_count;            /* number of codes at each bit length */
-{
-    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
-    ush code = 0;              /* running code value */
-    int bits;                  /* bit index */
-    int n;                     /* code index */
-
-    /* The distribution counts are first used to generate the code values
-     * without bit reversal.
-     */
-    for (bits = 1; bits <= MAX_BITS; bits++) {
-        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
-    }
-    /* Check that the bit counts in bl_count are consistent. The last code
-     * must be all ones.
-     */
-    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
-            "inconsistent bit counts");
-    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
-
-    for (n = 0;  n <= max_code; n++) {
-        int len = tree[n].Len;
-        if (len == 0) continue;
-        /* Now reverse the bits */
-        tree[n].Code = bi_reverse(next_code[len]++, len);
-
-        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
-             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
-    }
-}
-
-/* ===========================================================================
- * Construct one Huffman tree and assigns the code bit strings and lengths.
- * Update the total bit length for the current block.
- * IN assertion: the field freq is set for all tree elements.
- * OUT assertions: the fields len and code are set to the optimal bit length
- *     and corresponding code. The length opt_len is updated; static_len is
- *     also updated if stree is not null. The field max_code is set.
- */
-local void build_tree(s, desc)
-    deflate_state *s;
-    tree_desc *desc; /* the tree descriptor */
-{
-    ct_data *tree   = desc->dyn_tree;
-    ct_data *stree  = desc->stat_desc->static_tree;
-    int elems       = desc->stat_desc->elems;
-    int n, m;          /* iterate over heap elements */
-    int max_code = -1; /* largest code with non zero frequency */
-    int node;          /* new node being created */
-
-    /* Construct the initial heap, with least frequent element in
-     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-     * heap[0] is not used.
-     */
-    s->heap_len = 0, s->heap_max = HEAP_SIZE;
-
-    for (n = 0; n < elems; n++) {
-        if (tree[n].Freq != 0) {
-            s->heap[++(s->heap_len)] = max_code = n;
-            s->depth[n] = 0;
-        } else {
-            tree[n].Len = 0;
-        }
-    }
-
-    /* The pkzip format requires that at least one distance code exists,
-     * and that at least one bit should be sent even if there is only one
-     * possible code. So to avoid special checks later on we force at least
-     * two codes of non zero frequency.
-     */
-    while (s->heap_len < 2) {
-        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
-        tree[node].Freq = 1;
-        s->depth[node] = 0;
-        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
-        /* node is 0 or 1 so it does not have extra bits */
-    }
-    desc->max_code = max_code;
-
-    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-     * establish sub-heaps of increasing lengths:
-     */
-    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
-
-    /* Construct the Huffman tree by repeatedly combining the least two
-     * frequent nodes.
-     */
-    node = elems;              /* next internal node of the tree */
-    do {
-        pqremove(s, tree, n);  /* n = node of least frequency */
-        m = s->heap[SMALLEST]; /* m = node of next least frequency */
-
-        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
-        s->heap[--(s->heap_max)] = m;
-
-        /* Create a new node father of n and m */
-        tree[node].Freq = tree[n].Freq + tree[m].Freq;
-        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
-        tree[n].Dad = tree[m].Dad = (ush)node;
-#ifdef DUMP_BL_TREE
-        if (tree == s->bl_tree) {
-            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
-                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
-        }
-#endif
-        /* and insert the new node in the heap */
-        s->heap[SMALLEST] = node++;
-        pqdownheap(s, tree, SMALLEST);
-
-    } while (s->heap_len >= 2);
-
-    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
-
-    /* At this point, the fields freq and dad are set. We can now
-     * generate the bit lengths.
-     */
-    gen_bitlen(s, (tree_desc *)desc);
-
-    /* The field len is now set, we can generate the bit codes */
-    gen_codes ((ct_data *)tree, max_code, s->bl_count);
-}
-
-/* ===========================================================================
- * Scan a literal or distance tree to determine the frequencies of the codes
- * in the bit length tree.
- */
-local void scan_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree;   /* the tree to be scanned */
-    int max_code;    /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    if (nextlen == 0) max_count = 138, min_count = 3;
-    tree[max_code+1].Len = (ush)0xffff; /* guard */
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            s->bl_tree[curlen].Freq += count;
-        } else if (curlen != 0) {
-            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
-            s->bl_tree[REP_3_6].Freq++;
-        } else if (count <= 10) {
-            s->bl_tree[REPZ_3_10].Freq++;
-        } else {
-            s->bl_tree[REPZ_11_138].Freq++;
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Send a literal or distance tree in compressed form, using the codes in
- * bl_tree.
- */
-local void send_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree; /* the tree to be scanned */
-    int max_code;       /* and its largest code of non zero frequency */
-{
-    int n;                     /* iterates over all tree elements */
-    int prevlen = -1;          /* last emitted length */
-    int curlen;                /* length of current code */
-    int nextlen = tree[0].Len; /* length of next code */
-    int count = 0;             /* repeat count of the current code */
-    int max_count = 7;         /* max repeat count */
-    int min_count = 4;         /* min repeat count */
-
-    /* tree[max_code+1].Len = -1; */  /* guard already set */
-    if (nextlen == 0) max_count = 138, min_count = 3;
-
-    for (n = 0; n <= max_code; n++) {
-        curlen = nextlen; nextlen = tree[n+1].Len;
-        if (++count < max_count && curlen == nextlen) {
-            continue;
-        } else if (count < min_count) {
-            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
-
-        } else if (curlen != 0) {
-            if (curlen != prevlen) {
-                send_code(s, curlen, s->bl_tree); count--;
-            }
-            Assert(count >= 3 && count <= 6, " 3_6?");
-            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
-
-        } else if (count <= 10) {
-            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
-
-        } else {
-            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
-        }
-        count = 0; prevlen = curlen;
-        if (nextlen == 0) {
-            max_count = 138, min_count = 3;
-        } else if (curlen == nextlen) {
-            max_count = 6, min_count = 3;
-        } else {
-            max_count = 7, min_count = 4;
-        }
-    }
-}
-
-/* ===========================================================================
- * Construct the Huffman tree for the bit lengths and return the index in
- * bl_order of the last bit length code to send.
- */
-local int build_bl_tree(s)
-    deflate_state *s;
-{
-    int max_blindex;  /* index of last bit length code of non zero freq */
-
-    /* Determine the bit length frequencies for literal and distance trees */
-    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
-    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
-
-    /* Build the bit length tree: */
-    build_tree(s, (tree_desc *)(&(s->bl_desc)));
-    /* opt_len now includes the length of the tree representations, except
-     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-     */
-
-    /* Determine the number of bit length codes to send. The pkzip format
-     * requires that at least 4 bit length codes be sent. (appnote.txt says
-     * 3 but the actual value used is 4.)
-     */
-    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
-        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
-    }
-    /* Update opt_len to include the bit length tree and counts */
-    s->opt_len += 3*(max_blindex+1) + 5+5+4;
-    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
-            s->opt_len, s->static_len));
-
-    return max_blindex;
-}
-
-/* ===========================================================================
- * Send the header for a block using dynamic Huffman trees: the counts, the
- * lengths of the bit length codes, the literal tree and the distance tree.
- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
- */
-local void send_all_trees(s, lcodes, dcodes, blcodes)
-    deflate_state *s;
-    int lcodes, dcodes, blcodes; /* number of codes for each tree */
-{
-    int rank;                    /* index in bl_order */
-
-    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
-    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
-            "too many codes");
-    Tracev((stderr, "\nbl counts: "));
-    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
-    send_bits(s, dcodes-1,   5);
-    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
-    for (rank = 0; rank < blcodes; rank++) {
-        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
-        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
-    }
-    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
-    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
-
-    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
-    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
-}
-
-/* ===========================================================================
- * Send a stored block
- */
-void _tr_stored_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
-    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
-    s->compressed_len += (stored_len + 4) << 3;
-
-    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
-}
-
-/* Send just the `stored block' type code without any length bytes or data.
- */
-void _tr_stored_type_only(s)
-    deflate_state *s;
-{
-    send_bits(s, (STORED_BLOCK << 1), 3);
-    bi_windup(s);
-    s->compressed_len = (s->compressed_len + 3) & ~7L;
-}
-
-
-/* ===========================================================================
- * Send one empty static block to give enough lookahead for inflate.
- * This takes 10 bits, of which 7 may remain in the bit buffer.
- * The current inflate code requires 9 bits of lookahead. If the
- * last two codes for the previous block (real code plus EOB) were coded
- * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
- * the last real code. In this case we send two empty static blocks instead
- * of one. (There are no problems if the previous block is stored or fixed.)
- * To simplify the code, we assume the worst case of last real code encoded
- * on one bit only.
- */
-void _tr_align(s)
-    deflate_state *s;
-{
-    send_bits(s, STATIC_TREES<<1, 3);
-    send_code(s, END_BLOCK, static_ltree);
-    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
-    bi_flush(s);
-    /* Of the 10 bits for the empty block, we have already sent
-     * (10 - bi_valid) bits. The lookahead for the last real code (before
-     * the EOB of the previous block) was thus at least one plus the length
-     * of the EOB plus what we have just sent of the empty static block.
-     */
-    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
-        send_bits(s, STATIC_TREES<<1, 3);
-        send_code(s, END_BLOCK, static_ltree);
-        s->compressed_len += 10L;
-        bi_flush(s);
-    }
-    s->last_eob_len = 7;
-}
-
-/* ===========================================================================
- * Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and output the encoded block to the zip file. This function
- * returns the total compressed length for the file so far.
- */
-ulg _tr_flush_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block, or NULL if too old */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
-{
-    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
-    int max_blindex = 0;  /* index of last bit length code of non zero freq */
-
-    /* Build the Huffman trees unless a stored block is forced */
-    if (s->level > 0) {
-
-	 /* Check if the file is ascii or binary */
-	if (s->data_type == Z_UNKNOWN) set_data_type(s);
-
-	/* Construct the literal and distance trees */
-	build_tree(s, (tree_desc *)(&(s->l_desc)));
-	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-
-	build_tree(s, (tree_desc *)(&(s->d_desc)));
-	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
-		s->static_len));
-	/* At this point, opt_len and static_len are the total bit lengths of
-	 * the compressed block data, excluding the tree representations.
-	 */
-
-	/* Build the bit length tree for the above two trees, and get the index
-	 * in bl_order of the last bit length code to send.
-	 */
-	max_blindex = build_bl_tree(s);
-
-	/* Determine the best encoding. Compute first the block length in bytes*/
-	opt_lenb = (s->opt_len+3+7)>>3;
-	static_lenb = (s->static_len+3+7)>>3;
-
-	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
-		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
-		s->last_lit));
-
-	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
-
-    } else {
-        Assert(buf != (char*)0, "lost buf");
-	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
-    }
-
-    /* If compression failed and this is the first and last block,
-     * and if the .zip file can be seeked (to rewrite the local header),
-     * the whole file is transformed into a stored file:
-     */
-#ifdef STORED_FILE_OK
-#  ifdef FORCE_STORED_FILE
-    if (eof && s->compressed_len == 0L) { /* force stored file */
-#  else
-    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
-#  endif
-        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
-        if (buf == (charf*)0) error ("block vanished");
-
-        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
-        s->compressed_len = stored_len << 3;
-        s->method = STORED;
-    } else
-#endif /* STORED_FILE_OK */
-
-#ifdef FORCE_STORED
-    if (buf != (char*)0) { /* force stored block */
-#else
-    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
-                       /* 4: two words for the lengths */
-#endif
-        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-         * Otherwise we can't have processed more than WSIZE input bytes since
-         * the last block flush, because compression would have been
-         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-         * transform a block into a stored block.
-         */
-        _tr_stored_block(s, buf, stored_len, eof);
-
-#ifdef FORCE_STATIC
-    } else if (static_lenb >= 0) { /* force static trees */
-#else
-    } else if (static_lenb == opt_lenb) {
-#endif
-        send_bits(s, (STATIC_TREES<<1)+eof, 3);
-        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
-        s->compressed_len += 3 + s->static_len;
-    } else {
-        send_bits(s, (DYN_TREES<<1)+eof, 3);
-        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
-                       max_blindex+1);
-        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
-        s->compressed_len += 3 + s->opt_len;
-    }
-    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
-    init_block(s);
-
-    if (eof) {
-        bi_windup(s);
-        s->compressed_len += 7;  /* align on byte boundary */
-    }
-    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
-           s->compressed_len-7*eof));
-
-    return s->compressed_len >> 3;
-}
-
-/* ===========================================================================
- * Save the match info and tally the frequency counts. Return true if
- * the current block must be flushed.
- */
-int _tr_tally (s, dist, lc)
-    deflate_state *s;
-    unsigned dist;  /* distance of matched string */
-    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
-{
-    s->d_buf[s->last_lit] = (ush)dist;
-    s->l_buf[s->last_lit++] = (uch)lc;
-    if (dist == 0) {
-        /* lc is the unmatched char */
-        s->dyn_ltree[lc].Freq++;
-    } else {
-        s->matches++;
-        /* Here, lc is the match length - MIN_MATCH */
-        dist--;             /* dist = match distance - 1 */
-        Assert((ush)dist < (ush)MAX_DIST(s) &&
-               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
-               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
-
-        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
-        s->dyn_dtree[d_code(dist)].Freq++;
-    }
-
-    /* Try to guess if it is profitable to stop the current block here */
-    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
-        /* Compute an upper bound for the compressed length */
-        ulg out_length = (ulg)s->last_lit*8L;
-        ulg in_length = (ulg)((long)s->strstart - s->block_start);
-        int dcode;
-        for (dcode = 0; dcode < D_CODES; dcode++) {
-            out_length += (ulg)s->dyn_dtree[dcode].Freq *
-                (5L+extra_dbits[dcode]);
-        }
-        out_length >>= 3;
-        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
-               s->last_lit, in_length, out_length,
-               100L - out_length*100L/in_length));
-        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
-    }
-    return (s->last_lit == s->lit_bufsize-1);
-    /* We avoid equality with lit_bufsize because of wraparound at 64K
-     * on 16 bit machines and because stored blocks are restricted to
-     * 64K-1 bytes.
-     */
-}
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-local void compress_block(s, ltree, dtree)
-    deflate_state *s;
-    ct_data *ltree; /* literal tree */
-    ct_data *dtree; /* distance tree */
-{
-    unsigned dist;      /* distance of matched string */
-    int lc;             /* match length or unmatched char (if dist == 0) */
-    unsigned lx = 0;    /* running index in l_buf */
-    unsigned code;      /* the code to send */
-    int extra;          /* number of extra bits to send */
-
-    if (s->last_lit != 0) do {
-        dist = s->d_buf[lx];
-        lc = s->l_buf[lx++];
-        if (dist == 0) {
-            send_code(s, lc, ltree); /* send a literal byte */
-            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
-        } else {
-            /* Here, lc is the match length - MIN_MATCH */
-            code = length_code[lc];
-            send_code(s, code+LITERALS+1, ltree); /* send the length code */
-            extra = extra_lbits[code];
-            if (extra != 0) {
-                lc -= base_length[code];
-                send_bits(s, lc, extra);       /* send the extra length bits */
-            }
-            dist--; /* dist is now the match distance - 1 */
-            code = d_code(dist);
-            Assert (code < D_CODES, "bad d_code");
-
-            send_code(s, code, dtree);       /* send the distance code */
-            extra = extra_dbits[code];
-            if (extra != 0) {
-                dist -= base_dist[code];
-                send_bits(s, dist, extra);   /* send the extra distance bits */
-            }
-        } /* literal or match pair ? */
-
-        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
-        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
-
-    } while (lx < s->last_lit);
-
-    send_code(s, END_BLOCK, ltree);
-    s->last_eob_len = ltree[END_BLOCK].Len;
-}
-
-/* ===========================================================================
- * Set the data type to ASCII or BINARY, using a crude approximation:
- * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
- * IN assertion: the fields freq of dyn_ltree are set and the total of all
- * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
- */
-local void set_data_type(s)
-    deflate_state *s;
-{
-    int n = 0;
-    unsigned ascii_freq = 0;
-    unsigned bin_freq = 0;
-    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
-    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
-    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
-    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
-}
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-local unsigned bi_reverse(code, len)
-    unsigned code; /* the value to invert */
-    int len;       /* its bit length */
-{
-    register unsigned res = 0;
-    do {
-        res |= code & 1;
-        code >>= 1, res <<= 1;
-    } while (--len > 0);
-    return res >> 1;
-}
-
-/* ===========================================================================
- * Flush the bit buffer, keeping at most 7 bits in it.
- */
-local void bi_flush(s)
-    deflate_state *s;
-{
-    if (s->bi_valid == 16) {
-        put_short(s, s->bi_buf);
-        s->bi_buf = 0;
-        s->bi_valid = 0;
-    } else if (s->bi_valid >= 8) {
-        put_byte(s, (Byte)s->bi_buf);
-        s->bi_buf >>= 8;
-        s->bi_valid -= 8;
-    }
-}
-
-/* ===========================================================================
- * Flush the bit buffer and align the output on a byte boundary
- */
-local void bi_windup(s)
-    deflate_state *s;
-{
-    if (s->bi_valid > 8) {
-        put_short(s, s->bi_buf);
-    } else if (s->bi_valid > 0) {
-        put_byte(s, (Byte)s->bi_buf);
-    }
-    s->bi_buf = 0;
-    s->bi_valid = 0;
-#ifdef DEBUG_ZLIB
-    s->bits_sent = (s->bits_sent+7) & ~7;
-#endif
-}
-
-/* ===========================================================================
- * Copy a stored block, storing first the length and its
- * one's complement if requested.
- */
-local void copy_block(s, buf, len, header)
-    deflate_state *s;
-    charf    *buf;    /* the input data */
-    unsigned len;     /* its length */
-    int      header;  /* true if block header must be written */
-{
-    bi_windup(s);        /* align on byte boundary */
-    s->last_eob_len = 8; /* enough lookahead for inflate */
-
-    if (header) {
-        put_short(s, (ush)len);   
-        put_short(s, (ush)~len);
-#ifdef DEBUG_ZLIB
-        s->bits_sent += 2*16;
-#endif
-    }
-#ifdef DEBUG_ZLIB
-    s->bits_sent += (ulg)len<<3;
-#endif
-    /* bundle up the put_byte(s, *buf++) calls */
-    zmemcpy(&s->pending_buf[s->pending], buf, len);
-    s->pending += len;
-}
-/* --- trees.c */
-
-/* +++ inflate.c */
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-
-/* +++ infblock.h */
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1996 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;
-
-extern inflate_blocks_statef * inflate_blocks_new OF((
-    z_streamp z,
-    check_func c,               /* check function */
-    uInt w));                   /* window size */
-
-extern int inflate_blocks OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));                      /* initial return code */
-
-extern void inflate_blocks_reset OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern int inflate_blocks_free OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLongf *));                  /* check value on output */
-
-extern void inflate_set_dictionary OF((
-    inflate_blocks_statef *s,
-    const Bytef *d,  /* dictionary */
-    uInt  n));       /* dictionary length */
-
-extern int inflate_addhistory OF((
-    inflate_blocks_statef *,
-    z_streamp));
-
-extern int inflate_packet_flush OF((
-    inflate_blocks_statef *));
-/* --- infblock.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* inflate private state */
-struct internal_state {
-
-  /* mode */
-  enum {
-      METHOD,   /* waiting for method byte */
-      FLAG,     /* waiting for flag byte */
-      DICT4,    /* four dictionary check bytes to go */
-      DICT3,    /* three dictionary check bytes to go */
-      DICT2,    /* two dictionary check bytes to go */
-      DICT1,    /* one dictionary check byte to go */
-      DICT0,    /* waiting for inflateSetDictionary */
-      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_streamp 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_streamp 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);
-  z->state = Z_NULL;
-  Trace((stderr, "inflate: end\n"));
-  return Z_OK;
-}
-
-
-int inflateInit2_(z, w, version, stream_size)
-z_streamp z;
-int w;
-const char *version;
-int stream_size;
-{
-  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-      stream_size != sizeof(z_stream))
-      return Z_VERSION_ERROR;
-
-  /* initialize state */
-  if (z == Z_NULL)
-    return Z_STREAM_ERROR;
-  z->msg = Z_NULL;
-#ifndef NO_ZCFUNCS
-  if (z->zalloc == Z_NULL)
-  {
-    z->zalloc = zcalloc;
-    z->opaque = (voidpf)0;
-  }
-  if (z->zfree == Z_NULL) z->zfree = zcfree;
-#endif
-  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, (uInt)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, version, stream_size)
-z_streamp z;
-const char *version;
-int stream_size;
-{
-  return inflateInit2_(z, DEF_WBITS, version, stream_size);
-}
-
-
-#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_streamp z;
-int f;
-{
-  int r;
-  uInt b;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
-    return Z_STREAM_ERROR;
-  r = Z_BUF_ERROR;
-  while (1) switch (z->state->mode)
-  {
-    case METHOD:
-      NEEDBYTE
-      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"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 = (char*)"invalid window size";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = FLAG;
-    case FLAG:
-      NEEDBYTE
-      b = NEXTBYTE;
-      if (((z->state->sub.method << 8) + b) % 31)
-      {
-        z->state->mode = BAD;
-        z->msg = (char*)"incorrect header check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      Trace((stderr, "inflate: zlib header ok\n"));
-      if (!(b & PRESET_DICT))
-      {
-        z->state->mode = BLOCKS;
-	break;
-      }
-      z->state->mode = DICT4;
-    case DICT4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = DICT3;
-    case DICT3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = DICT2;
-    case DICT2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = DICT1;
-    case DICT1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-      z->adler = z->state->sub.check.need;
-      z->state->mode = DICT0;
-      return Z_NEED_DICT;
-    case DICT0:
-      z->state->mode = BAD;
-      z->msg = (char*)"need dictionary";
-      z->state->sub.marker = 0;       /* can try inflateSync */
-      return Z_STREAM_ERROR;
-    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 = (char*)"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->msg = (char *)"need more for packet flush";
-  z->state->sub.marker = 0;       /* can try inflateSync */
-  return Z_DATA_ERROR;
-}
-
-
-int inflateSetDictionary(z, dictionary, dictLength)
-z_streamp z;
-const Bytef *dictionary;
-uInt  dictLength;
-{
-  uInt length = dictLength;
-
-  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
-    return Z_STREAM_ERROR;
-
-  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
-  z->adler = 1L;
-
-  if (length >= ((uInt)1<<z->state->wbits))
-  {
-    length = (1<<z->state->wbits)-1;
-    dictionary += dictLength - length;
-  }
-  inflate_set_dictionary(z->state->blocks, dictionary, length);
-  z->state->mode = BLOCKS;
-  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.
- */
-
-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_streamp 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
-/* --- inflate.c */
-
-/* +++ infblock.c */
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-
-/* +++ inftrees.h */
-/* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1996 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;
-    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
-  extern uInt inflate_hufts;
-#endif
-
-extern int inflate_trees_bits OF((
-    uIntf *,                    /* 19 code lengths */
-    uIntf *,                    /* bits tree desired/actual depth */
-    inflate_huft * FAR *,       /* bits tree result */
-    z_streamp ));               /* for zalloc, zfree functions */
-
-extern 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_streamp ));               /* for zalloc, zfree functions */
-
-extern 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 */
-
-extern int inflate_trees_free OF((
-    inflate_huft *,             /* tables to free */
-    z_streamp ));               /* for zfree function */
-
-/* --- inftrees.h */
-
-/* +++ infcodes.h */
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1996 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;
-
-extern inflate_codes_statef *inflate_codes_new OF((
-    uInt, uInt,
-    inflate_huft *, inflate_huft *,
-    z_streamp ));
-
-extern int inflate_codes OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-extern void inflate_codes_free OF((
-    inflate_codes_statef *,
-    z_streamp ));
-
-/* --- infcodes.h */
-
-/* +++ infutil.h */
-/* infutil.h -- types and macros common to blocks and codes
- * Copyright (C) 1995-1996 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.
- */
-
-#ifndef _INFUTIL_H
-#define _INFUTIL_H
-
-typedef 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 */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
-  /* mode */
-  inflate_block_mode  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 */
-    } trees;            /* if DTREE, decoding info for trees */
-    struct {
-      inflate_huft *tl;
-      inflate_huft *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 (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
-#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
-#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-/*   load local pointers */
-#define LOAD {LOADIN LOADOUT}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int inflate_flush OF((
-    inflate_blocks_statef *,
-    z_streamp ,
-    int));
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#endif
-/* --- infutil.h */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* Table for deflate from PKZIP's appnote.txt. */
-local const 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.
- */
-
-
-void inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  if (s->checkfn != Z_NULL)
-    *c = s->check;
-  if (s->mode == BTREE || s->mode == DTREE)
-    ZFREE(z, s->sub.trees.blens);
-  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)
-    z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
-  Trace((stderr, "inflate:   blocks reset\n"));
-}
-
-
-inflate_blocks_statef *inflate_blocks_new(z, c, w)
-z_streamp 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);
-    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;
-}
-
-
-#ifdef DEBUG_ZLIB
-  extern uInt inflate_hufts;
-#endif
-int inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_streamp 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 = (char*)"invalid block type";
-          r = Z_DATA_ERROR;
-          LEAVE
-      }
-      break;
-    case LENS:
-      NEEDBITS(32)
-      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-      {
-        s->mode = BADB;
-        z->msg = (char*)"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 : (s->last ? DRY : 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 = (char*)"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
-      }
-      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)
-	{
-	  ZFREE(z, s->sub.trees.blens);
-          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))
-          {
-            inflate_trees_free(s->sub.trees.tb, z);
-            ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-            z->msg = (char*)"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;
-#ifdef DEBUG_ZLIB
-      inflate_hufts = 0;
-#endif
-        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)
-	  {
-	    ZFREE(z, s->sub.trees.blens);
-            s->mode = BADB;
-	  }
-          r = t;
-          LEAVE
-        }
-        Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
-              inflate_hufts, sizeof(inflate_huft)));
-        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.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
-  }
-}
-
-
-int inflate_blocks_free(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
-{
-  inflate_blocks_reset(s, z, c);
-  ZFREE(z, s->window);
-  ZFREE(z, s);
-  Trace((stderr, "inflate:   blocks freed\n"));
-  return Z_OK;
-}
-
-
-void inflate_set_dictionary(s, d, n)
-inflate_blocks_statef *s;
-const Bytef *d;
-uInt  n;
-{
-  zmemcpy((charf *)s->window, d, n);
-  s->read = s->write = s->window + n;
-}
-
-/*
- * 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 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 */
-/*      WWRAP  */ 	/* expand WWRAP 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.
- */
-int inflate_packet_flush(s)
-    inflate_blocks_statef *s;
-{
-    if (s->mode != LENS)
-	return Z_DATA_ERROR;
-    s->mode = TYPE;
-    return Z_OK;
-}
-/* --- infblock.c */
-
-/* +++ inftrees.c */
-/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-
-char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state  {int dummy;}; /* for buggy compilers */
-#endif
-
-/* 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 */
-    const uIntf *,      /* list of base values for non-simple codes */
-    const uIntf *,      /* list of extra bits for non-simple codes */
-    inflate_huft * FAR*,/* result: starting table */
-    uIntf *,            /* maximum lookup bits (returns actual) */
-    z_streamp ));       /* for zalloc function */
-
-local voidpf falloc OF((
-    voidpf,             /* opaque pointer (not used) */
-    uInt,               /* number of items */
-    uInt));             /* size of item */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-local const uInt cplens[31] = { /* 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};
-        /* see note #13 above about 258 */
-local const uInt cplext[31] = { /* 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, 112, 112}; /* 112==invalid */
-local const uInt cpdist[30] = { /* 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 const uInt cpdext[30] = { /* 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) */
-const uIntf *d;         /* list of base values for non-simple codes */
-const 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_streamp 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 (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);
-  n = x[g];                   /* set n to length of v */
-
-
-  /* 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 = g - w;
-        z = z > (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 */
-        }
-#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;
-}
-
-
-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_streamp 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 = (char*)"oversubscribed dynamic bit lengths tree";
-  else if (r == Z_BUF_ERROR || *bb == 0)
-  {
-    inflate_trees_free(*tb, z);
-    z->msg = (char*)"incomplete dynamic bit lengths tree";
-    r = Z_DATA_ERROR;
-  }
-  return r;
-}
-
-
-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_streamp z;            /* for zfree function */
-{
-  int r;
-
-  /* build literal/length tree */
-  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
-  if (r != Z_OK || *bl == 0)
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed literal/length tree";
-    else if (r != Z_MEM_ERROR)
-    {
-      inflate_trees_free(*tl, z);
-      z->msg = (char*)"incomplete literal/length tree";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-  }
-
-  /* build distance tree */
-  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
-  if (r != Z_OK || (*bd == 0 && nl > 257))
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed distance tree";
-    else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
-      r = Z_OK;
-    }
-#else
-      inflate_trees_free(*td, z);
-      z->msg = (char*)"incomplete distance tree";
-      r = Z_DATA_ERROR;
-    }
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"empty distance tree with lengths";
-      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_built = 0;
-#define FIXEDH 530      /* number of hufts used by fixed tables */
-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 */
-uInt n;         /* number of items */
-uInt s;         /* size of item */
-{
-  Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
-         "inflate_trees falloc overflow");
-  *(intf *)q -= n+s-s; /* s-s to avoid warning */
-  return (voidpf)(fixed_mem + *(intf *)q);
-}
-
-
-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 already (multiple overlapped executions ok) */
-  if (!fixed_built)
-  {
-    int k;              /* temporary variable */
-    unsigned c[288];    /* length list for huft_build */
-    z_stream z;         /* for falloc function */
-    int f = FIXEDH;     /* number of hufts left in fixed_mem */
-
-    /* set up fake z_stream for memory routines */
-    z.zalloc = falloc;
-    z.zfree = Z_NULL;
-    z.opaque = (voidpf)&f;
-
-    /* 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 */
-    Assert(f == 0, "invalid build of fixed tables");
-    fixed_built = 1;
-  }
-  *bl = fixed_bl;
-  *bd = fixed_bd;
-  *tl = fixed_tl;
-  *td = fixed_td;
-  return Z_OK;
-}
-
-
-int inflate_trees_free(t, z)
-inflate_huft *t;        /* table to free */
-z_streamp 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, *r;
-
-  /* Reverse linked list */
-  p = Z_NULL;
-  q = t;
-  while (q != Z_NULL)
-  {
-    r = (q - 1)->next;
-    (q - 1)->next = p;
-    p = q;
-    q = r;
-  }
-  /* Go through linked list, freeing from the malloced (t[-1]) address. */
-  while (p != Z_NULL)
-  {
-    q = (--p)->next;
-    ZFREE(z,p);
-    p = q;
-  } 
-  return Z_OK;
-}
-/* --- inftrees.c */
-
-/* +++ infcodes.c */
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-/* +++ inffast.h */
-/* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1996 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.
- */
-
-extern int inflate_fast OF((
-    uInt,
-    uInt,
-    inflate_huft *,
-    inflate_huft *,
-    inflate_blocks_statef *,
-    z_streamp ));
-/* --- inffast.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 */
-
-};
-
-
-inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-z_streamp 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;
-}
-
-
-int inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_streamp 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 = (char*)"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 = (char*)"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 - (uInt)(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
-  }
-}
-
-
-void inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_streamp z;
-{
-  ZFREE(z, c);
-  Tracev((stderr, "inflate:       codes free\n"));
-}
-/* --- infcodes.c */
-
-/* +++ infutil.c */
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "infblock.h" */
-/* #include "inftrees.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt inflate_mask[17] = {
-    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 */
-int inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
-{
-  uInt n;
-  Bytef *p;
-  Bytef *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)
-    z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-  /* copy as far as end of window */
-  if (p != Z_NULL) {
-    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)
-      z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-    /* copy */
-    if (p != Z_NULL) {
-      zmemcpy(p, q, n);
-      p += n;
-    }
-    q += n;
-  }
-
-  /* update pointers */
-  z->next_out = p;
-  s->read = q;
-
-  /* done */
-  return r;
-}
-/* --- infutil.c */
-
-/* +++ inffast.c */
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* #include "zutil.h" */
-/* #include "inftrees.h" */
-/* #include "infblock.h" */
-/* #include "infcodes.h" */
-/* #include "infutil.h" */
-/* #include "inffast.h" */
-
-#ifndef NO_DUMMY_DECL
-struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-#endif
-
-/* 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. */
-
-int inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-inflate_blocks_statef *s;
-z_streamp 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 - (uInt)(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 = (char*)"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 = (char*)"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;
-}
-/* --- inffast.c */
-
-/* +++ zutil.c */
-/* zutil.c -- target dependent utility functions for the compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
-
-/* #include "zutil.h" */
-
-#ifndef NO_DUMMY_DECL
-struct internal_state      {int dummy;}; /* for buggy compilers */
-#endif
-
-#ifndef STDC
-extern void exit OF((int));
-#endif
-
-const char *z_errmsg[10] = {
-"need dictionary",     /* Z_NEED_DICT       2  */
-"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) */
-"incompatible version",/* Z_VERSION_ERROR (-6) */
-""};
-
-
-const char *zlibVersion()
-{
-    return ZLIB_VERSION;
-}
-
-#ifdef DEBUG_ZLIB
-void z_error (m)
-    char *m;
-{
-    fprintf(stderr, "%s\n", m);
-    exit(1);
-}
-#endif
-
-#ifndef HAVE_MEMCPY
-
-void zmemcpy(dest, source, len)
-    Bytef* dest;
-    Bytef* source;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = *source++; /* ??? to be unrolled */
-    } while (--len != 0);
-}
-
-int zmemcmp(s1, s2, len)
-    Bytef* s1;
-    Bytef* s2;
-    uInt  len;
-{
-    uInt j;
-
-    for (j = 0; j < len; j++) {
-        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
-    }
-    return 0;
-}
-
-void zmemzero(dest, len)
-    Bytef* dest;
-    uInt  len;
-{
-    if (len == 0) return;
-    do {
-        *dest++ = 0;  /* ??? to be unrolled */
-    } while (--len != 0);
-}
-#endif
-
-#ifdef __TURBOC__
-#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
-/* Small and medium model in Turbo C are for now limited to near allocation
- * with reduced MAX_WBITS and MAX_MEM_LEVEL
- */
-#  define MY_ZCALLOC
-
-/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
- * and farmalloc(64K) returns a pointer with an offset of 8, so we
- * must fix the pointer. Warning: the pointer must be put back to its
- * original form in order to free it, use zcfree().
- */
-
-#define MAX_PTR 10
-/* 10*64K = 640K */
-
-local int next_ptr = 0;
-
-typedef struct ptr_table_s {
-    voidpf org_ptr;
-    voidpf new_ptr;
-} ptr_table;
-
-local ptr_table table[MAX_PTR];
-/* This table is used to remember the original form of pointers
- * to large buffers (64K). Such pointers are normalized with a zero offset.
- * Since MSDOS is not a preemptive multitasking OS, this table is not
- * protected from concurrent access. This hack doesn't work anyway on
- * a protected system like OS/2. Use Microsoft C instead.
- */
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    voidpf buf = opaque; /* just to make some compilers happy */
-    ulg bsize = (ulg)items*size;
-
-    /* If we allocate less than 65520 bytes, we assume that farmalloc
-     * will return a usable pointer which doesn't have to be normalized.
-     */
-    if (bsize < 65520L) {
-        buf = farmalloc(bsize);
-        if (*(ush*)&buf != 0) return buf;
-    } else {
-        buf = farmalloc(bsize + 16L);
-    }
-    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
-    table[next_ptr].org_ptr = buf;
-
-    /* Normalize the pointer to seg:0 */
-    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
-    *(ush*)&buf = 0;
-    table[next_ptr++].new_ptr = buf;
-    return buf;
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    int n;
-    if (*(ush*)&ptr != 0) { /* object < 64K */
-        farfree(ptr);
-        return;
-    }
-    /* Find the original pointer */
-    for (n = 0; n < next_ptr; n++) {
-        if (ptr != table[n].new_ptr) continue;
-
-        farfree(table[n].org_ptr);
-        while (++n < next_ptr) {
-            table[n-1] = table[n];
-        }
-        next_ptr--;
-        return;
-    }
-    ptr = opaque; /* just to make some compilers happy */
-    Assert(0, "zcfree: ptr not found");
-}
-#endif
-#endif /* __TURBOC__ */
-
-
-#if defined(M_I86) && !defined(__32BIT__)
-/* Microsoft C in 16-bit mode */
-
-#  define MY_ZCALLOC
-
-#if (!defined(_MSC_VER) || (_MSC_VER < 600))
-#  define _halloc  halloc
-#  define _hfree   hfree
-#endif
-
-voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    return _halloc((long)items, size);
-}
-
-void  zcfree (voidpf opaque, voidpf ptr)
-{
-    if (opaque) opaque = 0; /* to make compiler happy */
-    _hfree(ptr);
-}
-
-#endif /* MSC */
-
-
-#ifndef MY_ZCALLOC /* Any system without a special alloc function */
-
-#ifndef STDC
-extern voidp  calloc OF((uInt items, uInt size));
-extern void   free   OF((voidpf ptr));
-#endif
-
-voidpf zcalloc (opaque, items, size)
-    voidpf opaque;
-    unsigned items;
-    unsigned size;
-{
-    if (opaque) items += size - size; /* make compiler happy */
-    return (voidpf)calloc(items, size);
-}
-
-void  zcfree (opaque, ptr)
-    voidpf opaque;
-    voidpf ptr;
-{
-    free(ptr);
-    if (opaque) return; /* make compiler happy */
-}
-
-#endif /* MY_ZCALLOC */
-/* --- zutil.c */
-
-/* +++ adler32.c */
-/* adler32.c -- compute the Adler-32 checksum of a data stream
- * Copyright (C) 1995-1996 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
-
-/* #include "zlib.h" */
-
-#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,i)  {s1 += buf[i]; s2 += s1;}
-#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf)   DO8(buf,0); DO8(buf,8);
-
-/* ========================================================================= */
-uLong adler32(adler, buf, len)
-    uLong adler;
-    const 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);
-	    buf += 16;
-            k -= 16;
-        }
-        if (k != 0) do {
-            s1 += *buf++;
-	    s2 += s1;
-        } while (--k);
-        s1 %= BASE;
-        s2 %= BASE;
-    }
-    return (s2 << 16) | s1;
-}
-/* --- adler32.c */
diff -urN linux-2.4.20-pre1/fs/jffs2/zlib.h linux-2.4.20-pre2/fs/jffs2/zlib.h
--- linux-2.4.20-pre1/fs/jffs2/zlib.h	Fri Sep 14 14:04:07 2001
+++ linux-2.4.20-pre2/fs/jffs2/zlib.h	Wed Dec 31 16:00:00 1969
@@ -1,1010 +0,0 @@
-/*	$Id: zlib.h,v 1.2 1997/12/23 10:47:44 paulus Exp $	*/
-
-/*
- * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
- * 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 971127==
- *
- * 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 */
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.0.4, Jul 24th, 1996.
-
-  Copyright (C) 1995-1996 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
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef _ZLIB_H
-#define _ZLIB_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* +++ zconf.h */
-/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-1996 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
-
-#ifndef _ZCONF_H
-#define _ZCONF_H
-
-/*
- * If you *really* need a unique prefix for all types and library functions,
- * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
- */
-#ifdef Z_PREFIX
-#  define deflateInit_	z_deflateInit_
-#  define deflate	z_deflate
-#  define deflateEnd	z_deflateEnd
-#  define inflateInit_ 	z_inflateInit_
-#  define inflate	z_inflate
-#  define inflateEnd	z_inflateEnd
-#  define deflateInit2_	z_deflateInit2_
-#  define deflateSetDictionary z_deflateSetDictionary
-#  define deflateCopy	z_deflateCopy
-#  define deflateReset	z_deflateReset
-#  define deflateParams	z_deflateParams
-#  define inflateInit2_	z_inflateInit2_
-#  define inflateSetDictionary z_inflateSetDictionary
-#  define inflateSync	z_inflateSync
-#  define inflateReset	z_inflateReset
-#  define compress	z_compress
-#  define uncompress	z_uncompress
-#  define adler32	z_adler32
-#  define crc32		z_crc32
-#  define get_crc_table z_get_crc_table
-
-#  define Byte		z_Byte
-#  define uInt		z_uInt
-#  define uLong		z_uLong
-#  define Bytef	        z_Bytef
-#  define charf		z_charf
-#  define intf		z_intf
-#  define uIntf		z_uIntf
-#  define uLongf	z_uLongf
-#  define voidpf	z_voidpf
-#  define voidp		z_voidp
-#endif
-
-#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
-#  define WIN32
-#endif
-#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
-#  ifndef __32BIT__
-#    define __32BIT__
-#  endif
-#endif
-#if defined(__MSDOS__) && !defined(MSDOS)
-#  define MSDOS
-#endif
-
-/*
- * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
- * than 64k bytes at a time (needed on systems with 16-bit int).
- */
-#if defined(MSDOS) && !defined(__32BIT__)
-#  define MAXSEG_64K
-#endif
-#ifdef MSDOS
-#  define UNALIGNED_OK
-#endif
-
-#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
-#  define STDC
-#endif
-#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
-#  define STDC
-#endif
-
-#ifndef STDC
-#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
-#    define const
-#  endif
-#endif
-
-/* Some Mac compilers merge all .h files incorrectly: */
-#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
-#  define NO_DUMMY_DECL
-#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
-
-/* 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
-
-/* The following definitions for FAR are needed only for MSDOS mixed
- * model programming (small or medium model with some far allocations).
- * This was tested only with MSC; for other MSDOS compilers you may have
- * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
- * just define FAR to be empty.
- */
-#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
-   /* MSC small or medium model */
-#  define SMALL_MEDIUM
-#  ifdef _MSC_VER
-#    define FAR __far
-#  else
-#    define FAR far
-#  endif
-#endif
-#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
-#  ifndef __32BIT__
-#    define SMALL_MEDIUM
-#    define FAR __far
-#  endif
-#endif
-#ifndef FAR
-#   define FAR
-#endif
-
-typedef unsigned char  Byte;  /* 8 bits */
-typedef unsigned int   uInt;  /* 16 bits or more */
-typedef unsigned long  uLong; /* 32 bits or more */
-
-#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
-   /* Borland C/C++ ignores FAR inside typedef */
-#  define Bytef Byte FAR
-#else
-   typedef Byte  FAR Bytef;
-#endif
-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
-
-
-/* Compile with -DZLIB_DLL for Windows DLL support */
-#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
-#  include <windows.h>
-#  define EXPORT  WINAPI
-#else
-#  define EXPORT
-#endif
-
-#endif /* _ZCONF_H */
-/* --- zconf.h */
-
-#define ZLIB_VERSION "1.0.4P"
-
-/* 
-     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.
-
-     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.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-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 */
-    voidpf     opaque;  /* private data object passed to zalloc and zfree */
-
-    int     data_type;  /* best guess about the data type: ascii or binary */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-   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_PACKET_FLUSH	2
-#define Z_SYNC_FLUSH    3
-#define Z_FULL_FLUSH    4
-#define Z_FINISH        5
-/* Allowed flush values; see deflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#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
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_ASCII    1
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-#define zlib_version zlibVersion()
-/* for compatibility with versions < 1.0.2 */
-
-                        /* basic functions */
-
-extern const char * EXPORT zlibVersion OF((void));
-/* The application can compare zlibVersion 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.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/* 
-extern int EXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-extern int EXPORT deflate OF((z_streamp strm, int flush));
-/*
-  Performs one or both of the following actions:
-
-  - Compress 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 and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
-  block is terminated and flushed to the output buffer so that the
-  decompressor can get all input data available so far. For method 9, a future
-  variant on method 8, the current block will be flushed but not terminated.
-  Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
-  output is byte aligned (the compressor can clear its internal bit buffer)
-  and the current block is always terminated; this can be useful if the
-  compressor has to be restarted from scratch after an interruption (in which
-  case the internal state of the compressor may be lost).
-    If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
-  special marker is output and the compression dictionary is discarded; this
-  is useful to allow the decompressor to synchronize if one compressed block
-  has been damaged (see inflateSync below).  Flushing degrades compression and
-  so should be used only when necessary.  Using Z_FULL_FLUSH too often can
-  seriously degrade the compression. If deflate returns with avail_out == 0,
-  this function must be called again with the same value of the flush
-  parameter and more output space (updated avail_out), until the flush is
-  complete (deflate returns with non-zero avail_out).
-
-    If the parameter flush is set to Z_PACKET_FLUSH, the compression
-  block is terminated, and a zero-length stored block is output,
-  omitting the length bytes (the effect of this is that the 3-bit type
-  code 000 for a stored block is output, and the output is then
-  byte-aligned).  This is designed for use at the end of a PPP packet.
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-  
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() may update data_type if it can make a good guess about
-  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
-*/
-
-
-extern int EXPORT deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-/* 
-extern int EXPORT inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   zalloc, zfree and opaque 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, Z_VERSION_ERROR if the zlib library version is incompatible
-   with the version assumed by the caller.  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 EXPORT inflate OF((z_streamp 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() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  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 inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    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_NEED_DICT if a preset dictionary is needed at this point (see
-  inflateSetDictionary below), 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.
-  In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
-  dictionary chosen by the compressor.
-*/
-
-
-extern int EXPORT inflateEnd OF((z_streamp 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 */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*   
-extern int EXPORT deflateInit2 OF((z_streamp strm,
-                                   int  level,
-                                   int  method,
-                                   int  windowBits,
-                                   int  memLevel,
-                                   int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library. (Method 9 will allow a 64K history buffer and
-   partial block flushes.)
-
-     The windowBits parameter is the base two logarithm of the 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 for method 9). Larger
-   values of this parameter result in better compression at the expense of
-   memory usage. The default value is 15 if deflateInit is used instead.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match).  Filtered data consists mostly of small values with a
-   somewhat random distribution. In this case, the compression algorithm is
-   tuned to compress them better. The effect of Z_FILTERED is to force more
-   Huffman coding and less string matching; it is somewhat intermediate
-   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-   the compression ratio but not the correctness of the compressed output even
-   if it is not set appropriately.
-
-     If next_in is not null, the library will use this buffer to hold also
-   some history information; the buffer must either hold the entire input
-   data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
-   is null, the library will allocate its own history buffer (and leave next_in
-   null). next_out need not be provided here but must be provided by the
-   application for the next call of deflate().
-
-     If the history buffer is provided by the application, next_in must
-   must never be changed by the application since the compressor maintains
-   information inside this buffer from call to call; the application
-   must provide more input only by increasing avail_in. next_in is always
-   reset by the library in this case.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-   an invalid method). msg is set to null if there is no error message.
-   deflateInit2 does not perform any compression: this will be done by
-   deflate(). 
-*/
-                            
-extern int EXPORT deflateSetDictionary OF((z_streamp strm,
-                                           const Bytef *dictionary,
-				           uInt  dictLength));
-/*
-     Initializes the compression dictionary (history buffer) from the given
-   byte sequence without producing any compressed output. This function must
-   be called immediately after deflateInit or deflateInit2, before any call
-   of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and
-   can be predicted with good accuracy; the data can then be compressed better
-   than with the default empty dictionary. In this version of the library,
-   only the last 32K bytes of the dictionary are used.
-     Upon return of this function, strm->adler is set to the Adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The Adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.)
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state
-   is inconsistent (for example if deflate has already been called for this
-   stream). deflateSetDictionary does not perform any compression: this will
-   be done by deflate(). 
-*/
-
-extern int EXPORT deflateCopy OF((z_streamp dest,
-                                  z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.  If
-   the source stream is using an application-supplied history buffer, a new
-   buffer is allocated for the destination stream.  The compressed output
-   buffer is always application-supplied. It's the responsibility of the
-   application to provide the correct values of next_out and avail_out for the
-   next call of deflate.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-extern int EXPORT deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset 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 EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
-/*
-     Dynamically update the compression level and compression strategy.
-   This can be used to switch between compression and straight copy of
-   the input data, or to switch to a different kind of input data requiring
-   a different strategy. If the compression level is changed, the input
-   available so far is compressed with the old level (and may be flushed);
-   the new level will take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-extern int EXPORT deflateOutputPending OF((z_streamp strm));
-/*
-     Returns the number of bytes of output which are immediately
-   available from the compressor (i.e. without any further input
-   or flush).
-*/
-
-/*   
-extern int EXPORT inflateInit2 OF((z_streamp strm,
-                                   int  windowBits));
-
-     This is another version of inflateInit with more compression options. The
-   fields next_out, zalloc, zfree and opaque 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 EXPORT inflateSetDictionary OF((z_streamp strm,
-				           const Bytef *dictionary,
-					   uInt  dictLength));
-/*
-     Initializes the decompression dictionary (history buffer) from the given
-   uncompressed byte sequence. This function must be called immediately after
-   a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
-   by the compressor can be determined from the Adler32 value returned by this
-   call of inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-extern int EXPORT inflateSync OF((z_streamp 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 EXPORT inflateReset OF((z_streamp 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).
-*/
-
-                        /* utility functions */
-
-/*
-     The following utility functions are implemented on top of the
-   basic stream-oriented functions. To simplify the interface, some
-   default options are assumed (compression level, window size,
-   standard memory allocation functions). The source code of these
-   utility functions can easily be modified if you need special options.
-*/
-
-extern int EXPORT compress OF((Bytef *dest,   uLongf *destLen,
-			       const Bytef *source, uLong sourceLen));
-/*
-     Compresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be at least 0.1% larger than
-   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
-   compressed buffer.
-     This function can be used to compress a whole file at once if the
-   input file is mmap'ed.
-     compress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer.
-*/
-
-extern int EXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
-				 const Bytef *source, uLong sourceLen));
-/*
-     Decompresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be large enough to hold the
-   entire uncompressed data. (The size of the uncompressed data must have
-   been saved previously by the compressor and transmitted to the decompressor
-   by some mechanism outside the scope of this compression library.)
-   Upon exit, destLen is the actual size of the compressed buffer.
-     This function can be used to decompress a whole file at once if the
-   input file is mmap'ed.
-
-     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer, or Z_DATA_ERROR if the input data was corrupted.
-*/
-
-
-typedef voidp gzFile;
-
-extern gzFile EXPORT gzopen  OF((const char *path, const char *mode));
-/*
-     Opens a gzip (.gz) file for reading or writing. The mode parameter
-   is as in fopen ("rb" or "wb") but can also include a compression level
-   ("wb9").  gzopen can be used to read a file which is not in gzip format;
-   in this case gzread will directly read from the file without decompression.
-     gzopen returns NULL if the file could not be opened or if there was
-   insufficient memory to allocate the (de)compression state; errno
-   can be checked to distinguish the two cases (if errno is zero, the
-   zlib error is Z_MEM_ERROR).
-*/
-
-extern gzFile EXPORT gzdopen  OF((int fd, const char *mode));
-/*
-     gzdopen() associates a gzFile with the file descriptor fd.  File
-   descriptors are obtained from calls like open, dup, creat, pipe or
-   fileno (in the file has been previously opened with fopen).
-   The mode parameter is as in gzopen.
-     The next call of gzclose on the returned gzFile will also close the
-   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
-   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
-     gzdopen returns NULL if there was insufficient memory to allocate
-   the (de)compression state.
-*/
-
-extern int EXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
-/*
-     Reads the given number of uncompressed bytes from the compressed file.
-   If the input file was not in gzip format, gzread copies the given number
-   of bytes into the buffer.
-     gzread returns the number of uncompressed bytes actually read (0 for
-   end of file, -1 for error). */
-
-extern int EXPORT    gzwrite OF((gzFile file, const voidp buf, unsigned len));
-/*
-     Writes the given number of uncompressed bytes into the compressed file.
-   gzwrite returns the number of uncompressed bytes actually written
-   (0 in case of error).
-*/
-
-extern int EXPORT    gzflush OF((gzFile file, int flush));
-/*
-     Flushes all pending output into the compressed file. The parameter
-   flush is as in the deflate() function. The return value is the zlib
-   error number (see function gzerror below). gzflush returns Z_OK if
-   the flush parameter is Z_FINISH and all output could be flushed.
-     gzflush should be called only when strictly necessary because it can
-   degrade compression.
-*/
-
-extern int EXPORT    gzclose OF((gzFile file));
-/*
-     Flushes all pending output if necessary, closes the compressed file
-   and deallocates all the (de)compression state. The return value is the zlib
-   error number (see function gzerror below).
-*/
-
-extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
-/*
-     Returns the error message for the last error which occurred on the
-   given compressed file. errnum is set to zlib error number. If an
-   error occurred in the file system and not in the compression library,
-   errnum is set to Z_ERRNO and the application may consult errno
-   to get the exact error code.
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-extern uLong EXPORT adler32 OF((uLong adler, const 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();
-*/
-
-extern uLong EXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running crc with the bytes buf[0..len-1] and return the updated
-   crc. If buf is NULL, this function returns the required initial value
-   for the crc. Pre- and post-conditioning (one's complement) is performed
-   within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
-			           const char *version, int stream_size));
-extern int EXPORT inflateInit_ OF((z_streamp strm,
-				   const char *version, int stream_size));
-extern int EXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
-				    int windowBits, int memLevel, int strategy,
-				    const char *version, int stream_size));
-extern int EXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
-				    const char *version, int stream_size));
-#define deflateInit(strm, level) \
-        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit(strm) \
-        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
-#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-		      (strategy),           ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit2(strm, windowBits) \
-        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-
-#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZLIB_H */
-/* --- zlib.h */
diff -urN linux-2.4.20-pre1/fs/lockd/svc4proc.c linux-2.4.20-pre2/fs/lockd/svc4proc.c
--- linux-2.4.20-pre1/fs/lockd/svc4proc.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/lockd/svc4proc.c	Mon Aug 12 16:34:17 2002
@@ -528,7 +528,7 @@
 
 struct nlm_void			{ int dummy; };
 
-#define PROC(name, xargt, xrest, argt, rest)	\
+#define PROC(name, xargt, xrest, argt, rest, respsize)	\
  { (svc_procfunc) nlm4svc_proc_##name,	\
    (kxdrproc_t) nlm4svc_decode_##xargt,	\
    (kxdrproc_t) nlm4svc_encode_##xrest,	\
@@ -536,33 +536,38 @@
    sizeof(struct nlm_##argt),		\
    sizeof(struct nlm_##rest),		\
    0,					\
-   0					\
+   0,					\
+   respsize,				\
  }
+#define	Ck	(1+8)	/* cookie */
+#define	No	(1+1024/4)	/* netobj */
+#define	St	1	/* status */
+#define	Rg	4	/* range (offset + length) */
 struct svc_procedure		nlmsvc_procedures4[] = {
-  PROC(null,		void,		void,		void,	void),
-  PROC(test,		testargs,	testres,	args,	res),
-  PROC(lock,		lockargs,	res,		args,	res),
-  PROC(cancel,		cancargs,	res,		args,	res),
-  PROC(unlock,		unlockargs,	res,		args,	res),
-  PROC(granted,		testargs,	res,		args,	res),
-  PROC(test_msg,	testargs,	norep,		args,	void),
-  PROC(lock_msg,	lockargs,	norep,		args,	void),
-  PROC(cancel_msg,	cancargs,	norep,		args,	void),
-  PROC(unlock_msg,	unlockargs,	norep,		args,	void),
-  PROC(granted_msg,	testargs,	norep,		args,	void),
-  PROC(test_res,	testres,	norep,		res,	void),
-  PROC(lock_res,	lockres,	norep,		res,	void),
-  PROC(cancel_res,	cancelres,	norep,		res,	void),
-  PROC(unlock_res,	unlockres,	norep,		res,	void),
-  PROC(granted_res,	grantedres,	norep,		res,	void),
+  PROC(null,		void,		void,		void,	void, 1),
+  PROC(test,		testargs,	testres,	args,	res, Ck+St+2+No+Rg),
+  PROC(lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(cancel,		cancargs,	res,		args,	res, Ck+St),
+  PROC(unlock,		unlockargs,	res,		args,	res, Ck+St),
+  PROC(granted,		testargs,	res,		args,	res, Ck+St),
+  PROC(test_msg,	testargs,	norep,		args,	void, 1),
+  PROC(lock_msg,	lockargs,	norep,		args,	void, 1),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void, 1),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 1),
+  PROC(granted_msg,	testargs,	norep,		args,	void, 1),
+  PROC(test_res,	testres,	norep,		res,	void, 1),
+  PROC(lock_res,	lockres,	norep,		res,	void, 1),
+  PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
+  PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
+  PROC(granted_res,	grantedres,	norep,		res,	void, 1),
   /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(share,		shareargs,	shareres,	args,	res),
-  PROC(unshare,		shareargs,	shareres,	args,	res),
-  PROC(nm_lock,		lockargs,	res,		args,	res),
-  PROC(free_all,	notify,		void,		args,	void),
+  PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(share,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(unshare,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(nm_lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(free_all,	notify,		void,		args,	void, 1),
 
 };
diff -urN linux-2.4.20-pre1/fs/lockd/svcproc.c linux-2.4.20-pre2/fs/lockd/svcproc.c
--- linux-2.4.20-pre1/fs/lockd/svcproc.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/lockd/svcproc.c	Mon Aug 12 16:34:17 2002
@@ -556,7 +556,7 @@
 
 struct nlm_void			{ int dummy; };
 
-#define PROC(name, xargt, xrest, argt, rest)	\
+#define PROC(name, xargt, xrest, argt, rest, respsize)	\
  { (svc_procfunc) nlmsvc_proc_##name,	\
    (kxdrproc_t) nlmsvc_decode_##xargt,	\
    (kxdrproc_t) nlmsvc_encode_##xrest,	\
@@ -564,33 +564,40 @@
    sizeof(struct nlm_##argt),		\
    sizeof(struct nlm_##rest),		\
    0,					\
-   0					\
+   0,					\
+   respsize,				\
  }
+
+#define	Ck	(1+8)	/* cookie */
+#define	St	1	/* status */
+#define	No	(1+1024/4) /* Net Obj */
+#define	Rg	2	/* range - offset + size */
+
 struct svc_procedure		nlmsvc_procedures[] = {
-  PROC(null,		void,		void,		void,	void),
-  PROC(test,		testargs,	testres,	args,	res),
-  PROC(lock,		lockargs,	res,		args,	res),
-  PROC(cancel,		cancargs,	res,		args,	res),
-  PROC(unlock,		unlockargs,	res,		args,	res),
-  PROC(granted,		testargs,	res,		args,	res),
-  PROC(test_msg,	testargs,	norep,		args,	void),
-  PROC(lock_msg,	lockargs,	norep,		args,	void),
-  PROC(cancel_msg,	cancargs,	norep,		args,	void),
-  PROC(unlock_msg,	unlockargs,	norep,		args,	void),
-  PROC(granted_msg,	testargs,	norep,		args,	void),
-  PROC(test_res,	testres,	norep,		res,	void),
-  PROC(lock_res,	lockres,	norep,		res,	void),
-  PROC(cancel_res,	cancelres,	norep,		res,	void),
-  PROC(unlock_res,	unlockres,	norep,		res,	void),
-  PROC(granted_res,	grantedres,	norep,		res,	void),
+  PROC(null,		void,		void,		void,	void, 1),
+  PROC(test,		testargs,	testres,	args,	res, Ck+St+2+No+Rg),
+  PROC(lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(cancel,		cancargs,	res,		args,	res, Ck+St),
+  PROC(unlock,		unlockargs,	res,		args,	res, Ck+St),
+  PROC(granted,		testargs,	res,		args,	res, Ck+St),
+  PROC(test_msg,	testargs,	norep,		args,	void, 1),
+  PROC(lock_msg,	lockargs,	norep,		args,	void, 1),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void, 1),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 1),
+  PROC(granted_msg,	testargs,	norep,		args,	void, 1),
+  PROC(test_res,	testres,	norep,		res,	void, 1),
+  PROC(lock_res,	lockres,	norep,		res,	void, 1),
+  PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
+  PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
+  PROC(granted_res,	grantedres,	norep,		res,	void, 1),
   /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(share,		shareargs,	shareres,	args,	res),
-  PROC(unshare,		shareargs,	shareres,	args,	res),
-  PROC(nm_lock,		lockargs,	res,		args,	res),
-  PROC(free_all,	notify,		void,		args,	void),
+  PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
+  PROC(none,		void,		void,		void,	void, 1),
+  PROC(none,		void,		void,		void,	void, 1),
+  PROC(none,		void,		void,		void,	void, 1),
+  PROC(share,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(unshare,		shareargs,	shareres,	args,	res, Ck+St+1),
+  PROC(nm_lock,		lockargs,	res,		args,	res, Ck+St),
+  PROC(free_all,	notify,		void,		args,	void, 0),
 
 };
diff -urN linux-2.4.20-pre1/fs/ncpfs/dir.c linux-2.4.20-pre2/fs/ncpfs/dir.c
--- linux-2.4.20-pre1/fs/ncpfs/dir.c	Wed Mar  7 16:53:48 2001
+++ linux-2.4.20-pre2/fs/ncpfs/dir.c	Mon Aug 12 16:34:17 2002
@@ -74,12 +74,19 @@
 static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
 static int ncp_delete_dentry(struct dentry *);
 
-struct dentry_operations ncp_dentry_operations =
+static struct dentry_operations ncp_dentry_operations =
 {
 	d_revalidate:	ncp_lookup_validate,
 	d_hash:		ncp_hash_dentry,
 	d_compare:	ncp_compare_dentry,
 	d_delete:	ncp_delete_dentry,
+};
+
+struct dentry_operations ncp_root_dentry_operations =
+{
+	d_hash:		ncp_hash_dentry,
+	d_compare:	ncp_compare_dentry,
+	d_delete:	ncp_delete_dentry,
 };
 
 
diff -urN linux-2.4.20-pre1/fs/ncpfs/inode.c linux-2.4.20-pre2/fs/ncpfs/inode.c
--- linux-2.4.20-pre1/fs/ncpfs/inode.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.20-pre2/fs/ncpfs/inode.c	Mon Aug 12 16:34:17 2002
@@ -44,7 +44,7 @@
 	statfs:		ncp_statfs,
 };
 
-extern struct dentry_operations ncp_dentry_operations;
+extern struct dentry_operations ncp_root_dentry_operations;
 #ifdef CONFIG_NCPFS_EXTRAS
 extern struct address_space_operations ncp_symlink_aops;
 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
@@ -443,7 +443,7 @@
 	sb->s_root = d_alloc_root(root_inode);
         if (!sb->s_root)
 		goto out_no_root;
-	sb->s_root->d_op = &ncp_dentry_operations;
+	sb->s_root->d_op = &ncp_root_dentry_operations;
 	return sb;
 
 out_no_root:
diff -urN linux-2.4.20-pre1/fs/nfs/flushd.c linux-2.4.20-pre2/fs/nfs/flushd.c
--- linux-2.4.20-pre1/fs/nfs/flushd.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/nfs/flushd.c	Mon Aug 12 16:34:17 2002
@@ -50,7 +50,7 @@
 /*
  * This is the wait queue all cluster daemons sleep on
  */
-static struct rpc_wait_queue    flushd_queue = RPC_INIT_WAITQ("nfs_flushd");
+static RPC_WAITQ(flushd_queue, "nfs_flushd");
 
 /*
  * Local function declarations.
diff -urN linux-2.4.20-pre1/fs/nfs/unlink.c linux-2.4.20-pre2/fs/nfs/unlink.c
--- linux-2.4.20-pre1/fs/nfs/unlink.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.20-pre2/fs/nfs/unlink.c	Mon Aug 12 16:34:17 2002
@@ -24,7 +24,7 @@
 };
 
 static struct nfs_unlinkdata	*nfs_deletes;
-static struct rpc_wait_queue	nfs_delete_queue = RPC_INIT_WAITQ("nfs_delete_queue");
+static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue");
 
 /**
  * nfs_detach_unlinkdata - Remove asynchronous unlink from global list
diff -urN linux-2.4.20-pre1/fs/nfsd/export.c linux-2.4.20-pre2/fs/nfsd/export.c
--- linux-2.4.20-pre1/fs/nfsd/export.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/nfsd/export.c	Mon Aug 12 16:34:17 2002
@@ -50,6 +50,7 @@
 		((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
 /* XXX: is this adequate for 32bit kdev_t ? */
 #define EXPORT_HASH(dev)	((dev) & (NFSCLNT_EXPMAX - 1))
+#define EXPORT_FSID_HASH(fsid)	((fsid) & (NFSCLNT_EXPMAX - 1))
 
 struct svc_clnthash {
 	struct svc_clnthash *	h_next;
@@ -58,7 +59,6 @@
 };
 static struct svc_clnthash *	clnt_hash[CLIENT_HASHMAX];
 static svc_client *		clients;
-static int			initialized;
 
 static int			hash_lock;
 static int			want_lock;
@@ -87,6 +87,26 @@
 }
 
 /*
+ * Find the client's export entry matching fsid
+ */
+svc_export *
+exp_get_fsid(svc_client *clp, int fsid)
+{
+	struct list_head *head, *p;
+
+	if (!clp)
+		return NULL;
+
+	head = &clp->cl_expfsid[EXPORT_FSID_HASH(fsid)];
+	list_for_each(p, head) {
+		svc_export *exp = list_entry(p, svc_export, ex_fsid_hash);
+		if (exp->ex_fsid == fsid)
+			return exp;
+	}
+	return NULL;
+}
+
+/*
  * Find the export entry for a given dentry.  <gam3@acm.org>
  */
 static svc_export *
@@ -138,6 +158,25 @@
 	}
 }
 
+static void exp_fsid_unhash(struct svc_export *exp)
+{
+
+	if ((exp->ex_flags & NFSEXP_FSID) == 0)
+		return;
+
+	list_del_init(&exp->ex_fsid_hash);
+}
+
+static void exp_fsid_hash(struct svc_client *clp, struct svc_export *exp)
+{
+	struct list_head *head;
+
+	if ((exp->ex_flags & NFSEXP_FSID) == 0)
+		return;
+	head = clp->cl_expfsid + EXPORT_FSID_HASH(exp->ex_fsid);
+	list_add(&exp->ex_fsid_hash, head);
+}
+
 /*
  * Export a file system.
  */
@@ -145,7 +184,8 @@
 exp_export(struct nfsctl_export *nxp)
 {
 	svc_client	*clp;
-	svc_export	*exp, *parent;
+	svc_export	*exp = NULL, *parent;
+	svc_export	*fsid_exp;
 	struct nameidata nd;
 	struct inode	*inode = NULL;
 	int		err;
@@ -161,8 +201,6 @@
 	dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
 			nxp->ex_client, nxp->ex_path,
 			nxp->ex_dev, (long) nxp->ex_ino, nxp->ex_flags);
-	dev = to_kdev_t(nxp->ex_dev);
-	ino = nxp->ex_ino;
 
 	/* Try to lock the export table for update */
 	if ((err = exp_writelock()) < 0)
@@ -173,17 +211,6 @@
 	if (!(clp = exp_getclientbyname(nxp->ex_client)))
 		goto out_unlock;
 
-	/*
-	 * If there's already an export for this file, assume this
-	 * is just a flag update.
-	 */
-	if ((exp = exp_get(clp, dev, ino)) != NULL) {
-		exp->ex_flags    = nxp->ex_flags;
-		exp->ex_anon_uid = nxp->ex_anon_uid;
-		exp->ex_anon_gid = nxp->ex_anon_gid;
-		err = 0;
-		goto out_unlock;
-	}
 
 	/* Look up the dentry */
 	err = 0;
@@ -193,11 +220,28 @@
 		goto out_unlock;
 
 	inode = nd.dentry->d_inode;
+	dev = inode->i_dev;
+	ino = inode->i_ino;
 	err = -EINVAL;
-	if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
-		printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
-			inode->i_dev, dev); 
-		/* I'm just being paranoid... */
+
+	exp = exp_get(clp, dev, ino);
+
+	/* must make sure there wont be an ex_fsid clash */
+	if ((nxp->ex_flags & NFSEXP_FSID) &&
+	    (fsid_exp = exp_get_fsid(clp, nxp->ex_dev)) &&
+	    fsid_exp != exp)
+		goto finish;
+
+	if (exp != NULL) {
+		/* just a flags/id/fsid update */
+
+		exp_fsid_unhash(exp);
+		exp->ex_flags    = nxp->ex_flags;
+		exp->ex_anon_uid = nxp->ex_anon_uid;
+		exp->ex_anon_gid = nxp->ex_anon_gid;
+		exp->ex_fsid     = nxp->ex_dev;
+		exp_fsid_hash(clp, exp);
+		err = 0;
 		goto finish;
 	}
 
@@ -209,7 +253,17 @@
 		goto finish;
 
 	err = -EINVAL;
-	if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) ||
+	/* There are two requirements on a filesystem to be exportable.
+	 * 1:  We must be able to identify the filesystem from a number.
+	 *       either a device number (so FS_REQUIRES_DEV needed)
+	 *       or an FSID number (so NFSEXP_FSID needed).
+	 * 2:  We must be able to find an inode from a filehandle.
+	 *       either using fh_to_dentry (prefered)
+	 *       or using read_inode (the hack).
+	 */
+	if (!((inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV)
+	      || (nxp->ex_flags & NFSEXP_FSID))
+	    ||
 	    (inode->i_sb->s_op->read_inode == NULL
 	     && inode->i_sb->s_op->fh_to_dentry == NULL)) {
 		dprintk("exp_export: export of invalid fs type.\n");
@@ -241,6 +295,8 @@
 	exp->ex_ino = ino;
 	exp->ex_anon_uid = nxp->ex_anon_uid;
 	exp->ex_anon_gid = nxp->ex_anon_gid;
+	exp->ex_fsid = nxp->ex_dev;
+
 
 	/* Update parent pointers of all exports */
 	if (parent)
@@ -249,6 +305,8 @@
 	list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(dev));
 	list_add_tail(&exp->ex_list, &clp->cl_list);
 
+	exp_fsid_hash(clp, exp);
+
 	err = 0;
 
 finish:
@@ -272,6 +330,7 @@
 
 	list_del(&unexp->ex_hash);
 	list_del(&unexp->ex_list);
+	exp_fsid_unhash(unexp);
 
 	exp_change_parents(unexp->ex_client, unexp, unexp->ex_parent);
 
@@ -470,9 +529,6 @@
 	struct svc_clnthash	**hp, **head, *tmp;
 	unsigned long		addr = sin->sin_addr.s_addr;
 
-	if (!initialized)
-		return NULL;
-
 	head = &clnt_hash[CLIENT_HASH(addr)];
 
 	for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
@@ -590,7 +646,7 @@
 	{ 0, {"", ""}}
 };
 
-static void exp_flags(struct seq_file *m, int flag)
+static void exp_flags(struct seq_file *m, int flag, int fsid)
 {
 	int first = 0;
 	struct flags *flg;
@@ -600,6 +656,8 @@
 		if (*flg->name[state])
 			seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
 	}
+	if (flag & NFSEXP_FSID)
+		seq_printf(m, "%sfsid=%d", first++?",":"", fsid);
 }
 
 static inline void mangle(struct seq_file *m, const char *s)
@@ -625,7 +683,7 @@
 	seq_putc(m, '\t');
 	mangle(m, clp->cl_ident);
 	seq_putc(m, '(');
-	exp_flags(m, exp->ex_flags);
+	exp_flags(m, exp->ex_flags, exp->ex_fsid);
 	seq_puts(m, ") # ");
 	for (j = 0; j < clp->cl_naddr; j++) {
 		struct svc_clnthash **hp, **head, *tmp;
@@ -696,8 +754,10 @@
 		if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
 			goto out_unlock;
 		memset(clp, 0, sizeof(*clp));
-		for (i = 0; i < NFSCLNT_EXPMAX; i++)
+		for (i = 0; i < NFSCLNT_EXPMAX; i++) {
 			INIT_LIST_HEAD(&clp->cl_export[i]);
+			INIT_LIST_HEAD(&clp->cl_expfsid[i]);
+		}
 		INIT_LIST_HEAD(&clp->cl_list);
 
 		dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
@@ -869,13 +929,11 @@
 	int		i;
 
 	dprintk("nfsd: initializing export module.\n");
-	if (initialized)
-		return;
+
 	for (i = 0; i < CLIENT_HASHMAX; i++)
 		clnt_hash[i] = NULL;
 	clients = NULL;
 
-	initialized = 1;
 }
 
 /*
@@ -887,8 +945,7 @@
 	int	i;
 
 	dprintk("nfsd: shutting down export module.\n");
-	if (!initialized)
-		return;
+
 	if (exp_writelock() < 0) {
 		printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown");
 		return;
diff -urN linux-2.4.20-pre1/fs/nfsd/nfs3proc.c linux-2.4.20-pre2/fs/nfsd/nfs3proc.c
--- linux-2.4.20-pre1/fs/nfsd/nfs3proc.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/nfsd/nfs3proc.c	Mon Aug 12 16:34:17 2002
@@ -188,6 +188,8 @@
 	if ((avail << 2) < resp->count)
 		resp->count = avail << 2;
 
+	svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + argp->count +4);
+
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_read(rqstp, &resp->fh,
 				  argp->offset,
@@ -646,7 +648,7 @@
 #define nfsd3_voidres			nfsd3_voidargs
 struct nfsd3_voidargs { int dummy; };
 
-#define PROC(name, argt, rest, relt, cache)	\
+#define PROC(name, argt, rest, relt, cache, respsize)	\
  { (svc_procfunc) nfsd3_proc_##name,		\
    (kxdrproc_t) nfs3svc_decode_##argt##args,	\
    (kxdrproc_t) nfs3svc_encode_##rest##res,	\
@@ -654,29 +656,37 @@
    sizeof(struct nfsd3_##argt##args),		\
    sizeof(struct nfsd3_##rest##res),		\
    0,						\
-   cache					\
+   cache,					\
+   respsize,					\
  }
+
+#define ST 1		/* status*/
+#define FH 17		/* filehandle with length */
+#define AT 21		/* attributes */
+#define pAT (1+AT)	/* post attributes - conditional */
+#define WC (7+pAT)	/* WCC attributes */
+
 struct svc_procedure		nfsd_procedures3[22] = {
-  PROC(null,	 void,		void,		void,	 RC_NOCACHE),
-  PROC(getattr,	 fhandle,	attrstat,	fhandle, RC_NOCACHE),
-  PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF),
-  PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE),
-  PROC(access,	 access,	access,		fhandle,  RC_NOCACHE),
-  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE),
-  PROC(read,	 read,		read,		fhandle, RC_NOCACHE),
-  PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF),
-  PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF),
-  PROC(mkdir,	 mkdir,		create,		fhandle2, RC_REPLBUFF),
-  PROC(symlink,	 symlink,	create,		fhandle2, RC_REPLBUFF),
-  PROC(mknod,	 mknod,		create,		fhandle2, RC_REPLBUFF),
-  PROC(remove,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF),
-  PROC(rmdir,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF),
-  PROC(rename,	 rename,	rename,		fhandle2, RC_REPLBUFF),
-  PROC(link,	 link,		link,		fhandle2, RC_REPLBUFF),
-  PROC(readdir,	 readdir,	readdir,	fhandle,  RC_NOCACHE),
-  PROC(readdirplus,readdirplus,	readdir,	fhandle,  RC_NOCACHE),
-  PROC(fsstat,	 fhandle,	fsstat,		void,     RC_NOCACHE),
-  PROC(fsinfo,   fhandle,	fsinfo,		void,     RC_NOCACHE),
-  PROC(pathconf, fhandle,	pathconf,	void,     RC_NOCACHE),
-  PROC(commit,	 commit,	commit,		fhandle,  RC_NOCACHE)
+  PROC(null,	 void,		void,		void,	 RC_NOCACHE, ST),
+  PROC(getattr,	 fhandle,	attrstat,	fhandle, RC_NOCACHE, ST+AT),
+  PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
+  PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE, ST+FH+pAT+pAT),
+  PROC(access,	 access,	access,		fhandle,  RC_NOCACHE, ST+pAT+1),
+  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+256),
+  PROC(read,	 read,		read,		fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE),
+  PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF, ST+WC+4),
+  PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
+  PROC(mkdir,	 mkdir,		create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
+  PROC(symlink,	 symlink,	create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
+  PROC(mknod,	 mknod,		create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
+  PROC(remove,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
+  PROC(rmdir,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
+  PROC(rename,	 rename,	rename,		fhandle2, RC_REPLBUFF, ST+WC+WC),
+  PROC(link,	 link,		link,		fhandle2, RC_REPLBUFF, ST+pAT+WC),
+  PROC(readdir,	 readdir,	readdir,	fhandle,  RC_NOCACHE, 0),
+  PROC(readdirplus,readdirplus,	readdir,	fhandle,  RC_NOCACHE, 0),
+  PROC(fsstat,	 fhandle,	fsstat,		void,     RC_NOCACHE, ST+pAT+2*6+1),
+  PROC(fsinfo,   fhandle,	fsinfo,		void,     RC_NOCACHE, ST+pAT+12),
+  PROC(pathconf, fhandle,	pathconf,	void,     RC_NOCACHE, ST+pAT+6),
+  PROC(commit,	 commit,	commit,		fhandle,  RC_NOCACHE, ST+WC+2),
 };
diff -urN linux-2.4.20-pre1/fs/nfsd/nfs3xdr.c linux-2.4.20-pre2/fs/nfsd/nfs3xdr.c
--- linux-2.4.20-pre1/fs/nfsd/nfs3xdr.c	Wed Oct  3 22:27:48 2001
+++ linux-2.4.20-pre2/fs/nfsd/nfs3xdr.c	Mon Aug 12 16:34:17 2002
@@ -154,9 +154,9 @@
 }
 
 static inline u32 *
-encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
+encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 {
-	struct inode	*inode = dentry->d_inode;
+	struct inode	*inode = fhp->fh_dentry->d_inode;
 
 	*p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
 	*p++ = htonl((u32) inode->i_mode);
@@ -175,7 +175,12 @@
 		p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
 	*p++ = htonl((u32) MAJOR(inode->i_rdev));
 	*p++ = htonl((u32) MINOR(inode->i_rdev));
-	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	if (rqstp->rq_reffh->fh_version == 1
+	    && rqstp->rq_reffh->fh_fsid_type == 1
+	    && (fhp->fh_export->ex_flags & NFSEXP_FSID))
+		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
+	else
+		p = xdr_encode_hyper(p, (u64) inode->i_dev);
 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, inode->i_atime);
 	p = encode_time3(p, lease_get_mtime(inode));
@@ -205,7 +210,12 @@
 	p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
 	*p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
 	*p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
-	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	if (rqstp->rq_reffh->fh_version == 1
+	    && rqstp->rq_reffh->fh_fsid_type == 1
+	    && (fhp->fh_export->ex_flags & NFSEXP_FSID))
+		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
+	else
+		p = xdr_encode_hyper(p, (u64) inode->i_dev);
 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, fhp->fh_post_atime);
 	p = encode_time3(p, fhp->fh_post_mtime);
@@ -220,11 +230,12 @@
  * handle. In this case, no attributes are returned.
  */
 static u32 *
-encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
+encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 {
+	struct dentry *dentry = fhp->fh_dentry;
 	if (dentry && dentry->d_inode != NULL) {
 		*p++ = xdr_one;		/* attributes follow */
-		return encode_fattr3(rqstp, p, dentry);
+		return encode_fattr3(rqstp, p, fhp);
 	}
 	*p++ = xdr_zero;
 	return p;
@@ -251,7 +262,7 @@
 	}
 	/* no pre- or post-attrs */
 	*p++ = xdr_zero;
-	return encode_post_op_attr(rqstp, p, dentry);
+	return encode_post_op_attr(rqstp, p, fhp);
 }
 
 /*
@@ -509,7 +520,7 @@
 					struct nfsd3_attrstat *resp)
 {
 	if (resp->status == 0)
-		p = encode_fattr3(rqstp, p, resp->fh.fh_dentry);
+		p = encode_fattr3(rqstp, p, &resp->fh);
 	return xdr_ressize_check(rqstp, p);
 }
 
@@ -529,9 +540,9 @@
 {
 	if (resp->status == 0) {
 		p = encode_fh(p, &resp->fh);
-		p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+		p = encode_post_op_attr(rqstp, p, &resp->fh);
 	}
-	p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->dirfh);
 	return xdr_ressize_check(rqstp, p);
 }
 
@@ -540,7 +551,7 @@
 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_accessres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	if (resp->status == 0)
 		*p++ = htonl(resp->access);
 	return xdr_ressize_check(rqstp, p);
@@ -551,7 +562,7 @@
 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_readlinkres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	if (resp->status == 0) {
 		*p++ = htonl(resp->len);
 		p += XDR_QUADLEN(resp->len);
@@ -564,7 +575,7 @@
 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_readres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	if (resp->status == 0) {
 		*p++ = htonl(resp->count);
 		*p++ = htonl(resp->eof);
@@ -597,7 +608,7 @@
 	if (resp->status == 0) {
 		*p++ = xdr_one;
 		p = encode_fh(p, &resp->fh);
-		p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+		p = encode_post_op_attr(rqstp, p, &resp->fh);
 	}
 	p = encode_wcc_data(rqstp, p, &resp->dirfh);
 	return xdr_ressize_check(rqstp, p);
@@ -618,7 +629,7 @@
 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_linkres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	p = encode_wcc_data(rqstp, p, &resp->tfh);
 	return xdr_ressize_check(rqstp, p);
 }
@@ -628,7 +639,7 @@
 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_readdirres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
+	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	if (resp->status == 0) {
 		/* stupid readdir cookie */
 		memcpy(p, resp->verf, 8); p += 2;
@@ -709,7 +720,7 @@
 			goto noexec;
 		if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
 			goto noexec;
-		p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
+		p = encode_post_op_attr(cd->rqstp, p, &fh);
 		*p++ = xdr_one; /* yes, a file handle follows */
 		p = encode_fh(p, &fh);
 		fh_put(&fh);
diff -urN linux-2.4.20-pre1/fs/nfsd/nfscache.c linux-2.4.20-pre2/fs/nfsd/nfscache.c
--- linux-2.4.20-pre1/fs/nfsd/nfscache.c	Thu Feb 15 10:56:29 2001
+++ linux-2.4.20-pre2/fs/nfsd/nfscache.c	Mon Aug 12 16:34:17 2002
@@ -38,7 +38,6 @@
 static struct svc_cacherep *	lru_head;
 static struct svc_cacherep *	lru_tail;
 static struct svc_cacherep *	nfscache;
-static int			cache_initialized;
 static int			cache_disabled = 1;
 
 static int	nfsd_cache_append(struct svc_rqst *rqstp, struct svc_buf *data);
@@ -51,8 +50,6 @@
 	size_t			i;
 	unsigned long		order;
 
-	if (cache_initialized)
-		return;
 
 	i = CACHESIZE * sizeof (struct svc_cacherep);
 	for (order = 0; (PAGE_SIZE << order) < i; order++)
@@ -90,7 +87,6 @@
 	lru_head->c_lru_prev = NULL;
 	lru_tail->c_lru_next = NULL;
 
-	cache_initialized = 1;
 	cache_disabled = 0;
 }
 
@@ -101,15 +97,11 @@
 	size_t			i;
 	unsigned long		order;
 
-	if (!cache_initialized)
-		return;
-
 	for (rp = lru_head; rp; rp = rp->c_lru_next) {
 		if (rp->c_state == RC_DONE && rp->c_type == RC_REPLBUFF)
 			kfree(rp->c_replbuf.buf);
 	}
 
-	cache_initialized = 0;
 	cache_disabled = 1;
 
 	i = CACHESIZE * sizeof (struct svc_cacherep);
diff -urN linux-2.4.20-pre1/fs/nfsd/nfsfh.c linux-2.4.20-pre2/fs/nfsd/nfsfh.c
--- linux-2.4.20-pre1/fs/nfsd/nfsfh.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/nfsd/nfsfh.c	Mon Aug 12 16:34:17 2002
@@ -273,7 +273,9 @@
 	/* I'm going to assume that if the returned dentry is different, then
 	 * it is well connected.  But nobody returns different dentrys do they?
 	 */
+	down(&child->d_inode->i_sem);
 	pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
+	up(&child->d_inode->i_sem);
 	d_drop(tdentry); /* we never want ".." hashed */
 	if (!pdentry && tdentry->d_inode == NULL) {
 		/* File system cannot find ".." ... sad but possible */
@@ -534,12 +536,17 @@
 
 	dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
 
+	/* keep this filehandle for possible reference  when encoding attributes */
+	rqstp->rq_reffh = fh;
+
 	if (!fhp->fh_dentry) {
-		kdev_t xdev;
-		ino_t xino;
+		kdev_t xdev = NODEV;
+		ino_t xino = 0;
 		__u32 *datap=NULL;
 		int data_left = fh->fh_size/4;
 		int nfsdev;
+		int fsid = 0;
+
 		error = nfserr_stale;
 		if (rqstp->rq_vers == 3)
 			error = nfserr_badhandle;
@@ -559,6 +566,10 @@
 				xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
 				xino = *datap++;
 				break;
+			case 1:
+				if ((data_left-=1)<0) goto out;
+				fsid = *datap++;
+				break;
 			default:
 				goto out;
 			}
@@ -574,7 +585,10 @@
 		 * Look up the export entry.
 		 */
 		error = nfserr_stale; 
-		exp = exp_get(rqstp->rq_client, xdev, xino);
+		if (fh->fh_version == 1 && fh->fh_fsid_type == 1)
+			exp = exp_get_fsid(rqstp->rq_client, fsid);
+		else
+			exp = exp_get(rqstp->rq_client, xdev, xino);
 
 		if (!exp)
 			/* export entry revoked */
@@ -818,12 +832,20 @@
 	} else {
 		fhp->fh_handle.fh_version = 1;
 		fhp->fh_handle.fh_auth_type = 0;
-		fhp->fh_handle.fh_fsid_type = 0;
 		datap = fhp->fh_handle.fh_auth+0;
-		/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
-		*datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
-		*datap++ = ino_t_to_u32(exp->ex_ino);
-		fhp->fh_handle.fh_size = 3*4;
+		if ((exp->ex_flags & NFSEXP_FSID) &&
+		    (!ref_fh || ref_fh->fh_handle.fh_fsid_type == 1)) {
+			fhp->fh_handle.fh_fsid_type = 1;
+			/* fsid_type 1 == 4 bytes filesystem id */
+			*datap++ = exp->ex_fsid;
+			fhp->fh_handle.fh_size = 2*4;
+		} else {
+			fhp->fh_handle.fh_fsid_type = 0;
+			/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
+			*datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+			*datap++ = ino_t_to_u32(exp->ex_ino);
+			fhp->fh_handle.fh_size = 3*4;
+		}
 		if (inode) {
 			int size = fhp->fh_maxsize/4 - 3;
 			fhp->fh_handle.fh_fileid_type =
diff -urN linux-2.4.20-pre1/fs/nfsd/nfsproc.c linux-2.4.20-pre2/fs/nfsd/nfsproc.c
--- linux-2.4.20-pre1/fs/nfsd/nfsproc.c	Sun Oct 21 10:40:36 2001
+++ linux-2.4.20-pre2/fs/nfsd/nfsproc.c	Mon Aug 12 16:34:17 2002
@@ -148,6 +148,7 @@
 				argp->count);
 		argp->count = avail << 2;
 	}
+	svc_reserve(rqstp, (19<<2) + argp->count + 4);
 
 	resp->count = argp->count;
 	nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
@@ -522,7 +523,7 @@
 #define nfssvc_release_none	NULL
 struct nfsd_void { int dummy; };
 
-#define PROC(name, argt, rest, relt, cache)	\
+#define PROC(name, argt, rest, relt, cache, respsize)	\
  { (svc_procfunc) nfsd_proc_##name,		\
    (kxdrproc_t) nfssvc_decode_##argt,		\
    (kxdrproc_t) nfssvc_encode_##rest,		\
@@ -530,27 +531,33 @@
    sizeof(struct nfsd_##argt),			\
    sizeof(struct nfsd_##rest),			\
    0,						\
-   cache					\
+   cache,					\
+   respsize,				       	\
  }
+
+#define ST 1		/* status */
+#define FH 8		/* filehandle */
+#define	AT 18		/* attributes */
+
 struct svc_procedure		nfsd_procedures2[18] = {
-  PROC(null,	 void,		void,		none,		RC_NOCACHE),
-  PROC(getattr,	 fhandle,	attrstat,	fhandle,	RC_NOCACHE),
-  PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF),
-  PROC(none,	 void,		void,		none,		RC_NOCACHE),
-  PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE),
-  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE),
-  PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE),
-  PROC(none,	 void,		void,		none,		RC_NOCACHE),
-  PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF),
-  PROC(create,	 createargs,	diropres,	fhandle,	RC_REPLBUFF),
-  PROC(remove,	 diropargs,	void,		none,		RC_REPLSTAT),
-  PROC(rename,	 renameargs,	void,		none,		RC_REPLSTAT),
-  PROC(link,	 linkargs,	void,		none,		RC_REPLSTAT),
-  PROC(symlink,	 symlinkargs,	void,		none,		RC_REPLSTAT),
-  PROC(mkdir,	 createargs,	diropres,	fhandle,	RC_REPLBUFF),
-  PROC(rmdir,	 diropargs,	void,		none,		RC_REPLSTAT),
-  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLBUFF),
-  PROC(statfs,	 fhandle,	statfsres,	none,		RC_NOCACHE),
+  PROC(null,	 void,		void,		none,		RC_NOCACHE, ST),
+  PROC(getattr,	 fhandle,	attrstat,	fhandle,	RC_NOCACHE, ST+AT),
+  PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
+  PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
+  PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE, ST+FH+AT),
+  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+256),
+  PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE),
+  PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
+  PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
+  PROC(create,	 createargs,	diropres,	fhandle,	RC_REPLBUFF, ST+FH+AT),
+  PROC(remove,	 diropargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(rename,	 renameargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(link,	 linkargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(symlink,	 symlinkargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(mkdir,	 createargs,	diropres,	fhandle,	RC_REPLBUFF, ST+FH+AT),
+  PROC(rmdir,	 diropargs,	void,		none,		RC_REPLSTAT, ST),
+  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLBUFF, 0),
+  PROC(statfs,	 fhandle,	statfsres,	none,		RC_NOCACHE, ST+5),
 };
 
 
diff -urN linux-2.4.20-pre1/fs/nfsd/nfssvc.c linux-2.4.20-pre2/fs/nfsd/nfssvc.c
--- linux-2.4.20-pre1/fs/nfsd/nfssvc.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/nfsd/nfssvc.c	Mon Aug 12 16:34:17 2002
@@ -189,7 +189,7 @@
 		 * recvfrom routine.
 		 */
 		while ((err = svc_recv(serv, rqstp,
-				       MAX_SCHEDULE_TIMEOUT)) == -EAGAIN)
+				       5*60*HZ)) == -EAGAIN)
 		    ;
 		if (err < 0)
 			break;
diff -urN linux-2.4.20-pre1/fs/nfsd/nfsxdr.c linux-2.4.20-pre2/fs/nfsd/nfsxdr.c
--- linux-2.4.20-pre1/fs/nfsd/nfsxdr.c	Wed Oct 17 14:16:34 2001
+++ linux-2.4.20-pre2/fs/nfsd/nfsxdr.c	Mon Aug 12 16:34:17 2002
@@ -132,8 +132,9 @@
 }
 
 static inline u32 *
-encode_fattr(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
+encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 {
+	struct inode *inode = fhp->fh_dentry->d_inode;
 	int type = (inode->i_mode & S_IFMT);
 
 	*p++ = htonl(nfs_ftypes[type >> 12]);
@@ -153,7 +154,12 @@
 	else
 		*p++ = htonl(0xffffffff);
 	*p++ = htonl((u32) inode->i_blocks);
-	*p++ = htonl((u32) inode->i_dev);
+	if (rqstp->rq_reffh->fh_version == 1 
+	    && rqstp->rq_reffh->fh_fsid_type == 1
+	    && (fhp->fh_export->ex_flags & NFSEXP_FSID))
+		*p++ = htonl((u32) fhp->fh_export->ex_fsid);
+	else
+		*p++ = htonl((u32) inode->i_dev);
 	*p++ = htonl((u32) inode->i_ino);
 	*p++ = htonl((u32) inode->i_atime);
 	*p++ = 0;
@@ -332,7 +338,7 @@
 nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd_attrstat *resp)
 {
-	p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode);
+	p = encode_fattr(rqstp, p, &resp->fh);
 	return xdr_ressize_check(rqstp, p);
 }
 
@@ -341,7 +347,7 @@
 					struct nfsd_diropres *resp)
 {
 	p = encode_fh(p, &resp->fh);
-	p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode);
+	p = encode_fattr(rqstp, p, &resp->fh);
 	return xdr_ressize_check(rqstp, p);
 }
 
@@ -358,7 +364,7 @@
 nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd_readres *resp)
 {
-	p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode);
+	p = encode_fattr(rqstp, p, &resp->fh);
 	*p++ = htonl(resp->count);
 	p += XDR_QUADLEN(resp->count);
 
diff -urN linux-2.4.20-pre1/fs/nfsd/vfs.c linux-2.4.20-pre2/fs/nfsd/vfs.c
--- linux-2.4.20-pre1/fs/nfsd/vfs.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/nfsd/vfs.c	Mon Aug 12 16:34:17 2002
@@ -114,35 +114,31 @@
 	if (isdotent(name, len)) {
 		if (len==1)
 			dentry = dget(dparent);
-		else  { /* must be ".." */
+		else if (dparent != exp->ex_dentry)
+			dentry = dget(dparent->d_parent);
+		else if (!EX_CROSSMNT(exp))
+			dentry = dget(dparent); /* .. == . just like at / */
+		else {
 			/* checking mountpoint crossing is very different when stepping up */
-			if (dparent == exp->ex_dentry) {
-				if (!EX_CROSSMNT(exp))
-					dentry = dget(dparent); /* .. == . just like at / */
-				else
-				{
-					struct svc_export *exp2 = NULL;
-					struct dentry *dp;
-					struct vfsmount *mnt = mntget(exp->ex_mnt);
-					dentry = dget(dparent);
-					while(follow_up(&mnt, &dentry))
-						;
-					dp = dget(dentry->d_parent);
-					dput(dentry);
-					dentry = dp;
-					for ( ; exp2 == NULL && dp->d_parent != dp;
-					      dp=dp->d_parent)
-						exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
-					if (exp2==NULL) {
-						dput(dentry);
-						dentry = dget(dparent);
-					} else {
-						exp = exp2;
-					}
-					mntput(mnt);
-				}
-			} else
-				dentry = dget(dparent->d_parent);
+			struct svc_export *exp2 = NULL;
+			struct dentry *dp;
+			struct vfsmount *mnt = mntget(exp->ex_mnt);
+			dentry = dget(dparent);
+			while(follow_up(&mnt, &dentry))
+				;
+			dp = dget(dentry->d_parent);
+			dput(dentry);
+			dentry = dp;
+			for ( ; exp2 == NULL && dp->d_parent != dp;
+			      dp=dp->d_parent)
+				exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
+			if (exp2==NULL) {
+				dput(dentry);
+				dentry = dget(dparent);
+			} else {
+				exp = exp2;
+			}
+			mntput(mnt);
 		}
 	} else {
 		fh_lock(fhp);
diff -urN linux-2.4.20-pre1/fs/nls/Config.in linux-2.4.20-pre2/fs/nls/Config.in
--- linux-2.4.20-pre1/fs/nls/Config.in	Mon Feb 25 11:38:09 2002
+++ linux-2.4.20-pre2/fs/nls/Config.in	Mon Aug 12 16:34:17 2002
@@ -12,7 +12,8 @@
 # msdos and Joliet want NLS
 if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
 	-o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
-	-o "$CONFIG_SMB_NLS" = "y" ]; then
+	-o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" \
+	-o "$CONFIG_BEFS_FS" != "n" ]; then
   define_bool CONFIG_NLS y
 else
   define_bool CONFIG_NLS n
diff -urN linux-2.4.20-pre1/fs/partitions/Config.in linux-2.4.20-pre2/fs/partitions/Config.in
--- linux-2.4.20-pre1/fs/partitions/Config.in	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/fs/partitions/Config.in	Mon Aug 12 16:34:17 2002
@@ -25,7 +25,7 @@
       bool '    Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
       bool '    Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
    fi
-   dep_bool '  Windows Logical Disk Manager (Dynamic Disk) support' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL
+   dep_bool '  Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL
    if [ "$CONFIG_LDM_PARTITION" = "y" ]; then
       bool '    Windows LDM extra logging' CONFIG_LDM_DEBUG
    fi
@@ -34,7 +34,7 @@
    bool '  Sun partition tables support' CONFIG_SUN_PARTITION
    bool '  EFI GUID Partition support' CONFIG_EFI_PARTITION
 else
-   if [ "$ARCH" = "alpha" ]; then
+   if [ "$CONFIG_ALPHA" = "y" ]; then
       define_bool CONFIG_OSF_PARTITION y
    fi
    if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \
@@ -65,7 +65,7 @@
    if [ "$CONFIG_DECSTATION" = "y" ]; then
       define_bool CONFIG_ULTRIX_PARTITION y
    fi
-   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+   if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
       define_bool CONFIG_SUN_PARTITION y
    fi
 fi
diff -urN linux-2.4.20-pre1/fs/partitions/msdos.c linux-2.4.20-pre2/fs/partitions/msdos.c
--- linux-2.4.20-pre1/fs/partitions/msdos.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/partitions/msdos.c	Mon Aug 12 16:34:17 2002
@@ -488,8 +488,8 @@
 	/*
 	 * The i386 partition handling programs very often
 	 * make partitions end on cylinder boundaries.
-	 * There is no need to do so, and Linux fdisk doesnt always
-	 * do this, and Windows NT on Alpha doesnt do this either,
+	 * There is no need to do so, and Linux fdisk doesn't always
+	 * do this, and Windows NT on Alpha doesn't do this either,
 	 * but still, this helps to guess #heads.
 	 */
 	data = read_dev_sector(bdev, 0, &sect);
diff -urN linux-2.4.20-pre1/fs/pipe.c linux-2.4.20-pre2/fs/pipe.c
--- linux-2.4.20-pre1/fs/pipe.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/pipe.c	Mon Aug 12 16:34:17 2002
@@ -212,7 +212,7 @@
 		do {
 			/*
 			 * Synchronous wake-up: it knows that this process
-			 * is going to give up this CPU, so it doesnt have
+			 * is going to give up this CPU, so it doesn't have
 			 * to do idle reschedules.
 			 */
 			wake_up_interruptible_sync(PIPE_WAIT(*inode));
diff -urN linux-2.4.20-pre1/fs/proc/proc_misc.c linux-2.4.20-pre2/fs/proc/proc_misc.c
--- linux-2.4.20-pre1/fs/proc/proc_misc.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/proc/proc_misc.c	Mon Aug 12 16:34:17 2002
@@ -55,7 +55,6 @@
 extern int get_module_list(char *);
 #endif
 extern int get_device_list(char *);
-extern int get_partition_list(char *, char **, off_t, int);
 extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
 extern int get_irq_list(char *);
@@ -254,6 +253,18 @@
 }
 #endif
 
+extern struct seq_operations partitions_op;
+static int partitions_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &partitions_op);
+}
+static struct file_operations proc_partitions_operations = {
+	open:		partitions_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	seq_release,
+};
+
 #ifdef CONFIG_MODULES
 static int modules_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -377,14 +388,6 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
-static int partitions_read_proc(char *page, char **start, off_t off,
-				 int count, int *eof, void *data)
-{
-	int len = get_partition_list(page, start, off, count);
-	if (len < count) *eof = 1;
-	return len;
-}
-
 #if !defined(CONFIG_ARCH_S390)
 static int interrupts_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -561,7 +564,6 @@
 #endif
 		{"stat",	kstat_read_proc},
 		{"devices",	devices_read_proc},
-		{"partitions",	partitions_read_proc},
 #if !defined(CONFIG_ARCH_S390)
 		{"interrupts",	interrupts_read_proc},
 #endif
@@ -588,6 +590,7 @@
 	if (entry)
 		entry->proc_fops = &proc_kmsg_operations;
 	create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
+	create_seq_entry("partitions", 0, &proc_partitions_operations);
 	create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
 #ifdef CONFIG_MODULES
 	create_seq_entry("ksyms", 0, &proc_ksyms_operations);
diff -urN linux-2.4.20-pre1/fs/reiserfs/bitmap.c linux-2.4.20-pre2/fs/reiserfs/bitmap.c
--- linux-2.4.20-pre1/fs/reiserfs/bitmap.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/bitmap.c	Mon Aug 12 16:34:17 2002
@@ -1,26 +1,70 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
+   
+/* Reiserfs block (de)allocator, bitmap-based. */
 
 #include <linux/config.h>
 #include <linux/sched.h>
-#include <linux/reiserfs_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
 #include <linux/locks.h>
-#include <asm/bitops.h>
-#include <linux/list.h>
+#include <linux/kernel.h>
 
-#ifdef CONFIG_REISERFS_CHECK
+#include <linux/reiserfs_fs.h>
+#include <linux/reiserfs_fs_sb.h>
+#include <linux/reiserfs_fs_i.h>
+
+#define PREALLOCATION_SIZE 8
+
+#define INODE_INFO(inode) (&(inode)->u.reiserfs_i)
+
+/* different reiserfs block allocator options */
+
+#define SB_ALLOC_OPTS(s) ((s)->u.reiserfs_sb.s_alloc_options.bits)
+
+#define  _ALLOC_concentrating_formatted_nodes 0
+#define  _ALLOC_displacing_large_files 1
+#define  _ALLOC_displacing_new_packing_localities 2
+#define  _ALLOC_old_hashed_relocation 3
+#define  _ALLOC_new_hashed_relocation 4
+#define  _ALLOC_skip_busy 5
+#define  _ALLOC_displace_based_on_dirid 6
+#define  _ALLOC_hashed_formatted_nodes 7
+#define  _ALLOC_old_way 8
+#define  _ALLOC_hundredth_slices 9
+
+#define  concentrating_formatted_nodes(s)     test_bit(_ALLOC_concentrating_formatted_nodes, &SB_ALLOC_OPTS(s))
+#define  displacing_large_files(s)            test_bit(_ALLOC_displacing_large_files, &SB_ALLOC_OPTS(s))
+#define  displacing_new_packing_localities(s) test_bit(_ALLOC_displacing_new_packing_localities, &SB_ALLOC_OPTS(s))
+
+#define SET_OPTION(optname) \
+   do { \
+        reiserfs_warning("reiserfs: option \"%s\" is set\n", #optname); \
+        set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \
+    } while(0)
+#define TEST_OPTION(optname, s) \
+    test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s))
+
+
+/* #define LIMIT(a,b) do { if ((a) > (b)) (a) = (b); } while(0) */
+
+static inline void get_bit_address (struct super_block * s,
+				    unsigned long block, int * bmap_nr, int * offset)
+{
+    /* It is in the bitmap block number equal to the block
+     * number divided by the number of bits in a block. */
+    *bmap_nr = block / (s->s_blocksize << 3);
+    /* Within that bitmap block it is located at bit offset *offset. */
+    *offset = block & ((s->s_blocksize << 3) - 1 );
+    return;
+}
 
-/* this is a safety check to make sure
-** blocks are reused properly.  used for debugging only.
-**
-** this checks, that block can be reused, and it has correct state
-**   (free or busy) 
-*/
+#ifdef CONFIG_REISERFS_CHECK
 int is_reusable (struct super_block * s, unsigned long block, int bit_value)
 {
     int i, j;
-  
+
     if (block == 0 || block >= SB_BLOCK_COUNT (s)) {
 	reiserfs_warning ("vs-4010: is_reusable: block number is out of range %lu (%u)\n",
 			  block, SB_BLOCK_COUNT (s));
@@ -29,104 +73,266 @@
 
     /* it can't be one of the bitmap blocks */
     for (i = 0; i < SB_BMAP_NR (s); i ++)
-	if (block == SB_AP_BITMAP (s)[i]->b_blocknr) {
+	if (block == SB_AP_BITMAP (s)[i].bh->b_blocknr) {
 	    reiserfs_warning ("vs: 4020: is_reusable: "
 			      "bitmap block %lu(%u) can't be freed or reused\n",
 			      block, SB_BMAP_NR (s));
 	    return 0;
 	}
   
-    i = block / (s->s_blocksize << 3);
+    get_bit_address (s, block, &i, &j);
+
     if (i >= SB_BMAP_NR (s)) {
 	reiserfs_warning ("vs-4030: is_reusable: there is no so many bitmap blocks: "
 			  "block=%lu, bitmap_nr=%d\n", block, i);
 	return 0;
     }
 
-    j = block % (s->s_blocksize << 3);
     if ((bit_value == 0 && 
-         reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i]->b_data)) ||
+         reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data)) ||
 	(bit_value == 1 && 
-	 reiserfs_test_le_bit(j, SB_AP_BITMAP (s)[i]->b_data) == 0)) {
+	 reiserfs_test_le_bit(j, SB_AP_BITMAP (s)[i].bh->b_data) == 0)) {
 	reiserfs_warning ("vs-4040: is_reusable: corresponding bit of block %lu does not "
 			  "match required value (i==%d, j==%d) test_bit==%d\n",
-		block, i, j, reiserfs_test_le_bit (j, SB_AP_BITMAP (s)[i]->b_data));
+		block, i, j, reiserfs_test_le_bit (j, SB_AP_BITMAP (s)[i].bh->b_data));
+		
 	return 0;
     }
 
     if (bit_value == 0 && block == SB_ROOT_BLOCK (s)) {
 	reiserfs_warning ("vs-4050: is_reusable: this is root block (%u), "
-			  "it must be busy", SB_ROOT_BLOCK (s));
+			  "it must be busy\n", SB_ROOT_BLOCK (s));
 	return 0;
     }
 
     return 1;
 }
+#endif /* CONFIG_REISERFS_CHECK */
 
+/* searches in journal structures for a given block number (bmap, off). If block
+   is found in reiserfs journal it suggests next free block candidate to test. */
+static inline  int is_block_in_journal (struct super_block * s, int bmap, int off, int *next)
+{
+    unsigned int tmp;
 
+    if (reiserfs_in_journal (s, s->s_dev, bmap, off, s->s_blocksize, 1, &tmp)) {
+	if (tmp) {		/* hint supplied */
+	    *next = tmp;
+	    PROC_INFO_INC( s, scan_bitmap.in_journal_hint );
+	} else {
+	    (*next) = off + 1;		/* inc offset to avoid looping. */
+	    PROC_INFO_INC( s, scan_bitmap.in_journal_nohint );
+	}
+	PROC_INFO_INC( s, scan_bitmap.retry );
+	return 1;
+    }
+    return 0;
+}
 
+/* it searches for a window of zero bits with given minimum and maximum lengths in one bitmap
+ * block; */
+static int scan_bitmap_block (struct reiserfs_transaction_handle *th,
+			      int bmap_n, int *beg, int boundary, int min, int max, int unfm)
+{
+    struct super_block *s = th->t_super;
+    struct reiserfs_bitmap_info *bi=&SB_AP_BITMAP(s)[bmap_n];
+    int end, next;
+    int org = *beg;
+
+    RFALSE(bmap_n >= SB_BMAP_NR (s), "Bitmap %d is out of range (0..%d)\n",bmap_n, SB_BMAP_NR (s) - 1);
+    PROC_INFO_INC( s, scan_bitmap.bmap );
+/* this is unclear and lacks comments, explain how journal bitmaps
+   work here for the reader.  Convey a sense of the design here. What
+   is a window? */
+/* - I mean `a window of zero bits' as in description of this function - Zam. */
 
-#endif /* CONFIG_REISERFS_CHECK */
+    if ( !bi ) {
+	printk("Hey, bitmap info pointer is zero for bitmap %d!\n",bmap_n);
+	return 0;
+    }
+    if (buffer_locked (bi->bh)) {
+       PROC_INFO_INC( s, scan_bitmap.wait );
+       __wait_on_buffer (bi->bh);
+    }
+
+    /* If we know that first zero bit is only one or first zero bit is
+       closer to the end of bitmap than our start pointer */
+    if (bi->first_zero_hint > *beg || bi->free_count == 1)
+	*beg = bi->first_zero_hint;
+
+    while (1) {
+	cont:
+	if (bi->free_count < min)
+		return 0; // No free blocks in this bitmap
+
+	/* search for a first zero bit -- beggining of a window */
+	*beg = reiserfs_find_next_zero_le_bit
+	        ((unsigned long*)(bi->bh->b_data), boundary, *beg);
 
-/* get address of corresponding bit (bitmap block number and offset in it) */
-static inline void get_bit_address (struct super_block * s, unsigned long block, int * bmap_nr, int * offset)
-{
-                                /* It is in the bitmap block number equal to the block number divided by the number of
-                                   bits in a block. */
-    *bmap_nr = block / (s->s_blocksize << 3);
-                                /* Within that bitmap block it is located at bit offset *offset. */
-    *offset = block % (s->s_blocksize << 3);
-    return;
+	if (*beg + min > boundary) { /* search for a zero bit fails or the rest of bitmap block
+				      * cannot contain a zero window of minimum size */
+	    return 0;
+	}
+
+	if (unfm && is_block_in_journal(s,bmap_n, *beg, beg))
+	    continue;
+	/* first zero bit found; we check next bits */
+	for (end = *beg + 1;; end ++) {
+	    if (end >= *beg + max || end >= boundary || reiserfs_test_le_bit (end, bi->bh->b_data)) {
+		next = end;
+		break;
+	    }
+	    /* finding the other end of zero bit window requires looking into journal structures (in
+	     * case of searching for free blocks for unformatted nodes) */
+	    if (unfm && is_block_in_journal(s, bmap_n, end, &next))
+		break;
+	}
+
+	/* now (*beg) points to beginning of zero bits window,
+	 * (end) points to one bit after the window end */
+	if (end - *beg >= min) { /* it seems we have found window of proper size */
+	    int i;
+	    reiserfs_prepare_for_journal (s, bi->bh, 1);
+	    /* try to set all blocks used checking are they still free */
+	    for (i = *beg; i < end; i++) {
+		/* It seems that we should not check in journal again. */
+		if (reiserfs_test_and_set_le_bit (i, bi->bh->b_data)) {
+		    /* bit was set by another process
+		     * while we slept in prepare_for_journal() */
+		    PROC_INFO_INC( s, scan_bitmap.stolen );
+		    if (i >= *beg + min)	{ /* we can continue with smaller set of allocated blocks,
+					   * if length of this set is more or equal to `min' */
+			end = i;
+			break;
+		    }
+		    /* otherwise we clear all bit were set ... */
+		    while (--i >= *beg)
+			reiserfs_test_and_clear_le_bit (i, bi->bh->b_data);
+		    reiserfs_restore_prepared_buffer (s, bi->bh);
+		    *beg = max(org, (int)bi->first_zero_hint);
+		    /* ... and search again in current block from beginning */
+		    goto cont;	
+		}
+	    }
+	    bi->free_count -= (end - *beg);
+
+	    /* if search started from zero_hint bit, and zero hint have not
+                changed since, then we need to update first_zero_hint */
+	    if ( bi->first_zero_hint >= *beg)
+		/* no point in looking for free bit if there is not any */
+		bi->first_zero_hint = (bi->free_count > 0 ) ?
+			reiserfs_find_next_zero_le_bit
+			((unsigned long*)(bi->bh->b_data), s->s_blocksize << 3, end) : (s->s_blocksize << 3);
+
+	    journal_mark_dirty (th, s, bi->bh);
+
+	    /* free block count calculation */
+	    reiserfs_prepare_for_journal (s, SB_BUFFER_WITH_SB(s), 1);
+	    PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (end - *beg));
+	    journal_mark_dirty (th, s, SB_BUFFER_WITH_SB(s));
+
+	    return end - (*beg);
+	} else {
+	    *beg = next;
+	}
+    }
 }
 
+/* Tries to find contiguous zero bit window (given size) in given region of
+ * bitmap and place new blocks there. Returns number of allocated blocks. */
+static int scan_bitmap (struct reiserfs_transaction_handle *th,
+			unsigned long *start, unsigned long finish,
+			int min, int max, int unfm, unsigned long file_block)
+{
+    int nr_allocated=0;
+    struct super_block * s = th->t_super;
+    /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr
+     * - Hans, it is not a block number - Zam. */
+
+    int bm, off;
+    int end_bm, end_off;
+    int off_max = s->s_blocksize << 3;
+
+    PROC_INFO_INC( s, scan_bitmap.call ); 
+    if ( SB_FREE_BLOCKS(s) <= 0)
+	return 0; // No point in looking for more free blocks
+
+    get_bit_address (s, *start, &bm, &off);
+    get_bit_address (s, finish, &end_bm, &end_off);
+
+    // With this option set first we try to find a bitmap that is at least 10%
+    // free, and if that fails, then we fall back to old whole bitmap scanning
+    if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) {
+	for (;bm < end_bm; bm++, off = 0) {
+	    if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 )
+		nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
+	    if (nr_allocated)
+		goto ret;
+        }
+	get_bit_address (s, *start, &bm, &off);
+    }
+
+    for (;bm < end_bm; bm++, off = 0) {
+	nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
+	if (nr_allocated)
+	    goto ret;
+    }
+
+    nr_allocated = scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm);
 
-/* There would be a modest performance benefit if we write a version
-   to free a list of blocks at once. -Hans */
-				/* I wonder if it would be less modest
-                                   now that we use journaling. -Hans */
-static void _reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long block)
+ ret:
+    *start = bm * off_max + off;
+    return nr_allocated;
+
+}
+
+static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
+			  b_blocknr_t block)
 {
     struct super_block * s = th->t_super;
     struct reiserfs_super_block * rs;
     struct buffer_head * sbh;
-    struct buffer_head ** apbh;
+    struct reiserfs_bitmap_info *apbi;
     int nr, offset;
 
-  PROC_INFO_INC( s, free_block );
-
-  rs = SB_DISK_SUPER_BLOCK (s);
-  sbh = SB_BUFFER_WITH_SB (s);
-  apbh = SB_AP_BITMAP (s);
-
-  get_bit_address (s, block, &nr, &offset);
-
-  if (nr >= sb_bmap_nr (rs)) {
-	  reiserfs_warning ("vs-4075: reiserfs_free_block: "
-			    "block %lu is out of range on %s\n", 
-			    block, bdevname(s->s_dev));
-	  return;
-  }
-
-  reiserfs_prepare_for_journal(s, apbh[nr], 1 ) ;
-
-  /* clear bit for the given block in bit map */
-  if (!reiserfs_test_and_clear_le_bit (offset, apbh[nr]->b_data)) {
-      reiserfs_warning ("vs-4080: reiserfs_free_block: "
-			"free_block (%04x:%lu)[dev:blocknr]: bit already cleared\n", 
-	    s->s_dev, block);
-  }
-  journal_mark_dirty (th, s, apbh[nr]);
+    PROC_INFO_INC( s, free_block );
 
-  reiserfs_prepare_for_journal(s, sbh, 1) ;
-  /* update super block */
-  set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
+    rs = SB_DISK_SUPER_BLOCK (s);
+    sbh = SB_BUFFER_WITH_SB (s);
+    apbi = SB_AP_BITMAP(s);
+  
+    get_bit_address (s, block, &nr, &offset);
+  
+    if (nr >= sb_bmap_nr (rs)) {
+	reiserfs_warning ("vs-4075: reiserfs_free_block: "
+			  "block %lu is out of range on %s\n",
+			  block, bdevname(s->s_dev));
+	return;
+    }
 
-  journal_mark_dirty (th, s, sbh);
-  s->s_dirt = 1;
+    reiserfs_prepare_for_journal(s, apbi[nr].bh, 1 ) ;
+  
+    /* clear bit for the given block in bit map */
+    if (!reiserfs_test_and_clear_le_bit (offset, apbi[nr].bh->b_data)) {
+	reiserfs_warning ("vs-4080: reiserfs_free_block: "
+			  "free_block (%04x:%lu)[dev:blocknr]: bit already cleared\n", 
+			  s->s_dev, block);
+    }
+    if (offset < apbi[nr].first_zero_hint) {
+	apbi[nr].first_zero_hint = offset;
+    }
+    apbi[nr].free_count ++;
+    journal_mark_dirty (th, s, apbi[nr].bh);
+  
+    reiserfs_prepare_for_journal(s, sbh, 1) ;
+    /* update super block */
+    set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
+  
+    journal_mark_dirty (th, s, sbh);
 }
 
-void reiserfs_free_block (struct reiserfs_transaction_handle *th, 
-                          unsigned long block) {
+void reiserfs_free_block (struct reiserfs_transaction_handle *th,
+			  unsigned long block) {
     struct super_block * s = th->t_super;
 
     RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
@@ -144,568 +350,558 @@
     _reiserfs_free_block(th, block) ;
 }
 
-/* beginning from offset-th bit in bmap_nr-th bitmap block,
-   find_forward finds the closest zero bit. It returns 1 and zero
-   bit address (bitmap, offset) if zero bit found or 0 if there is no
-   zero bit in the forward direction */
-/* The function is NOT SCHEDULE-SAFE! */
-static int find_forward (struct super_block * s, int * bmap_nr, int * offset, int for_unformatted)
-{
-  int i, j;
-  struct buffer_head * bh;
-  unsigned long block_to_try = 0;
-  unsigned long next_block_to_try = 0 ;
-
-  PROC_INFO_INC( s, find_forward.call );
-
-  for (i = *bmap_nr; i < SB_BMAP_NR (s); i ++, *offset = 0, 
-	       PROC_INFO_INC( s, find_forward.bmap )) {
-    /* get corresponding bitmap block */
-    bh = SB_AP_BITMAP (s)[i];
-    if (buffer_locked (bh)) {
-	PROC_INFO_INC( s, find_forward.wait );
-        __wait_on_buffer (bh);
-    }
-retry:
-    j = reiserfs_find_next_zero_le_bit ((unsigned long *)bh->b_data, 
-                                         s->s_blocksize << 3, *offset);
-
-    /* wow, this really needs to be redone.  We can't allocate a block if
-    ** it is in the journal somehow.  reiserfs_in_journal makes a suggestion
-    ** for a good block if the one you ask for is in the journal.  Note,
-    ** reiserfs_in_journal might reject the block it suggests.  The big
-    ** gain from the suggestion is when a big file has been deleted, and
-    ** many blocks show free in the real bitmap, but are all not free
-    ** in the journal list bitmaps.
-    **
-    ** this whole system sucks.  The bitmaps should reflect exactly what
-    ** can and can't be allocated, and the journal should update them as
-    ** it goes.  TODO.
-    */
-    if (j < (s->s_blocksize << 3)) {
-      block_to_try = (i * (s->s_blocksize << 3)) + j; 
-
-      /* the block is not in the journal, we can proceed */
-      if (!(reiserfs_in_journal(s, s->s_dev, block_to_try, s->s_blocksize, for_unformatted, &next_block_to_try))) {
-	*bmap_nr = i;
-	*offset = j;
-	return 1;
-      } 
-      /* the block is in the journal */
-      else if ((j+1) < (s->s_blocksize << 3)) { /* try again */
-	/* reiserfs_in_journal suggested a new block to try */
-	if (next_block_to_try > 0) {
-	  int new_i ;
-	  get_bit_address (s, next_block_to_try, &new_i, offset);
-
-	  PROC_INFO_INC( s, find_forward.in_journal_hint );
-
-	  /* block is not in this bitmap. reset i and continue
-	  ** we only reset i if new_i is in a later bitmap.
-	  */
-	  if (new_i > i) {
-	    i = (new_i - 1 ); /* i gets incremented by the for loop */
-	    PROC_INFO_INC( s, find_forward.in_journal_out );
-	    continue ;
-	  }
-	} else {
-	  /* no suggestion was made, just try the next block */
-	  *offset = j+1 ;
-	}
-	PROC_INFO_INC( s, find_forward.retry );
-	goto retry ;
-      }
+static void __discard_prealloc (struct reiserfs_transaction_handle * th,
+				struct inode * inode)
+{
+    unsigned long save = inode->u.reiserfs_i.i_prealloc_block ;
+#ifdef CONFIG_REISERFS_CHECK
+    if (inode->u.reiserfs_i.i_prealloc_count < 0)
+	reiserfs_warning("zam-4001:%s: inode has negative prealloc blocks count.\n", __FUNCTION__ );
+#endif  
+    while (inode->u.reiserfs_i.i_prealloc_count > 0) {
+	reiserfs_free_prealloc_block(th,inode->u.reiserfs_i.i_prealloc_block);
+	inode->u.reiserfs_i.i_prealloc_block++;
+	inode->u.reiserfs_i.i_prealloc_count --;
+    }
+    inode->u.reiserfs_i.i_prealloc_block = save ;
+    list_del (&(inode->u.reiserfs_i.i_prealloc_list));
+}
+
+/* FIXME: It should be inline function */
+void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
+				struct inode * inode)
+{
+    if (inode->u.reiserfs_i.i_prealloc_count) {
+	__discard_prealloc(th, inode);
+    }
+}
+
+void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
+{
+  struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
+  struct inode * inode;
+  
+  while (!list_empty(plist)) {
+    inode = list_entry(plist->next, struct inode, u.reiserfs_i.i_prealloc_list);
+#ifdef CONFIG_REISERFS_CHECK
+    if (!inode->u.reiserfs_i.i_prealloc_count) {
+      reiserfs_warning("zam-4001:%s: inode is in prealloc list but has no preallocated blocks.\n", __FUNCTION__ );
     }
+#endif
+    __discard_prealloc(th, inode);
   }
-    /* zero bit not found */
-    return 0;
 }
 
-/* return 0 if no free blocks, else return 1 */
-/* The function is NOT SCHEDULE-SAFE!  
-** because the bitmap block we want to change could be locked, and on its
-** way to the disk when we want to read it, and because of the 
-** flush_async_commits.  Per bitmap block locks won't help much, and 
-** really aren't needed, as we retry later on if we try to set the bit
-** and it is already set.
-*/
-static int find_zero_bit_in_bitmap (struct super_block * s, 
-                                    unsigned long search_start, 
-				    int * bmap_nr, int * offset, 
-				    int for_unformatted)
-{
-  int retry_count = 0 ;
-  /* get bit location (bitmap number and bit offset) of search_start block */
-  get_bit_address (s, search_start, bmap_nr, offset);
-
-    /* note that we search forward in the bitmap, benchmarks have shown that it is better to allocate in increasing
-       sequence, which is probably due to the disk spinning in the forward direction.. */
-    if (find_forward (s, bmap_nr, offset, for_unformatted) == 0) {
-      /* there wasn't a free block with number greater than our
-         starting point, so we are going to go to the beginning of the disk */
-
-retry:
-      search_start = 0; /* caller will reset search_start for itself also. */
-      get_bit_address (s, search_start, bmap_nr, offset);
-      if (find_forward (s, bmap_nr,offset,for_unformatted) == 0) {
-	if (for_unformatted) {	/* why only unformatted nodes? -Hans */
-	  if (retry_count == 0) {
-	    /* we've got a chance that flushing async commits will free up
-	    ** some space.  Sync then retry
-	    */
-	    flush_async_commits(s) ;
-	    retry_count++ ;
-	    goto retry ;
-	  } else if (retry_count > 0) {
-	    /* nothing more we can do.  Make the others wait, flush
-	    ** all log blocks to disk, and flush to their home locations.
-	    ** this will free up any blocks held by the journal
-	    */
-	    SB_JOURNAL(s)->j_must_wait = 1 ;
-	  }
+/* block allocator related options are parsed here */
+int reiserfs_parse_alloc_options(struct super_block * s, char * options)
+{
+    char * this_char, * value;
+
+    s->u.reiserfs_sb.s_alloc_options.preallocmin = 4;
+    s->u.reiserfs_sb.s_alloc_options.bits = 0; /* clear default settings */
+
+    for (this_char = strtok (options, ":"); this_char != NULL; this_char = strtok (NULL, ":")) {
+	if ((value = strchr (this_char, '=')) != NULL)
+	    *value++ = 0;
+
+	if (!strcmp(this_char, "concentrating_formatted_nodes")) {
+	    int temp;
+	    SET_OPTION(concentrating_formatted_nodes);
+	    temp = (value && *value) ? simple_strtoul (value, &value, 0) : 10;
+	    if (temp <= 0 || temp > 100) {
+		s->u.reiserfs_sb.s_alloc_options.border = 10;
+	    } else {
+		s->u.reiserfs_sb.s_alloc_options.border = 100 / temp;
+	   }
+	    continue;
+	}
+	if (!strcmp(this_char, "displacing_large_files")) {
+	    SET_OPTION(displacing_large_files);
+	    s->u.reiserfs_sb.s_alloc_options.large_file_size =
+		(value && *value) ? simple_strtoul (value, &value, 0) : 16;
+	    continue;
+	}
+	if (!strcmp(this_char, "displacing_new_packing_localities")) {
+	    SET_OPTION(displacing_new_packing_localities);
+	    continue;
+	};
+
+	if (!strcmp(this_char, "old_hashed_relocation")) {
+	    SET_OPTION(old_hashed_relocation);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "new_hashed_relocation")) {
+	    SET_OPTION(new_hashed_relocation);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "hashed_formatted_nodes")) {
+	    SET_OPTION(hashed_formatted_nodes);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "skip_busy")) {
+	    SET_OPTION(skip_busy);
+	    continue;
 	}
-        return 0;
-      }
+
+	if (!strcmp(this_char, "hundredth_slices")) {
+	    SET_OPTION(hundredth_slices);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "old_way")) {
+	    SET_OPTION(old_way);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "displace_based_on_dirid")) {
+	    SET_OPTION(displace_based_on_dirid);
+	    continue;
+	}
+
+	if (!strcmp(this_char, "preallocmin")) {
+	    s->u.reiserfs_sb.s_alloc_options.preallocmin =
+		(value && *value) ? simple_strtoul (value, &value, 0) : 4;
+	    continue;
+	}
+
+	if (!strcmp(this_char, "preallocsize")) {
+	    s->u.reiserfs_sb.s_alloc_options.preallocsize =
+		(value && *value) ? simple_strtoul (value, &value, 0) : PREALLOCATION_SIZE;
+	    continue;
+	}
+
+	reiserfs_warning("zam-4001: %s : unknown option - %s\n", __FUNCTION__ , this_char);
+	return 1;
     }
-  return 1;
+
+    return 0;
 }
 
-/* get amount_needed free block numbers from scanning the bitmap of
-   free/used blocks.
-   
-   Optimize layout by trying to find them starting from search_start
-   and moving in increasing blocknr direction.  (This was found to be
-   faster than using a bi-directional elevator_direction, in part
-   because of disk spin direction, in part because by the time one
-   reaches the end of the disk the beginning of the disk is the least
-   congested).
-
-   search_start is the block number of the left
-   semantic neighbor of the node we create.
-
-   return CARRY_ON if everything is ok
-   return NO_DISK_SPACE if out of disk space
-   return NO_MORE_UNUSED_CONTIGUOUS_BLOCKS if the block we found is not contiguous to the last one
-   
-   return block numbers found, in the array free_blocknrs.  assumes
-   that any non-zero entries already present in the array are valid.
-   This feature is perhaps convenient coding when one might not have
-   used all blocknrs from the last time one called this function, or
-   perhaps it is an archaism from the days of schedule tracking, one
-   of us ought to reread the code that calls this, and analyze whether
-   it is still the right way to code it.
-
-   spare space is used only when priority is set to 1. reiserfsck has
-   its own reiserfs_new_blocknrs, which can use reserved space
-
-   exactly what reserved space?  the SPARE_SPACE?  if so, please comment reiserfs.h.
-
-   Give example of who uses spare space, and say that it is a deadlock
-   avoidance mechanism.  -Hans */
-
-/* This function is NOT SCHEDULE-SAFE! */
-
-static int do_reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th,
-                                     unsigned long * free_blocknrs, 
-				     unsigned long search_start, 
-				     int amount_needed, int priority, 
-				     int for_unformatted,
-				     int for_prealloc)
-{
-  struct super_block * s = th->t_super;
-  int i, j;
-  unsigned long * block_list_start = free_blocknrs;
-  int init_amount_needed = amount_needed;
-  unsigned long new_block = 0 ; 
-
-    if (SB_FREE_BLOCKS (s) < SPARE_SPACE && !priority)
-	/* we can answer NO_DISK_SPACE being asked for new block with
-	   priority 0 */
-	return NO_DISK_SPACE;
-
-  RFALSE( !s, "vs-4090: trying to get new block from nonexistent device");
-  RFALSE( search_start == MAX_B_NUM,
-	  "vs-4100: we are optimizing location based on "
-	  "the bogus location of a temp buffer (%lu).", search_start);
-  RFALSE( amount_needed < 1 || amount_needed > 2,
-	  "vs-4110: amount_needed parameter incorrect (%d)", amount_needed);
-
-  /* We continue the while loop if another process snatches our found
-   * free block from us after we find it but before we successfully
-   * mark it as in use */
-
-  while (amount_needed--) {
-    /* skip over any blocknrs already gotten last time. */
-    if (*(free_blocknrs) != 0) {
-      RFALSE( is_reusable (s, *free_blocknrs, 1) == 0, 
-	      "vs-4120: bad blocknr on free_blocknrs list");
-      free_blocknrs++;
-      continue;
-    }
-    /* look for zero bits in bitmap */
-    if (find_zero_bit_in_bitmap(s,search_start, &i, &j,for_unformatted) == 0) {
-      if (find_zero_bit_in_bitmap(s,search_start,&i,&j, for_unformatted) == 0) {
-				/* recode without the goto and without
-				   the if.  It will require a
-				   duplicate for.  This is worth the
-				   code clarity.  Your way was
-				   admirable, and just a bit too
-				   clever in saving instructions.:-)
-				   I'd say create a new function, but
-				   that would slow things also, yes?
-				   -Hans */
-free_and_return:
-	for ( ; block_list_start != free_blocknrs; block_list_start++) {
-	  reiserfs_free_block (th, *block_list_start);
-	  *block_list_start = 0;
-	}
-	if (for_prealloc) 
-	    return NO_MORE_UNUSED_CONTIGUOUS_BLOCKS;
-	else
-	    return NO_DISK_SPACE;
-      }
+static void inline new_hashed_relocation (reiserfs_blocknr_hint_t * hint)
+{
+    char * hash_in;
+    if (hint->formatted_node) {
+	    hash_in = (char*)&hint->key.k_dir_id;
+    } else {
+	if (!hint->inode) {
+	    //hint->search_start = hint->beg;
+	    hash_in = (char*)&hint->key.k_dir_id;
+	} else 
+	    if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
+		hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
+	    else
+		hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
     }
-    
-    /* i and j now contain the results of the search. i = bitmap block
-       number containing free block, j = offset in this block.  we
-       compute the blocknr which is our result, store it in
-       free_blocknrs, and increment the pointer so that on the next
-       loop we will insert into the next location in the array.  Also
-       in preparation for the next loop, search_start is changed so
-       that the next search will not rescan the same range but will
-       start where this search finished.  Note that while it is
-       possible that schedule has occurred and blocks have been freed
-       in that range, it is perhaps more important that the blocks
-       returned be near each other than that they be near their other
-       neighbors, and it also simplifies and speeds the code this way.  */
-
-    /* journal: we need to make sure the block we are giving out is not
-    ** a log block, horrible things would happen there.
-    */
-    new_block = (i * (s->s_blocksize << 3)) + j; 
-    if (for_prealloc && (new_block - 1) != search_start) {
-      /* preallocated blocks must be contiguous, bail if we didnt find one.
-      ** this is not a bug.  We want to do the check here, before the
-      ** bitmap block is prepared, and before we set the bit and log the
-      ** bitmap. 
-      **
-      ** If we do the check after this function returns, we have to 
-      ** call reiserfs_free_block for new_block, which would be pure
-      ** overhead.
-      **
-      ** for_prealloc should only be set if the caller can deal with the
-      ** NO_MORE_UNUSED_CONTIGUOUS_BLOCKS return value.  This can be
-      ** returned before the disk is actually full
-      */
-      goto free_and_return ;
-    }
-    search_start = new_block ;
-    if (search_start >= reiserfs_get_journal_block(s) &&
-        search_start < (reiserfs_get_journal_block(s) + JOURNAL_BLOCK_COUNT)) {
-	reiserfs_warning("vs-4130: reiserfs_new_blocknrs: trying to allocate log block %lu\n",
-			 search_start) ;
-	search_start++ ;
-	amount_needed++ ;
-	continue ;
-    }
-       
-
-    reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[i], 1) ;
-
-    RFALSE( buffer_locked (SB_AP_BITMAP (s)[i]) || 
-	    is_reusable (s, search_start, 0) == 0,
-	    "vs-4140: bitmap block is locked or bad block number found");
-
-    /* if this bit was already set, we've scheduled, and someone else
-    ** has allocated it.  loop around and try again
-    */
-    if (reiserfs_test_and_set_le_bit (j, SB_AP_BITMAP (s)[i]->b_data)) {
-	reiserfs_restore_prepared_buffer(s, SB_AP_BITMAP(s)[i]) ;
-	amount_needed++ ;
-	continue ;
-    }    
-    journal_mark_dirty (th, s, SB_AP_BITMAP (s)[i]); 
-    *free_blocknrs = search_start ;
-    free_blocknrs ++;
-  }
 
-  reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-  /* update free block count in super block */
-  PUT_SB_FREE_BLOCKS( s, SB_FREE_BLOCKS(s) - init_amount_needed );
-  journal_mark_dirty (th, s, SB_BUFFER_WITH_SB (s));
-  s->s_dirt = 1;
-
-  return CARRY_ON;
-}
-
-// this is called only by get_empty_nodes
-int reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
-			    unsigned long search_start, int amount_needed) {
-  return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, amount_needed, 0/*priority*/, 0/*for_formatted*/, 0/*for_prealloc */) ;
-}
-
-
-// called by get_new_buffer and by reiserfs_get_block with amount_needed == 1
-int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
-			      unsigned long search_start) {
-  return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
-                                  1/*amount_needed*/,
-				  0/*priority*/, 
-				  1/*for formatted*/,
-				  0/*for prealloc */) ;
-}
-
-#ifdef REISERFS_PREALLOCATE
-
-/* 
-** We pre-allocate 8 blocks.  Pre-allocation is used for files > 16 KB only.
-** This lowers fragmentation on large files by grabbing a contiguous set of
-** blocks at once.  It also limits the number of times the bitmap block is
-** logged by making X number of allocation changes in a single transaction.
-**
-** We are using a border to divide the disk into two parts.  The first part
-** is used for tree blocks, which have a very high turnover rate (they
-** are constantly allocated then freed)
-**
-** The second part of the disk is for the unformatted nodes of larger files.
-** Putting them away from the tree blocks lowers fragmentation, and makes
-** it easier to group files together.  There are a number of different
-** allocation schemes being tried right now, each is documented below.
-**
-** A great deal of the allocator's speed comes because reiserfs_get_block
-** sends us the block number of the last unformatted node in the file.  Once
-** a given block is allocated past the border, we don't collide with the
-** blocks near the search_start again.
-** 
-*/
-int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th, 
-				struct inode       * p_s_inode,
-				unsigned long      * free_blocknrs,
-				unsigned long        search_start)
-{
-  int ret=0, blks_gotten=0;
-  unsigned long border = 0;
-  unsigned long bstart = 0;
-  unsigned long hash_in, hash_out;
-  unsigned long saved_search_start=search_start;
-  int allocated[PREALLOCATION_SIZE];
-  int blks;
-
-  if (!reiserfs_no_border(th->t_super)) {
-    /* we default to having the border at the 10% mark of the disk.  This
-    ** is an arbitrary decision and it needs tuning.  It also needs a limit
-    ** to prevent it from taking too much space on huge drives.
-    */
-    bstart = (SB_BLOCK_COUNT(th->t_super) / 10); 
-  }
-  if (!reiserfs_no_unhashed_relocation(th->t_super)) {
-    /* this is a very simple first attempt at preventing too much grouping
-    ** around the border value.  Since k_dir_id is never larger than the
-    ** highest allocated oid, it is far from perfect, and files will tend
-    ** to be grouped towards the start of the border
-    */
-    border = le32_to_cpu(INODE_PKEY(p_s_inode)->k_dir_id) % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
-  } else if (!reiserfs_hashed_relocation(th->t_super)) {
-      hash_in = le32_to_cpu((INODE_PKEY(p_s_inode))->k_dir_id);
-				/* I wonder if the CPU cost of the
-                                   hash will obscure the layout
-                                   effect? Of course, whether that
-                                   effect is good or bad we don't
-                                   know.... :-) */
-      
-      hash_out = keyed_hash(((char *) (&hash_in)), 4);
-      border = hash_out % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
-  }
-  border += bstart ;
-  allocated[0] = 0 ; /* important.  Allows a check later on to see if at
-                      * least one block was allocated.  This prevents false
-		      * no disk space returns
-		      */
-
-  if ( (p_s_inode->i_size < 4 * 4096) || 
-       !(S_ISREG(p_s_inode->i_mode)) )
-    {
-      if ( search_start < border 
-	   || (
-				/* allow us to test whether it is a
-                                   good idea to prevent files from
-                                   getting too far away from their
-                                   packing locality by some unexpected
-                                   means.  This might be poor code for
-                                   directories whose files total
-                                   larger than 1/10th of the disk, and
-                                   it might be good code for
-                                   suffering from old insertions when the disk
-                                   was almost full. */
-               /* changed from !reiserfs_test3(th->t_super), which doesn't
-               ** seem like a good idea.  Think about adding blocks to
-               ** a large file.  If you've allocated 10% of the disk
-               ** in contiguous blocks, you start over at the border value
-               ** for every new allocation.  This throws away all the
-               ** information sent in about the last block that was allocated
-               ** in the file.  Not a good general case at all.
-               ** -chris
-               */
-	       reiserfs_test4(th->t_super) && 
-	       (search_start > border + (SB_BLOCK_COUNT(th->t_super) / 10))
-	       )
-	   )
-	search_start=border;
-  
-      ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
-				     1/*amount_needed*/, 
-				     0/*use reserved blocks for root */,
-				     1/*for_formatted*/,
-				     0/*for prealloc */) ;  
-      return ret;
-    }
-
-  /* take a block off the prealloc list and return it -Hans */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count > 0) {
-    p_s_inode->u.reiserfs_i.i_prealloc_count--;
-    *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block++;
-
-    /* if no more preallocated blocks, remove inode from list */
-    if (! p_s_inode->u.reiserfs_i.i_prealloc_count) {
-      list_del(&p_s_inode->u.reiserfs_i.i_prealloc_list);
+    hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
+}
+
+static void inline get_left_neighbor(reiserfs_blocknr_hint_t *hint)
+{
+    struct path * path;
+    struct buffer_head * bh;
+    struct item_head * ih;
+    int pos_in_item;
+    __u32 * item;
+
+    if (!hint->path)		/* reiserfs code can call this function w/o pointer to path
+				 * structure supplied; then we rely on supplied search_start */
+	return;
+
+    path = hint->path;
+    bh = get_last_bh(path);
+    RFALSE( !bh, "green-4002: Illegal path specified to get_left_neighbor\n");
+    ih = get_ih(path);
+    pos_in_item = path->pos_in_item;
+    item = get_item (path);
+
+    hint->search_start = bh->b_blocknr;
+
+    if (!hint->formatted_node && is_indirect_le_ih (ih)) {
+	/* for indirect item: go to left and look for the first non-hole entry
+	   in the indirect item */
+	if (pos_in_item == I_UNFM_NUM (ih))
+	    pos_in_item--;
+//	    pos_in_item = I_UNFM_NUM (ih) - 1;
+	while (pos_in_item >= 0) {
+	    int t=get_block_num(item,pos_in_item);
+	    if (t) {
+		hint->search_start = t;
+		break;
+	    }
+	    pos_in_item --;
+	}
+    } else {
     }
+
+    /* does result value fit into specified region? */
+    return;
+}
+
+/* should be, if formatted node, then try to put on first part of the device
+   specified as number of percent with mount option device, else try to put
+   on last of device.  This is not to say it is good code to do so,
+   but the effect should be measured.  */
+static void inline set_border_in_hint(struct super_block *s, reiserfs_blocknr_hint_t *hint)
+{
+    b_blocknr_t border = SB_BLOCK_COUNT(hint->th->t_super) / s->u.reiserfs_sb.s_alloc_options.border;
+
+    if (hint->formatted_node)
+	hint->end = border - 1;
+    else
+	hint->beg = border;
+}
+
+static void inline displace_large_file(reiserfs_blocknr_hint_t *hint)
+{
+    if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
+	hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_dir_id), 4) % (hint->end - hint->beg);
+    else
+	hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_objectid), 4) % (hint->end - hint->beg);
+}
+
+static void inline hash_formatted_node(reiserfs_blocknr_hint_t *hint)
+{
+   char * hash_in;
+
+   if (!hint->inode)
+	hash_in = (char*)&hint->key.k_dir_id;
+    else if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
+	hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
+    else
+	hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
+
+	hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
+}
+
+static int inline this_blocknr_allocation_would_make_it_a_large_file(reiserfs_blocknr_hint_t *hint)
+{
+    return hint->block == hint->th->t_super->u.reiserfs_sb.s_alloc_options.large_file_size;
+}
+
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+static void inline displace_new_packing_locality (reiserfs_blocknr_hint_t *hint)
+{
+    struct key * key = &hint->key;
+
+    hint->th->displace_new_blocks = 0;
+    hint->search_start = hint->beg + keyed_hash((char*)(&key->k_objectid),4) % (hint->end - hint->beg);
+}
+#endif
+
+static int inline old_hashed_relocation (reiserfs_blocknr_hint_t * hint)
+{
+    unsigned long border;
+    unsigned long hash_in;
     
-    return ret;
-  }
+    if (hint->formatted_node || hint->inode == NULL) {
+	return 0;
+    }
 
-				/* else get a new preallocation for the file */
-  reiserfs_discard_prealloc (th, p_s_inode);
-  /* this uses the last preallocated block as the search_start.  discard
-  ** prealloc does not zero out this number.
-  */
-  if (search_start <= p_s_inode->u.reiserfs_i.i_prealloc_block) {
-    search_start = p_s_inode->u.reiserfs_i.i_prealloc_block;
-  }
-  
-  /* doing the compare again forces search_start to be >= the border,
-  ** even if the file already had prealloction done.  This seems extra,
-  ** and should probably be removed
-  */
-  if ( search_start < border ) search_start=border; 
-
-  /* If the disk free space is already below 10% we should 
-  ** start looking for the free blocks from the beginning 
-  ** of the partition, before the border line.
-  */
-  if ( SB_FREE_BLOCKS(th->t_super) <= (SB_BLOCK_COUNT(th->t_super) / 10) ) {
-    search_start=saved_search_start;
-  }
+    hash_in = le32_to_cpu((INODE_PKEY(hint->inode))->k_dir_id);
+    border = hint->beg + (unsigned long) keyed_hash(((char *) (&hash_in)), 4) % (hint->end - hint->beg - 1);
+    if (border > hint->search_start)
+	hint->search_start = border;
 
-  *free_blocknrs = 0;
-  blks = PREALLOCATION_SIZE-1;
-  for (blks_gotten=0; blks_gotten<PREALLOCATION_SIZE; blks_gotten++) {
-    ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 
-				   1/*amount_needed*/, 
-				   0/*for root reserved*/,
-				   1/*for_formatted*/,
-				   (blks_gotten > 0)/*must_be_contiguous*/) ;
-    /* if we didn't find a block this time, adjust blks to reflect
-    ** the actual number of blocks allocated
-    */ 
-    if (ret != CARRY_ON) {
-      blks = blks_gotten > 0 ? (blks_gotten - 1) : 0 ;
-      break ;
+    return 1;
+}
+
+static int inline old_way (reiserfs_blocknr_hint_t * hint)
+{
+    unsigned long border;
+    
+    if (hint->formatted_node || hint->inode == NULL) {
+	return 0;
     }
-    allocated[blks_gotten]= *free_blocknrs;
-#ifdef CONFIG_REISERFS_CHECK
-    if ( (blks_gotten>0) && (allocated[blks_gotten] - allocated[blks_gotten-1]) != 1 ) {
-      /* this should be caught by new_blocknrs now, checking code */
-      reiserfs_warning("yura-1, reiserfs_new_unf_blocknrs2: pre-allocated not contiguous set of blocks!\n") ;
-      reiserfs_free_block(th, allocated[blks_gotten]);
-      blks = blks_gotten-1; 
-      break;
+
+      border = hint->beg + le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id) % (hint->end  - hint->beg);
+    if (border > hint->search_start)
+	hint->search_start = border;
+
+    return 1;
+}
+
+static void inline hundredth_slices (reiserfs_blocknr_hint_t * hint)
+{
+    struct key * key = &hint->key;
+    unsigned long slice_start;
+
+    slice_start = (keyed_hash((char*)(&key->k_dir_id),4) % 100) * (hint->end / 100);
+    if ( slice_start > hint->search_start || slice_start + (hint->end / 100) <= hint->search_start) {
+	hint->search_start = slice_start;
     }
+}
+
+static void inline determine_search_start(reiserfs_blocknr_hint_t *hint,
+					  int amount_needed)
+{
+    struct super_block *s = hint->th->t_super;
+    hint->beg = 0;
+    hint->end = SB_BLOCK_COUNT(s) - 1;
+
+    /* This is former border algorithm. Now with tunable border offset */
+    if (concentrating_formatted_nodes(s))
+	set_border_in_hint(s, hint);
+
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    /* whenever we create a new directory, we displace it.  At first we will
+       hash for location, later we might look for a moderately empty place for
+       it */
+    if (displacing_new_packing_localities(s)
+	&& hint->th->displace_new_blocks) {
+	displace_new_packing_locality(hint);
+
+	/* we do not continue determine_search_start,
+	 * if new packing locality is being displaced */
+	return;
+    }				      
 #endif
-    if (blks_gotten==0) {
-      p_s_inode->u.reiserfs_i.i_prealloc_block = *free_blocknrs;
+
+    /* all persons should feel encouraged to add more special cases here and
+     * test them */
+
+    if (displacing_large_files(s) && !hint->formatted_node
+	&& this_blocknr_allocation_would_make_it_a_large_file(hint)) {
+	displace_large_file(hint);
+	return;
+    }
+
+    /* attempt to copy a feature from old block allocator code */
+    if (TEST_OPTION(old_hashed_relocation, s) && !hint->formatted_node) {
+	old_hashed_relocation(hint);
+    }
+
+    /* if none of our special cases is relevant, use the left neighbor in the
+       tree order of the new node we are allocating for */
+    if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes,s)) {
+	hash_formatted_node(hint);
+	return;
+    } 
+
+    get_left_neighbor(hint);
+
+    /* Mimic old block allocator behaviour, that is if VFS allowed for preallocation,
+       new blocks are displaced based on directory ID. Also, if suggested search_start
+       is less than last preallocated block, we start searching from it, assuming that
+       HDD dataflow is faster in forward direction */
+    if ( TEST_OPTION(old_way, s)) {
+	if (!hint->formatted_node) {
+	    if ( !reiserfs_hashed_relocation(s))
+		old_way(hint);
+	    else if (!reiserfs_no_unhashed_relocation(s))
+		old_hashed_relocation(hint);
+
+	    if ( hint->inode && hint->search_start < hint->inode->u.reiserfs_i.i_prealloc_block)
+		hint->search_start = hint->inode->u.reiserfs_i.i_prealloc_block;
+	}
+	return;
     }
-    search_start = *free_blocknrs; 
-    *free_blocknrs = 0;
-  }
-  p_s_inode->u.reiserfs_i.i_prealloc_count = blks;
-  *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block;
-  p_s_inode->u.reiserfs_i.i_prealloc_block++;
-
-  /* if inode has preallocated blocks, link him to list */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count) {
-    list_add(&p_s_inode->u.reiserfs_i.i_prealloc_list,
-	     &SB_JOURNAL(th->t_super)->j_prealloc_list);
-  } 
-  /* we did actually manage to get 1 block */
-  if (ret != CARRY_ON && allocated[0] > 0) {
-    return CARRY_ON ;
-  }
-  /* NO_MORE_UNUSED_CONTIGUOUS_BLOCKS should only mean something to
-  ** the preallocation code.  The rest of the filesystem asks for a block
-  ** and should either get it, or know the disk is full.  The code
-  ** above should never allow ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCK,
-  ** as it doesn't send for_prealloc = 1 to do_reiserfs_new_blocknrs
-  ** unless it has already successfully allocated at least one block.
-  ** Just in case, we translate into a return value the rest of the
-  ** filesystem can understand.
-  **
-  ** It is an error to change this without making the
-  ** rest of the filesystem understand NO_MORE_UNUSED_CONTIGUOUS_BLOCKS
-  ** If you consider it a bug to return NO_DISK_SPACE here, fix the rest
-  ** of the fs first.
-  */
-  if (ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCKS) {
-#ifdef CONFIG_REISERFS_CHECK
-    reiserfs_warning("reiser-2015: this shouldn't happen, may cause false out of disk space error");
-#endif
-     return NO_DISK_SPACE; 
-  }
-  return ret;
+
+    /* This is an approach proposed by Hans */
+    if ( TEST_OPTION(hundredth_slices, s) && ! (displacing_large_files(s) && !hint->formatted_node)) {
+	hundredth_slices(hint);
+	return;
+    }
+
+    if (TEST_OPTION(old_hashed_relocation, s))
+	old_hashed_relocation(hint);
+    if (TEST_OPTION(new_hashed_relocation, s))
+	new_hashed_relocation(hint);
+    return;
 }
 
-//
-// a portion of this function, was derived from minix or ext2's
-// analog. You should be able to tell which portion by looking at the
-// ext2 code and comparing. 
-static void __discard_prealloc (struct reiserfs_transaction_handle * th,
-				struct inode * inode)
+static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint)
 {
-  unsigned long save = inode->u.reiserfs_i.i_prealloc_block ;
-  while (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    reiserfs_free_prealloc_block(th,inode->u.reiserfs_i.i_prealloc_block);
-    inode->u.reiserfs_i.i_prealloc_block++;
-    inode->u.reiserfs_i.i_prealloc_count --;
-  }
-  inode->u.reiserfs_i.i_prealloc_block = save ; 
-  list_del (&(inode->u.reiserfs_i.i_prealloc_list));
-}
+    /* make minimum size a mount option and benchmark both ways */
+    /* we preallocate blocks only for regular files, specific size */
+    /* benchmark preallocating always and see what happens */
+
+    hint->prealloc_size = 0;
+
+    if (!hint->formatted_node && hint->preallocate) {
+	if (S_ISREG(hint->inode->i_mode)
+	    && hint->inode->i_size >= hint->th->t_super->u.reiserfs_sb.s_alloc_options.preallocmin * hint->inode->i_sb->s_blocksize)
+	    hint->prealloc_size = hint->th->t_super->u.reiserfs_sb.s_alloc_options.preallocsize - 1;
+    }
+    return CARRY_ON;
+}
+
+/* XXX I know it could be merged with upper-level function;
+   but may be result function would be too complex. */
+static inline int allocate_without_wrapping_disk (reiserfs_blocknr_hint_t * hint,
+					 b_blocknr_t * new_blocknrs,
+					 b_blocknr_t start, b_blocknr_t finish,
+					 int amount_needed, int prealloc_size)
+{
+    int rest = amount_needed;
+    int nr_allocated;
+
+    while (rest > 0) {
+	nr_allocated = scan_bitmap (hint->th, &start, finish, 1,
+				    rest + prealloc_size, !hint->formatted_node,
+				    hint->block);
+
+	if (nr_allocated == 0)	/* no new blocks allocated, return */
+	    break;
+	
+	/* fill free_blocknrs array first */
+	while (rest > 0 && nr_allocated > 0) {
+	    * new_blocknrs ++ = start ++;
+	    rest --; nr_allocated --;
+	}
 
+	/* do we have something to fill prealloc. array also ? */
+	if (nr_allocated > 0) {
+	    /* it means prealloc_size was greater that 0 and we do preallocation */
+	    list_add(&INODE_INFO(hint->inode)->i_prealloc_list,
+		     &SB_JOURNAL(hint->th->t_super)->j_prealloc_list);
+	    INODE_INFO(hint->inode)->i_prealloc_block = start;
+	    INODE_INFO(hint->inode)->i_prealloc_count = nr_allocated;
+	    break;
+	}
+    }
 
-void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, 
-				struct inode * inode)
+    return (amount_needed - rest);
+}
+
+static inline int blocknrs_and_prealloc_arrays_from_search_start
+    (reiserfs_blocknr_hint_t *hint, b_blocknr_t *new_blocknrs, int amount_needed)
 {
-#ifdef CONFIG_REISERFS_CHECK
-  if (inode->u.reiserfs_i.i_prealloc_count < 0)
-     reiserfs_warning("zam-4001:" __FUNCTION__ ": inode has negative prealloc blocks count.\n");
-#endif  
-    if (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    __discard_prealloc(th, inode);
-  }
-      }
+    struct super_block *s = hint->th->t_super;
+    b_blocknr_t start = hint->search_start;
+    b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
+    int second_pass = 0;
+    int nr_allocated = 0;
+
+    determine_prealloc_size(hint);
+    while((nr_allocated
+	  += allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish,
+					  amount_needed - nr_allocated, hint->prealloc_size))
+	  < amount_needed) {
+
+	/* not all blocks were successfully allocated yet*/
+	if (second_pass) {	/* it was a second pass; we must free all blocks */
+	    while (nr_allocated --)
+		reiserfs_free_block(hint->th, new_blocknrs[nr_allocated]);
 
-void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
+	    return NO_DISK_SPACE;
+	} else {		/* refine search parameters for next pass */
+	    second_pass = 1;
+	    finish = start;
+	    start = 0;
+	    continue;
+	}
+    }
+    return CARRY_ON;
+}
+
+/* grab new blocknrs from preallocated list */
+/* return amount still needed after using them */
+static int use_preallocated_list_if_available (reiserfs_blocknr_hint_t *hint,
+					       b_blocknr_t *new_blocknrs, int amount_needed)
 {
-  struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
-  struct inode * inode;
-  
-  while (!list_empty(plist)) {
-    inode = list_entry(plist->next, struct inode, u.reiserfs_i.i_prealloc_list);
-#ifdef CONFIG_REISERFS_CHECK
-    if (!inode->u.reiserfs_i.i_prealloc_count) {
-      reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
+    struct inode * inode = hint->inode;
+
+    if (INODE_INFO(inode)->i_prealloc_count > 0) {
+	while (amount_needed) {
+
+	    *new_blocknrs ++ = INODE_INFO(inode)->i_prealloc_block ++;
+	    INODE_INFO(inode)->i_prealloc_count --;
+
+	    amount_needed --;
+
+	    if (INODE_INFO(inode)->i_prealloc_count <= 0) {
+		list_del(&inode->u.reiserfs_i.i_prealloc_list);  
+		break;
+	    }
+	}
     }
-#endif    
-    __discard_prealloc(th, inode);
+    /* return amount still needed after using preallocated blocks */
+    return amount_needed;
+}
+
+int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint,
+			       b_blocknr_t * new_blocknrs, int amount_needed,
+			       int reserved_by_us /* Amount of blocks we have
+						      already reserved */)
+{
+    int initial_amount_needed = amount_needed;
+    int ret;
+
+    /* Check if there is enough space, taking into account reserved space */
+    if ( SB_FREE_BLOCKS(hint->th->t_super) - hint->th->t_super->u.reiserfs_sb.reserved_blocks <
+	 amount_needed - reserved_by_us)
+        return NO_DISK_SPACE;
+    /* should this be if !hint->inode &&  hint->preallocate? */
+    /* do you mean hint->formatted_node can be removed ? - Zam */
+    /* hint->formatted_node cannot be removed because we try to access
+       inode information here, and there is often no inode assotiated with
+       metadata allocations - green */
+
+    if (!hint->formatted_node && hint->preallocate) {
+	amount_needed = use_preallocated_list_if_available
+	    (hint, new_blocknrs, amount_needed);
+	if (amount_needed == 0)	/* all blocknrs we need we got from
+                                   prealloc. list */
+	    return CARRY_ON;
+	new_blocknrs += (initial_amount_needed - amount_needed);
+    }
+
+    /* find search start and save it in hint structure */
+    determine_search_start(hint, amount_needed);
+
+    /* allocation itself; fill new_blocknrs and preallocation arrays */
+    ret = blocknrs_and_prealloc_arrays_from_search_start
+	(hint, new_blocknrs, amount_needed);
+
+    /* we used prealloc. list to fill (partially) new_blocknrs array. If final allocation fails we
+     * need to return blocks back to prealloc. list or just free them. -- Zam (I chose second
+     * variant) */
+
+    if (ret != CARRY_ON) {
+	while (amount_needed ++ < initial_amount_needed) {
+	    reiserfs_free_block(hint->th, *(--new_blocknrs));
+	}
     }
+    return ret;
+}
+
+/* These 2 functions are here to provide blocks reservation to the rest of kernel */
+/* Reserve @blocks amount of blocks in fs pointed by @sb. Caller must make sure
+   there are actually this much blocks on the FS available */
+void reiserfs_claim_blocks_to_be_allocated( 
+				      struct super_block *sb, /* super block of
+							        filesystem where
+								blocks should be
+								reserved */
+				      int blocks /* How much to reserve */
+					  )
+{
+
+    /* Fast case, if reservation is zero - exit immediately. */
+    if ( !blocks )
+	return;
+
+    sb->u.reiserfs_sb.reserved_blocks += blocks;
+}
+
+/* Unreserve @blocks amount of blocks in fs pointed by @sb */
+void reiserfs_release_claimed_blocks( 
+				struct super_block *sb, /* super block of
+							  filesystem where
+							  blocks should be
+							  reserved */
+				int blocks /* How much to unreserve */
+					  )
+{
+
+    /* Fast case, if unreservation is zero - exit immediately. */
+    if ( !blocks )
+	return;
+
+    sb->u.reiserfs_sb.reserved_blocks -= blocks;
+    RFALSE( sb->u.reiserfs_sb.reserved_blocks < 0, "amount of blocks reserved became zero?");
 }
-#endif
diff -urN linux-2.4.20-pre1/fs/reiserfs/buffer2.c linux-2.4.20-pre2/fs/reiserfs/buffer2.c
--- linux-2.4.20-pre1/fs/reiserfs/buffer2.c	Fri Dec 21 09:42:03 2001
+++ linux-2.4.20-pre2/fs/reiserfs/buffer2.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README  
+ *  Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README  
  */
 
 #include <linux/config.h>
diff -urN linux-2.4.20-pre1/fs/reiserfs/dir.c linux-2.4.20-pre2/fs/reiserfs/dir.c
--- linux-2.4.20-pre1/fs/reiserfs/dir.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/dir.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
@@ -106,7 +106,7 @@
 		if (!d_name[d_reclen - 1])
 		    d_reclen = strlen (d_name);
 	
-		if (d_reclen > REISERFS_MAX_NAME_LEN(inode->i_sb->s_blocksize)){
+		if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)){
 		    /* too big to send back to VFS */
 		    continue ;
 		}
@@ -177,7 +177,7 @@
 
 
  end:
-    // FIXME: ext2_readdir does not reset f_pos
+
     filp->f_pos = next_pos;
     pathrelse (&path_to_entry);
     reiserfs_check_path(&path_to_entry) ;
diff -urN linux-2.4.20-pre1/fs/reiserfs/do_balan.c linux-2.4.20-pre2/fs/reiserfs/do_balan.c
--- linux-2.4.20-pre1/fs/reiserfs/do_balan.c	Fri Dec 21 09:42:03 2001
+++ linux-2.4.20-pre2/fs/reiserfs/do_balan.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 /* Now we have all buffers that must be used in balancing of the tree 	*/
diff -urN linux-2.4.20-pre1/fs/reiserfs/file.c linux-2.4.20-pre2/fs/reiserfs/file.c
--- linux-2.4.20-pre1/fs/reiserfs/file.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.20-pre2/fs/reiserfs/file.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 
diff -urN linux-2.4.20-pre1/fs/reiserfs/fix_node.c linux-2.4.20-pre2/fs/reiserfs/fix_node.c
--- linux-2.4.20-pre1/fs/reiserfs/fix_node.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/fix_node.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 /**
@@ -795,8 +795,8 @@
   else /* If we have enough already then there is nothing to do. */
     return CARRY_ON;
 
-  if ( reiserfs_new_blocknrs (p_s_tb->transaction_handle, a_n_blocknrs,
-			      PATH_PLAST_BUFFER(p_s_tb->tb_path)->b_blocknr, n_amount_needed) == NO_DISK_SPACE )
+  if ( reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs,
+                                   n_amount_needed) == NO_DISK_SPACE )
     return NO_DISK_SPACE;
 
   /* for each blocknumber we just got, get a buffer and stick it on FEB */
diff -urN linux-2.4.20-pre1/fs/reiserfs/hashes.c linux-2.4.20-pre2/fs/reiserfs/hashes.c
--- linux-2.4.20-pre1/fs/reiserfs/hashes.c	Fri Oct 12 14:19:28 2001
+++ linux-2.4.20-pre2/fs/reiserfs/hashes.c	Mon Aug 12 16:34:17 2002
@@ -19,6 +19,7 @@
 //
 
 #include <asm/types.h>
+#include <asm/page.h>
 
 
 
@@ -57,7 +58,6 @@
 	u32 pad;
 	int i;
  
-
 	//	assert(len >= 0 && len < 256);
 
 	pad = (u32)len | ((u32)len << 8);
@@ -92,7 +92,7 @@
 	{
 	    	//assert(len < 16);
 		if (len >= 16)
-		    *(int *)0 = 0;
+		    BUG();
 
 		a = (u32)msg[ 0]      |
 		    (u32)msg[ 1] << 8 |
@@ -118,7 +118,7 @@
 	{
 	    	//assert(len < 12);
 		if (len >= 12)
-		    *(int *)0 = 0;
+		    BUG();
 		a = (u32)msg[ 0]      |
 		    (u32)msg[ 1] << 8 |
 		    (u32)msg[ 2] << 16|
@@ -139,7 +139,7 @@
 	{
 	    	//assert(len < 8);
 		if (len >= 8)
-		    *(int *)0 = 0;
+		    BUG();
 		a = (u32)msg[ 0]      |
 		    (u32)msg[ 1] << 8 |
 		    (u32)msg[ 2] << 16|
@@ -156,7 +156,7 @@
 	{
 	    	//assert(len < 4);
 		if (len >= 4)
-		    *(int *)0 = 0;
+		    BUG();
 		a = b = c = d = pad;
 		for(i = 0; i < len; i++)
 		{
@@ -171,7 +171,7 @@
 	return h0^h1;
 }
 
-/* What follows in this file is copyright 2000 by Hans Reiser, and the
+/* What follows in this file is copyright 2000-2002 by Hans Reiser, and the
  * licensing of what follows is governed by reiserfs/README */
 
 u32 yura_hash (const signed char *msg, int len)
diff -urN linux-2.4.20-pre1/fs/reiserfs/ibalance.c linux-2.4.20-pre2/fs/reiserfs/ibalance.c
--- linux-2.4.20-pre1/fs/reiserfs/ibalance.c	Fri Nov  9 14:18:25 2001
+++ linux-2.4.20-pre2/fs/reiserfs/ibalance.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
diff -urN linux-2.4.20-pre1/fs/reiserfs/inode.c linux-2.4.20-pre2/fs/reiserfs/inode.c
--- linux-2.4.20-pre1/fs/reiserfs/inode.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/inode.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
@@ -19,10 +19,7 @@
 
 static int reiserfs_get_block (struct inode * inode, long block,
 			       struct buffer_head * bh_result, int create);
-//
-// initially this function was derived from minix or ext2's analog and
-// evolved as the prototype did
-//
+
 void reiserfs_delete_inode (struct inode * inode)
 {
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2; 
@@ -111,8 +108,7 @@
 }
 
 //
-// FIXME: we might cache recently accessed indirect item (or at least
-// first 15 pointers just like ext2 does
+// FIXME: we might cache recently accessed indirect item
 
 // Ugh.  Not too eager for that....
 //  I cut the code until such time as I see a convincing argument (benchmark).
@@ -159,33 +155,6 @@
     }
 }
 
-
-
-
-/* we need to allocate a block for new unformatted node.  Try to figure out
-   what point in bitmap reiserfs_new_blocknrs should start from. */
-static b_blocknr_t find_tag (struct buffer_head * bh, struct item_head * ih,
-			     __u32 * item, int pos_in_item)
-{
-  __u32 block ;
-  if (!is_indirect_le_ih (ih))
-	 /* something more complicated could be here */
-	 return bh->b_blocknr;
-
-  /* for indirect item: go to left and look for the first non-hole entry in
-	  the indirect item */
-  if (pos_in_item == I_UNFM_NUM (ih))
-	 pos_in_item --;
-  while (pos_in_item >= 0) {
-	 block = get_block_num(item, pos_in_item) ;
-	 if (block)
-		return block ;
-	 pos_in_item --;
-  }
-  return bh->b_blocknr;
-}
-
-
 /* reiserfs_get_block does not need to allocate a block only if it has been
    done already or non-hole position has been found in the indirect item */
 static inline int allocation_needed (int retval, b_blocknr_t allocated, 
@@ -348,10 +317,10 @@
     ** kmap schedules
     */
     if (!p) {
-    p = (char *)kmap(bh_result->b_page) ;
-    if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
-        goto research;
-    }
+	p = (char *)kmap(bh_result->b_page) ;
+	if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
+	    goto research;
+	}
     }
     p += offset ;
     memset (p, 0, inode->i_sb->s_blocksize);
@@ -531,29 +500,24 @@
 }
 
 static inline int _allocate_block(struct reiserfs_transaction_handle *th,
+			   long block,
                            struct inode *inode, 
 			   b_blocknr_t *allocated_block_nr, 
-			   unsigned long tag,
+			   struct path * path,
 			   int flags) {
   
 #ifdef REISERFS_PREALLOCATE
     if (!(flags & GET_BLOCK_NO_ISEM)) {
-        return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, tag);
+        return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, path, block);
     }
 #endif
-    return reiserfs_new_unf_blocknrs (th, allocated_block_nr, tag);
+    return reiserfs_new_unf_blocknrs (th, allocated_block_nr, path, block);
 }
-//
-// initially this function was derived from ext2's analog and evolved
-// as the prototype did.  You'll need to look at the ext2 version to
-// determine which parts are derivative, if any, understanding that
-// there are only so many ways to code to a given interface.
-//
+
 static int reiserfs_get_block (struct inode * inode, long block,
 			       struct buffer_head * bh_result, int create)
 {
     int repeat, retval;
-    unsigned long tag;
     b_blocknr_t allocated_block_nr = 0;// b_blocknr_t is unsigned long
     INITIALIZE_PATH(path);
     int pos_in_item;
@@ -632,7 +596,6 @@
 
     if (allocation_needed (retval, allocated_block_nr, ih, item, pos_in_item)) {
 	/* we have to allocate block for the unformatted node */
-	tag = find_tag (bh, ih, item, pos_in_item);
 	if (!transaction_started) {
 	    pathrelse(&path) ;
 	    journal_begin(&th, inode->i_sb, jbegin_count) ;
@@ -641,7 +604,7 @@
 	    goto research ;
 	}
 
-	repeat = _allocate_block(&th, inode, &allocated_block_nr, tag, create);
+	repeat = _allocate_block(&th, block, inode, &allocated_block_nr, &path, create);
 
 	if (repeat == NO_DISK_SPACE) {
 	    /* restart the transaction to give the journal a chance to free
@@ -649,7 +612,7 @@
 	    ** research if we succeed on the second try
 	    */
 	    restart_transaction(&th, inode, &path) ; 
-	    repeat = _allocate_block(&th, inode,&allocated_block_nr,tag,create);
+	    repeat = _allocate_block(&th, block, inode, &allocated_block_nr, NULL, create);
 
 	    if (repeat != NO_DISK_SPACE) {
 		goto research ;
@@ -800,10 +763,10 @@
 	    add_to_flushlist(inode, unbh) ;
 
 	    /* mark it dirty now to prevent commit_write from adding
-	    ** this buffer to the inode's dirty buffer list
-	    */
+	     ** this buffer to the inode's dirty buffer list
+	     */
 	    __mark_buffer_dirty(unbh) ;
-		  
+
 	    //inode->i_blocks += inode->i_sb->s_blocksize / 512;
 	    //mark_tail_converted (inode);
 	} else {
@@ -1137,15 +1100,17 @@
     return;
 }
 
-void reiserfs_read_inode(struct inode *inode) {
-    make_bad_inode(inode) ;
+/* We need to clear inode key in private part of inode to avoid races between
+   blocking iput, knfsd and file deletion with creating of safelinks.*/
+static void reiserfs_make_bad_inode(struct inode *inode) {
+    memset(INODE_PKEY(inode), 0, KEY_SIZE);
+    make_bad_inode(inode);
 }
 
+void reiserfs_read_inode(struct inode *inode) {
+    reiserfs_make_bad_inode(inode) ;
+}
 
-//
-// initially this function was derived from minix or ext2's analog and
-// evolved as the prototype did
-//
 
 /* looks for stat data in the tree, and fills up the fields of in-core
    inode stat data fields */
@@ -1158,7 +1123,7 @@
     int retval;
 
     if (!p) {
-	make_bad_inode(inode) ;
+	reiserfs_make_bad_inode(inode) ;
 	return;
     }
 
@@ -1178,13 +1143,13 @@
 	reiserfs_warning ("vs-13070: reiserfs_read_inode2: "
                     "i/o failure occurred trying to find stat data of %K\n",
                     &key);
-	make_bad_inode(inode) ;
+	reiserfs_make_bad_inode(inode) ;
 	return;
     }
     if (retval != ITEM_FOUND) {
 	/* a stale NFS handle can trigger this without it being an error */
 	pathrelse (&path_to_sd);
-	make_bad_inode(inode) ;
+	reiserfs_make_bad_inode(inode) ;
 	inode->i_nlink = 0;
 	return;
     }
@@ -1211,7 +1176,7 @@
 			      "dead inode read from disk %K. "
 			      "This is likely to be race with knfsd. Ignore\n", 
 			      &key );
-	    make_bad_inode( inode );
+	    reiserfs_make_bad_inode( inode );
     }
 
     reiserfs_check_path(&path_to_sd) ; /* init inode should be relsing */
@@ -1368,10 +1333,6 @@
 }
 
 
-//
-// initially this function was derived from minix or ext2's analog and
-// evolved as the prototype did
-//
 /* looks for stat data, then copies fields to it, marks the buffer
    containing stat data as dirty */
 /* reiserfs inodes are never really dirty, since the dirty inode call
@@ -1504,7 +1465,7 @@
    directory) or reiserfs_new_symlink (to insert symlink body if new
    object is symlink) or nothing (if new object is regular file) */
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
-				   const struct inode * dir, int mode, 
+				   struct inode * dir, int mode, 
 				   const char * symname, 
 				   int i_size, /* 0 for regular, EMTRY_DIR_SIZE for dirs,
 						  strlen (symname) for symlinks)*/
@@ -1628,6 +1589,10 @@
 	set_inode_sd_version (inode, STAT_DATA_V2);
     
     /* insert the stat data into the tree */
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    if (dir->u.reiserfs_i.new_packing_locality)
+	th->displace_new_blocks = 1;
+#endif
     retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
     if (retval) {
 	iput (inode);
@@ -1636,6 +1601,10 @@
 	return NULL;
     }
 
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    if (!th->displace_new_blocks)
+	dir->u.reiserfs_i.new_packing_locality = 0;
+#endif
     if (S_ISDIR(mode)) {
 	/* insert item with "." and ".." */
 	retval = reiserfs_new_directory (th, &ih, &path_to_key, dir);
@@ -1793,16 +1762,16 @@
     reiserfs_update_inode_transaction(p_s_inode) ;
     windex = push_journal_writer("reiserfs_vfs_truncate_file") ;
     if (update_timestamps)
-           /* we are doing real truncate: if the system crashes before the last
-              transaction of truncating gets committed - on reboot the file
-              either appears truncated properly or not truncated at all */
-           add_save_link (&th, p_s_inode, 1);
+	    /* we are doing real truncate: if the system crashes before the last
+	       transaction of truncating gets committed - on reboot the file
+	       either appears truncated properly or not truncated at all */
+	add_save_link (&th, p_s_inode, 1);
     reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
     pop_journal_writer(windex) ;
     journal_end(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
 
     if (update_timestamps)
-       remove_save_link (p_s_inode, 1/* truncate */);
+	remove_save_link (p_s_inode, 1/* truncate */);
 
     if (page) {
         length = offset & (blocksize - 1) ;
@@ -2042,18 +2011,13 @@
     return error ;
 }
 
-//
-// this is exactly what 2.3.99-pre9's ext2_readpage is
-//
+
 static int reiserfs_readpage (struct file *f, struct page * page)
 {
     return block_read_full_page (page, reiserfs_get_block);
 }
 
 
-//
-// modified from ext2_writepage is
-//
 static int reiserfs_writepage (struct page * page)
 {
     struct inode *inode = page->mapping->host ;
@@ -2062,9 +2026,6 @@
 }
 
 
-//
-// from ext2_prepare_write, but modified
-//
 int reiserfs_prepare_write(struct file *f, struct page *page, 
 			   unsigned from, unsigned to) {
     struct inode *inode = page->mapping->host ;
@@ -2074,9 +2035,6 @@
 }
 
 
-//
-// this is exactly what 2.3.99-pre9's ext2_bmap is
-//
 static int reiserfs_aop_bmap(struct address_space *as, long block) {
   return generic_block_bmap(as, block, reiserfs_bmap) ;
 }
@@ -2095,13 +2053,13 @@
     */
     if (pos > inode->i_size) {
 	struct reiserfs_transaction_handle th ;
-	lock_kernel() ;
+	lock_kernel();
 	journal_begin(&th, inode->i_sb, 1) ;
 	reiserfs_update_inode_transaction(inode) ;
 	inode->i_size = pos ;
 	reiserfs_update_sd(&th, inode) ;
 	journal_end(&th, inode->i_sb, 1) ;
-	unlock_kernel() ;
+	unlock_kernel();
     }
  
     ret = generic_commit_write(f, page, from, to) ;
diff -urN linux-2.4.20-pre1/fs/reiserfs/ioctl.c linux-2.4.20-pre2/fs/reiserfs/ioctl.c
--- linux-2.4.20-pre1/fs/reiserfs/ioctl.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/ioctl.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/fs.h>
@@ -31,8 +31,12 @@
 				return 0;
 		} else
 			return -ENOTTY;
-	/* following two cases are taken from fs/ext2/ioctl.c by Remy
-	   Card (card@masi.ibp.fr) */
+	/*
+	 * Following {G,S}ETFLAGS, and {G,S}ETVERSION are providing ext2
+	 * binary compatible interface (used by lsattr(1), and chattr(1)) and
+	 * are * thus conceptually similar to appropriate pieces of
+	 * fs/ext2/ioctl.c
+	 */
 	case REISERFS_IOC_GETFLAGS:
 		flags = inode -> u.reiserfs_i.i_attrs;
 		i_attrs_to_sd_attrs( inode, ( __u16 * ) &flags );
diff -urN linux-2.4.20-pre1/fs/reiserfs/item_ops.c linux-2.4.20-pre2/fs/reiserfs/item_ops.c
--- linux-2.4.20-pre1/fs/reiserfs/item_ops.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/item_ops.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/sched.h>
diff -urN linux-2.4.20-pre1/fs/reiserfs/journal.c linux-2.4.20-pre2/fs/reiserfs/journal.c
--- linux-2.4.20-pre1/fs/reiserfs/journal.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/journal.c	Mon Aug 12 16:34:17 2002
@@ -191,7 +191,7 @@
   if (!jb->bitmaps[bmap_nr]) {
     jb->bitmaps[bmap_nr] = get_bitmap_node(p_s_sb) ;
   }
-  set_bit(bit_nr, jb->bitmaps[bmap_nr]->data) ;
+  set_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data) ;
   return 0 ;
 }
 
@@ -375,7 +375,7 @@
 /* buffer is in current transaction */
 inline int buffer_journaled(const struct buffer_head *bh) {
   if (bh)
-    return test_bit(BH_JDirty, ( struct buffer_head * ) &bh->b_state) ;
+    return test_bit(BH_JDirty, &((struct buffer_head *)bh)->b_state) ;
   else
     return 0 ;
 }
@@ -385,7 +385,7 @@
 */ 
 inline int buffer_journal_new(const struct buffer_head *bh) {
   if (bh) 
-    return test_bit(BH_JNew, ( struct buffer_head * )&bh->b_state) ;
+    return test_bit(BH_JNew, &((struct buffer_head *)bh)->b_state) ;
   else
     return 0 ;
 }
@@ -508,14 +508,12 @@
 **
 */
 int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, 
-                        unsigned long bl, int size, int search_all, 
-			unsigned long *next_zero_bit) {
+                        int bmap_nr, int bit_nr, int size, int search_all, 
+			unsigned int *next_zero_bit) {
   struct reiserfs_journal_cnode *cn ;
   struct reiserfs_list_bitmap *jb ;
   int i ;
-  int bmap_nr = bl / (p_s_sb->s_blocksize << 3) ;
-  int bit_nr = bl % (p_s_sb->s_blocksize << 3) ;
-  int tmp_bit ;
+  unsigned long bl;
 
   *next_zero_bit = 0 ; /* always start this at zero. */
 
@@ -534,16 +532,16 @@
       PROC_INFO_INC( p_s_sb, journal.in_journal_bitmap );
       jb = SB_JOURNAL(p_s_sb)->j_list_bitmap + i ;
       if (jb->journal_list && jb->bitmaps[bmap_nr] &&
-          test_bit(bit_nr, jb->bitmaps[bmap_nr]->data)) {
-	tmp_bit = find_next_zero_bit((unsigned long *)
+          test_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data)) {
+	*next_zero_bit = find_next_zero_bit((unsigned long *)
 	                             (jb->bitmaps[bmap_nr]->data),
 	                             p_s_sb->s_blocksize << 3, bit_nr+1) ; 
-	*next_zero_bit = bmap_nr * (p_s_sb->s_blocksize << 3) + tmp_bit ;
 	return 1 ;
       }
     }
   }
 
+  bl = bmap_nr * (p_s_sb->s_blocksize << 3) + bit_nr;
   /* is it in any old transactions? */
   if (search_all && (cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, dev,bl,size))) {
     return 1; 
@@ -1811,7 +1809,8 @@
   jl = SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex ;
 
   flush_commit_list(ct->p_s_sb, SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex, 1) ; 
-  if (jl->j_len > 0 && atomic_read(&(jl->j_nonzerolen)) > 0 && 
+
+  if (jl->j_len > 0 && atomic_read(&(jl->j_nonzerolen)) > 0 &&
       atomic_read(&(jl->j_commit_left)) == 0) {
     kupdate_one_transaction(ct->p_s_sb, jl) ;
   }
diff -urN linux-2.4.20-pre1/fs/reiserfs/lbalance.c linux-2.4.20-pre2/fs/reiserfs/lbalance.c
--- linux-2.4.20-pre1/fs/reiserfs/lbalance.c	Fri Dec 21 09:42:03 2001
+++ linux-2.4.20-pre2/fs/reiserfs/lbalance.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
diff -urN linux-2.4.20-pre1/fs/reiserfs/namei.c linux-2.4.20-pre2/fs/reiserfs/namei.c
--- linux-2.4.20-pre1/fs/reiserfs/namei.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/namei.c	Mon Aug 12 16:34:17 2002
@@ -1,14 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
- *
- * Trivial changes by Alan Cox to remove EHASHCOLLISION for compatibility
- *
- * Trivial Changes:
- * Rights granted to Hans Reiser to redistribute under other terms providing
- * he accepts all liability including but not limited to patent, fitness
- * for purpose, and direct or indirect claims arising from failure to perform.
- *
- * NO WARRANTY
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
@@ -195,13 +186,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_match (struct reiserfs_dir_entry * de, 
 			   const char * name, int namelen)
 {
@@ -248,7 +232,7 @@
    
 	/* mark, that this generation number is used */
 	if (de->de_gen_number_bit_string)
-	    set_bit (GET_GENERATION_NUMBER (deh_offset (deh)), de->de_gen_number_bit_string);
+	    set_bit (GET_GENERATION_NUMBER (deh_offset (deh)), (unsigned long *)de->de_gen_number_bit_string);
 
 	// calculate pointer to name and namelen
 	de->de_entry_num = i;
@@ -284,13 +268,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 // may return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND
 // FIXME: should add something like IOERROR
 static int reiserfs_find_entry (struct inode * dir, const char * name, int namelen, 
@@ -300,7 +277,7 @@
     int retval;
 
 
-    if (namelen > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize))
+    if (namelen > REISERFS_MAX_NAME (dir->i_sb->s_blocksize))
 	return NAME_NOT_FOUND;
 
     /* we will search for this key in the tree */
@@ -310,7 +287,7 @@
     while (1) {
 	retval = search_by_entry_key (dir->i_sb, &key_to_search, path_to_entry, de);
 	if (retval == IO_ERROR) {
-	    reiserfs_warning ("zam-7001: io error in " __FUNCTION__ "\n");
+	    reiserfs_warning ("zam-7001: io error in %s\n", __FUNCTION__);
 	    return IO_ERROR;
 	}
 
@@ -330,13 +307,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry)
 {
     int retval;
@@ -346,7 +316,7 @@
 
     reiserfs_check_lock_depth("lookup") ;
 
-    if (dentry->d_name.len > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize))
+    if (REISERFS_MAX_NAME (dir->i_sb->s_blocksize) < dentry->d_name.len)
 	return ERR_PTR(-ENAMETOOLONG);
 
     de.de_gen_number_bit_string = 0;
@@ -366,14 +336,6 @@
     return NULL;
 }
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
-
 /* add entry to the directory (entry can be hidden). 
 
 insert definition of when hidden directories are used here -Hans
@@ -401,7 +363,7 @@
     if (!namelen)
 	return -EINVAL;
 
-    if (namelen > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize))
+    if (namelen > REISERFS_MAX_NAME (dir->i_sb->s_blocksize))
 	return -ENAMETOOLONG;
 
     /* each entry has unique key. compose it */
@@ -417,7 +379,7 @@
     } else
 	buffer = small_buf;
 
-    paste_size = (old_format_only (dir->i_sb)) ? (DEH_SIZE + namelen) : buflen;
+    paste_size = (get_inode_sd_version (dir) == STAT_DATA_V1) ? (DEH_SIZE + namelen) : buflen;
 
     /* fill buffer : directory entry head, name[, dir objectid | , stat data | ,stat data, dir objectid ] */
     deh = (struct reiserfs_de_head *)buffer;
@@ -451,21 +413,36 @@
 	}
 
         if (retval != NAME_FOUND) {
-	    reiserfs_warning ("zam-7002:" __FUNCTION__ ": \"reiserfs_find_entry\" has returned"
-                              " unexpected value (%d)\n", retval);
+	    reiserfs_warning ("zam-7002:%s: \"reiserfs_find_entry\" has returned"
+                              " unexpected value (%d)\n", __FUNCTION__, retval);
        }
 
 	return -EEXIST;
     }
 
-    gen_number = find_first_zero_bit (bit_string, MAX_GENERATION_NUMBER + 1);
+    gen_number = find_first_zero_bit ((unsigned long *)bit_string, MAX_GENERATION_NUMBER + 1);
     if (gen_number > MAX_GENERATION_NUMBER) {
       /* there is no free generation number */
       reiserfs_warning ("reiserfs_add_entry: Congratulations! we have got hash function screwed up\n");
       if (buffer != small_buf)
           reiserfs_kfree (buffer, buflen, dir->i_sb);
       pathrelse (&path);
+/*
+ * Trivial changes by Alan Cox to remove EHASHCOLLISION for compatibility
+ *
+ * Trivial Changes:
+ * Rights granted to Hans Reiser to redistribute under other terms providing
+ * he accepts all liability including but not limited to patent, fitness
+ * for purpose, and direct or indirect claims arising from failure to perform.
+ *
+ * NO WARRANTY
+ * This is one of two lines that this fix consist of.
+ */
       return -EBUSY;
+      /* I think it was better to have an error code with a name that says
+	 what it means, but I choose not to fight over it.  Persons porting to
+	 other operating systems should consider keeping it as it was
+	 (return -EHASHCOLLISION;). -Hans */
     }
     /* adjust offset of directory enrty */
     put_deh_offset(deh, SET_GENERATION_NUMBER(deh_offset(deh), gen_number));
@@ -482,7 +459,12 @@
 	    if (buffer != small_buf)
 		reiserfs_kfree (buffer, buflen, dir->i_sb);
 	    pathrelse (&path);
+	    /* Following line is 2nd line touched by Alan Cox' trivial fix */
 	    return -EBUSY;
+      /* I think it was better to have an error code with a name that says
+	 what it means, but I choose not to fight over it.  Persons porting to
+	 other operating systems should consider keeping it as it was
+	 (return -EHASHCOLLISION;). -Hans */
 	}
     }
   
@@ -507,13 +489,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode)
 {
     int retval;
@@ -523,8 +498,7 @@
     struct reiserfs_transaction_handle th ;
 
 
-    inode = new_inode(dir->i_sb) ;
-    if (!inode) {
+    if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
     journal_begin(&th, dir->i_sb, jbegin_count) ;
@@ -563,13 +537,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
 {
     int retval;
@@ -578,8 +545,7 @@
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
-    inode = new_inode(dir->i_sb) ;
-    if (!inode) {
+    if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
     journal_begin(&th, dir->i_sb, jbegin_count) ;
@@ -618,13 +584,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
 {
     int retval;
@@ -633,8 +592,7 @@
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
-    inode = new_inode(dir->i_sb) ;
-    if (!inode) {
+    if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
     journal_begin(&th, dir->i_sb, jbegin_count) ;
@@ -645,6 +603,10 @@
     */
     INC_DIR_INODE_NLINK(dir)
 
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    /* set flag that new packing locality created and new blocks for the content     * of that directory are not displaced yet */
+    dir->u.reiserfs_i.new_packing_locality = 1;
+#endif
     mode = S_IFDIR | mode;
     inode = reiserfs_new_inode (&th, dir, mode, 0/*symlink*/,
 				old_format_only (dir->i_sb) ? EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
@@ -697,13 +659,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
 {
     int retval;
@@ -784,13 +739,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
 {
     int retval;
@@ -866,14 +814,7 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
-static int reiserfs_symlink (struct inode * dir, struct dentry * dentry, const char * symname)
+static int reiserfs_symlink (struct inode * parent_dir, struct dentry * dentry, const char * symname)
 {
     int retval;
     struct inode * inode;
@@ -884,18 +825,17 @@
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
 
-    inode = new_inode(dir->i_sb) ;
-    if (!inode) {
-	return -ENOMEM ;
+    if (!(inode = new_inode(parent_dir->i_sb))) {
+  	return -ENOMEM ;
     }
 
     item_len = ROUND_UP (strlen (symname));
-    if (item_len > MAX_DIRECT_ITEM_LEN (dir->i_sb->s_blocksize)) {
+    if (item_len > MAX_DIRECT_ITEM_LEN (parent_dir->i_sb->s_blocksize)) {
 	iput(inode) ;
 	return -ENAMETOOLONG;
     }
   
-    name = reiserfs_kmalloc (item_len, GFP_NOFS, dir->i_sb);
+    name = reiserfs_kmalloc (item_len, GFP_NOFS, parent_dir->i_sb);
     if (!name) {
 	iput(inode) ;
 	return -ENOMEM;
@@ -903,20 +843,20 @@
     memcpy (name, symname, strlen (symname));
     padd_item (name, item_len, strlen (symname));
 
-    journal_begin(&th, dir->i_sb, jbegin_count) ;
+    journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
     windex = push_journal_writer("reiserfs_symlink") ;
 
-    inode = reiserfs_new_inode (&th, dir, S_IFLNK | S_IRWXUGO, name, strlen (symname), dentry,
+    inode = reiserfs_new_inode (&th, parent_dir, S_IFLNK | S_IRWXUGO, name, strlen (symname), dentry,
 				inode, &retval);
-    reiserfs_kfree (name, item_len, dir->i_sb);
+    reiserfs_kfree (name, item_len, parent_dir->i_sb);
     if (inode == 0) { /* reiserfs_new_inode iputs for us */
 	pop_journal_writer(windex) ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
+	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
 	return retval;
     }
 
     reiserfs_update_inode_transaction(inode) ;
-    reiserfs_update_inode_transaction(dir) ;
+    reiserfs_update_inode_transaction(parent_dir) ;
 
     inode->i_op = &page_symlink_inode_operations;
     inode->i_mapping->a_ops = &reiserfs_address_space_operations;
@@ -925,31 +865,24 @@
     //
     //reiserfs_update_sd (&th, inode, READ_BLOCKS);
 
-    retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
+    retval = reiserfs_add_entry (&th, parent_dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
 	pop_journal_writer(windex) ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
+	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
 	iput (inode);
 	return retval;
     }
 
     d_instantiate(dentry, inode);
     pop_journal_writer(windex) ;
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    journal_end(&th, parent_dir->i_sb, jbegin_count) ;
     return 0;
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct dentry * dentry)
 {
     int retval;
@@ -957,6 +890,7 @@
     int windex ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
+    time_t ctime;
 
 
     if (S_ISDIR(inode->i_mode))
@@ -984,7 +918,8 @@
     }
 
     inode->i_nlink++;
-    inode->i_ctime = CURRENT_TIME;
+    ctime = CURRENT_TIME;
+    inode->i_ctime = ctime;
     reiserfs_update_sd (&th, inode);
 
     atomic_inc(&inode->i_count) ;
@@ -1037,14 +972,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
-
 /* 
  * process, that is going to call fix_nodes/do_balance must hold only
  * one path. If it holds 2 or more, it can get into endless waiting in
@@ -1059,10 +986,12 @@
     INITIALIZE_PATH (dot_dot_entry_path);
     struct item_head new_entry_ih, old_entry_ih, dot_dot_ih ;
     struct reiserfs_dir_entry old_de, new_de, dot_dot_de;
-    struct inode * old_inode, * new_inode;
+    struct inode * old_inode, * new_dentry_inode;
     int windex ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count ; 
+    umode_t old_inode_mode;
+    time_t ctime;
 
 
     /* two balancings: old name removal, new name insertion or "save" link,
@@ -1071,7 +1000,7 @@
     jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 3;
 
     old_inode = old_dentry->d_inode;
-    new_inode = new_dentry->d_inode;
+    new_dentry_inode = new_dentry->d_inode;
 
     // make sure, that oldname still exists and points to an object we
     // are going to rename
@@ -1086,13 +1015,14 @@
 	return -ENOENT;
     }
 
-    if (S_ISDIR(old_inode->i_mode)) {
+    old_inode_mode = old_inode->i_mode;
+    if (S_ISDIR(old_inode_mode)) {
 	// make sure, that directory being renamed has correct ".." 
 	// and that its new parent directory has not too many links
 	// already
 
-	if (new_inode) {
-	    if (!reiserfs_empty_dir(new_inode)) {
+	if (new_dentry_inode) {
+	    if (!reiserfs_empty_dir(new_dentry_inode)) {
 		return -ENOTEMPTY;
 	    }
 	}
@@ -1118,9 +1048,7 @@
     retval = reiserfs_add_entry (&th, new_dir, new_dentry->d_name.name, new_dentry->d_name.len, 
 				 old_inode, 0);
     if (retval == -EEXIST) {
-	// FIXME: is it possible, that new_inode == 0 here? If yes, it
-	// is not clear how does ext2 handle that
-	if (!new_inode) {
+	if (!new_dentry_inode) {
 	    reiserfs_panic (old_dir->i_sb,
 			    "vs-7050: new entry is found, new inode == 0\n");
 	}
@@ -1138,8 +1066,8 @@
     */
     reiserfs_update_inode_transaction(old_inode) ;
 
-    if (new_inode) 
-	reiserfs_update_inode_transaction(new_inode) ;
+    if (new_dentry_inode) 
+	reiserfs_update_inode_transaction(new_dentry_inode) ;
 
     while (1) {
 	// look for old name using corresponding entry key (found by reiserfs_find_entry)
@@ -1186,18 +1114,18 @@
 	if (item_moved(&new_entry_ih, &new_entry_path) ||
 	    !entry_points_to_object(new_dentry->d_name.name, 
 	                            new_dentry->d_name.len,
-				    &new_de, new_inode) ||
+				    &new_de, new_dentry_inode) ||
 	    item_moved(&old_entry_ih, &old_entry_path) || 
 	    !entry_points_to_object (old_dentry->d_name.name, 
 	                             old_dentry->d_name.len,
 				     &old_de, old_inode)) {
 	    reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
 	    reiserfs_restore_prepared_buffer (old_inode->i_sb, old_de.de_bh);
-	    if (S_ISDIR(old_inode->i_mode))
+	    if (S_ISDIR(old_inode_mode))
 		reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh);
 	    continue;
 	}
-	if (S_ISDIR(old_inode->i_mode)) {
+	if (S_ISDIR(old_inode_mode)) {
 	    if ( item_moved(&dot_dot_ih, &dot_dot_entry_path) ||
 		 !entry_points_to_object ( "..", 2, &dot_dot_de, old_dir) ) {
 		reiserfs_restore_prepared_buffer (old_inode->i_sb, old_de.de_bh);
@@ -1208,7 +1136,7 @@
 	}
 
 
-	RFALSE( S_ISDIR(old_inode->i_mode) && 
+	RFALSE( S_ISDIR(old_inode_mode) && 
 		!reiserfs_buffer_prepared(dot_dot_de.de_bh), "" );
 
 	break;
@@ -1226,22 +1154,23 @@
     old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
     new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
 
-    if (new_inode) {
+    if (new_dentry_inode) {
 	// adjust link number of the victim
-	if (S_ISDIR(new_inode->i_mode)) {
-	    new_inode->i_nlink  = 0;
+	if (S_ISDIR(new_dentry_inode->i_mode)) {
+	    new_dentry_inode->i_nlink  = 0;
 	} else {
-	    new_inode->i_nlink--;
+	    new_dentry_inode->i_nlink--;
 	}
-	new_inode->i_ctime = CURRENT_TIME;
+	ctime = CURRENT_TIME;
+	new_dentry_inode->i_ctime = ctime;
     }
 
-    if (S_ISDIR(old_inode->i_mode)) {
+    if (S_ISDIR(old_inode_mode)) {
 	// adjust ".." of renamed directory 
 	set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir));
 	journal_mark_dirty (&th, new_dir->i_sb, dot_dot_de.de_bh);
 	
-        if (!new_inode)
+        if (!new_dentry_inode)
 	    /* there (in new_dir) was no directory, so it got new link
 	       (".."  of renamed directory) */
 	    INC_DIR_INODE_NLINK(new_dir);
@@ -1266,10 +1195,10 @@
     reiserfs_update_sd (&th, old_dir);
     reiserfs_update_sd (&th, new_dir);
 
-    if (new_inode) {
-	if (new_inode->i_nlink == 0)
-	    add_save_link (&th, new_inode, 0/* not truncate */);
-	reiserfs_update_sd (&th, new_inode);
+    if (new_dentry_inode) {
+	if (new_dentry_inode->i_nlink == 0)
+	    add_save_link (&th, new_dentry_inode, 0/* not truncate */);
+	reiserfs_update_sd (&th, new_dentry_inode);
     }
 
     pop_journal_writer(windex) ;
diff -urN linux-2.4.20-pre1/fs/reiserfs/objectid.c linux-2.4.20-pre2/fs/reiserfs/objectid.c
--- linux-2.4.20-pre1/fs/reiserfs/objectid.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/objectid.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
diff -urN linux-2.4.20-pre1/fs/reiserfs/prints.c linux-2.4.20-pre2/fs/reiserfs/prints.c
--- linux-2.4.20-pre1/fs/reiserfs/prints.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/prints.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
diff -urN linux-2.4.20-pre1/fs/reiserfs/procfs.c linux-2.4.20-pre2/fs/reiserfs/procfs.c
--- linux-2.4.20-pre1/fs/reiserfs/procfs.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/procfs.c	Mon Aug 12 16:34:17 2002
@@ -1,9 +1,7 @@
 /* -*- linux-c -*- */
-
 /* fs/reiserfs/procfs.c */
-
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 /* proc info support a la one created by Sizif@Botik.RU for PGC */
@@ -120,7 +118,7 @@
 #define SF( x ) ( r -> x )
 #define SFP( x ) SF( s_proc_info_data.x )
 #define SFPL( x ) SFP( x[ level ] )
-#define SFPF( x ) SFP( find_forward.x )
+#define SFPF( x ) SFP( scan_bitmap.x )
 #define SFPJ( x ) SFP( journal.x )
 
 #define D2C( x ) le16_to_cpu( x )
@@ -191,7 +189,7 @@
 			reiserfs_no_unhashed_relocation( sb ) ? "NO_UNHASHED_RELOCATION " : "",
 			reiserfs_hashed_relocation( sb ) ? "UNHASHED_RELOCATION " : "",
 			reiserfs_test4( sb ) ? "TEST4 " : "",
-			dont_have_tails( sb ) ? "NO_TAILS " : "TAILS ",
+			have_large_tails( sb ) ? "TAILS " : have_small_tails(sb)?"SMALL_TAILS ":"NO_TAILS ",
 			replay_only( sb ) ? "REPLAY_ONLY " : "",
 			reiserfs_dont_log( sb ) ? "DONT_LOG " : "LOG ",
 			convert_reiserfs( sb ) ? "CONV " : "",
@@ -321,27 +319,30 @@
 	r = &sb->u.reiserfs_sb;
 
 	len += sprintf( &buffer[ len ], "free_block: %lu\n"
-			"find_forward:"
-			"         wait"
-			"         bmap"
-			"        retry"
-			" journal_hint"
-			"  journal_out"
+			"  scan_bitmap:"
+			"          wait"
+			"          bmap"
+			"         retry"
+			"        stolen"
+			"  journal_hint"
+			"journal_nohint"
 			"\n"
-			" %12lu"
-			" %12lu"
-			" %12lu"
-			" %12lu"
-			" %12lu"
-			" %12lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
+			" %14lu"
 			"\n",
 			SFP( free_block ),
 			SFPF( call ), 
 			SFPF( wait ), 
 			SFPF( bmap ),
 			SFPF( retry ),
+			SFPF( stolen ),
 			SFPF( in_journal_hint ),
-			SFPF( in_journal_out ) );
+			SFPF( in_journal_nohint ) );
 
 	procinfo_epilogue( sb );
 	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
diff -urN linux-2.4.20-pre1/fs/reiserfs/resize.c linux-2.4.20-pre2/fs/reiserfs/resize.c
--- linux-2.4.20-pre1/fs/reiserfs/resize.c	Mon Feb 25 11:38:09 2002
+++ linux-2.4.20-pre2/fs/reiserfs/resize.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /* 
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
  
 /* 
@@ -19,7 +19,8 @@
 int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
 {
 	struct reiserfs_super_block * sb;
-	struct buffer_head ** bitmap, * bh;
+        struct reiserfs_bitmap_info *bitmap;
+	struct buffer_head * bh;
 	struct reiserfs_transaction_handle th;
 	unsigned int bmap_nr_new, bmap_nr;
 	unsigned int block_r_new, block_r;
@@ -103,26 +104,26 @@
 	
 	    /* allocate additional bitmap blocks, reallocate array of bitmap
 	     * block pointers */
-	    bitmap = reiserfs_kmalloc(sizeof(struct buffer_head *) * bmap_nr_new, GFP_KERNEL, s);
+	    bitmap = vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
 	    if (!bitmap) {
 		printk("reiserfs_resize: unable to allocate memory.\n");
 		return -ENOMEM;
 	    }
 	    for (i = 0; i < bmap_nr; i++)
-		bitmap[i] = SB_AP_BITMAP(s)[i];
+		bitmap[i].bh = SB_AP_BITMAP(s)[i].bh;
 	    for (i = bmap_nr; i < bmap_nr_new; i++) {
-		bitmap[i] = getblk(s->s_dev, i * s->s_blocksize * 8, s->s_blocksize);
-		memset(bitmap[i]->b_data, 0, sb->s_blocksize);
-		reiserfs_test_and_set_le_bit(0, bitmap[i]->b_data);
-
-		mark_buffer_dirty(bitmap[i]) ;
-		mark_buffer_uptodate(bitmap[i], 1);
-		ll_rw_block(WRITE, 1, bitmap + i);
-		wait_on_buffer(bitmap[i]);
+		bitmap[i].bh = getblk(s->s_dev, i * s->s_blocksize * 8, s->s_blocksize);
+		memset(bitmap[i].bh->b_data, 0, sb->s_blocksize);
+		reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data);
+
+		mark_buffer_dirty(bitmap[i].bh) ;
+		mark_buffer_uptodate(bitmap[i].bh, 1);
+		ll_rw_block(WRITE, 1, &bitmap[i].bh);
+		wait_on_buffer(bitmap[i].bh);
 	    }	
 	    /* free old bitmap blocks array */
-	    reiserfs_kfree(SB_AP_BITMAP(s), 
-			   sizeof(struct buffer_head *) * bmap_nr, s);
+	    vfree(SB_AP_BITMAP(s)); 
+			   
 	    SB_AP_BITMAP(s) = bitmap;
 	}
 	
@@ -130,17 +131,17 @@
 	journal_begin(&th, s, 10);
 
 	/* correct last bitmap blocks in old and new disk layout */
-	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1], 1);
+	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
 	for (i = block_r; i < s->s_blocksize * 8; i++)
 	    reiserfs_test_and_clear_le_bit(i, 
-					   SB_AP_BITMAP(s)[bmap_nr - 1]->b_data);
-	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1]);
+					   SB_AP_BITMAP(s)[bmap_nr - 1].bh->b_data);
+	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1].bh);
 
-	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1], 1);
+	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh, 1);
 	for (i = block_r_new; i < s->s_blocksize * 8; i++)
 	    reiserfs_test_and_set_le_bit(i,
-					 SB_AP_BITMAP(s)[bmap_nr_new - 1]->b_data);
-	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1]);
+					 SB_AP_BITMAP(s)[bmap_nr_new - 1].bh->b_data);
+	journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh);
  
  	/* update super */
 	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
diff -urN linux-2.4.20-pre1/fs/reiserfs/stree.c linux-2.4.20-pre2/fs/reiserfs/stree.c
--- linux-2.4.20-pre1/fs/reiserfs/stree.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/stree.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ *  Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 /*
@@ -1621,9 +1621,9 @@
     
     do_balance(&s_cut_balance, NULL, NULL, c_mode);
     if ( n_is_inode_locked ) {
-	/* we've done an indirect->direct conversion.  when the data block 
-	** was freed, it was removed from the list of blocks that must 
-	** be flushed before the transaction commits, so we don't need to 
+	/* we've done an indirect->direct conversion.  when the data block
+	** was freed, it was removed from the list of blocks that must
+	** be flushed before the transaction commits, so we don't need to
 	** deal with it here.
 	*/
 	p_s_inode->u.reiserfs_i.i_flags &= ~i_pack_on_close_mask;
@@ -1814,6 +1814,9 @@
     int                 retval;
 
     init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, n_pasted_size);
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    s_paste_balance.key = p_s_key->on_disk_key;
+#endif
     
     while ( (retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) == REPEAT_SEARCH ) {
 	/* file system changed while we were in the fix_nodes */
@@ -1824,7 +1827,7 @@
 	    goto error_out ;
 	}
 	if (retval == POSITION_FOUND) {
-	    reiserfs_warning ("PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists", p_s_key);
+	    reiserfs_warning ("PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists\n", p_s_key);
 	    retval = -EEXIST ;
 	    goto error_out ;
 	}
@@ -1859,6 +1862,9 @@
     int                 retval;
 
     init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + ih_item_len(p_s_ih));
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    s_ins_balance.key = key->on_disk_key;
+#endif
 
     /*
     if (p_c_body == 0)
diff -urN linux-2.4.20-pre1/fs/reiserfs/super.c linux-2.4.20-pre2/fs/reiserfs/super.c
--- linux-2.4.20-pre1/fs/reiserfs/super.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/super.c	Mon Aug 12 16:34:17 2002
@@ -1,19 +1,11 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
- *
- * Trivial changes by Alan Cox to add the LFS fixes
- *
- * Trivial Changes:
- * Rights granted to Hans Reiser to redistribute under other terms providing
- * he accepts all liability including but not limited to patent, fitness
- * for purpose, and direct or indirect claims arising from failure to perform.
- *
- * NO WARRANTY
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/vmalloc.h>
 #include <asm/uaccess.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
@@ -29,13 +21,6 @@
 static int reiserfs_remount (struct super_block * s, int * flags, char * data);
 static int reiserfs_statfs (struct super_block * s, struct statfs * buf);
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static void reiserfs_write_super (struct super_block * s)
 {
 
@@ -48,13 +33,6 @@
   unlock_kernel() ;
 }
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static void reiserfs_write_super_lockfs (struct super_block * s)
 {
 
@@ -333,13 +311,6 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static void reiserfs_put_super (struct super_block * s)
 {
   int i;
@@ -359,9 +330,9 @@
   journal_release(&th, s) ;
 
   for (i = 0; i < SB_BMAP_NR (s); i ++)
-    brelse (SB_AP_BITMAP (s)[i]);
+    brelse (SB_AP_BITMAP (s)[i].bh);
 
-  reiserfs_kfree (SB_AP_BITMAP (s), sizeof (struct buffer_head *) * SB_BMAP_NR (s), s);
+  vfree (SB_AP_BITMAP (s));
 
   brelse (SB_BUFFER_WITH_SB (s));
 
@@ -372,6 +343,11 @@
 		      s->u.reiserfs_sb.s_kmallocs);
   }
 
+  if (s->u.reiserfs_sb.reserved_blocks != 0) {
+    reiserfs_warning ("green-2005: reiserfs_put_super: reserved blocks left %d\n",
+		      s->u.reiserfs_sb.reserved_blocks);
+  }
+
   reiserfs_proc_unregister( s, "journal" );
   reiserfs_proc_unregister( s, "oidmap" );
   reiserfs_proc_unregister( s, "on-disk-super" );
@@ -422,81 +398,209 @@
 
 };
 
-/* this was (ext2)parse_options */
-static int parse_options (char * options, unsigned long * mount_options, unsigned long * blocks)
-{
-    char * this_char;
+/* this struct is used in reiserfs_getopt () for containing the value for those
+   mount options that have values rather than being toggles. */
+typedef struct {
     char * value;
-  
+    int bitmask; /* bit which is to be set in mount_options bitmask when this
+                    value is found, 0 is no bits are to be set */
+} arg_desc_t;
+
+
+/* this struct is used in reiserfs_getopt() for describing the set of reiserfs
+   mount options */
+typedef struct {
+    char * option_name;
+    int arg_required; /* 0 is argument is not required, not 0 otherwise */
+    const arg_desc_t * values; /* list of values accepted by an option */
+    int bitmask;  /* bit which is to be set in mount_options bitmask when this
+		     option is selected, 0 is not bits are to be set */
+} opt_desc_t;
+
+
+/* possible values for "-o hash=" and bits which are to be set in s_mount_opt
+   of reiserfs specific part of in-core super block */
+const arg_desc_t hash[] = {
+    {"rupasov", FORCE_RUPASOV_HASH},
+    {"tea", FORCE_TEA_HASH},
+    {"r5", FORCE_R5_HASH},
+    {"detect", FORCE_HASH_DETECT},
+    {NULL, 0}
+};
+
+
+/* possible values for "-o block-allocator=" and bits which are to be set in
+   s_mount_opt of reiserfs specific part of in-core super block */
+const arg_desc_t balloc[] = {
+    {"noborder", REISERFS_NO_BORDER},
+    {"no_unhashed_relocation", REISERFS_NO_UNHASHED_RELOCATION},
+    {"hashed_relocation", REISERFS_HASHED_RELOCATION},
+    {"test4", REISERFS_TEST4},
+    {NULL, 0}
+};
+
+const arg_desc_t tails[] = {
+    {"on", REISERFS_LARGETAIL},
+    {"off", -1},
+    {"small", REISERFS_SMALLTAIL},
+    {NULL, 0}
+};
+
+
+/* proceed only one option from a list *cur - string containing of mount options
+   opts - array of options which are accepted
+   opt_arg - if option is found and requires an argument and if it is specifed
+   in the input - pointer to the argument is stored here
+   bit_flags - if option requires to set a certain bit - it is set here
+   return -1 if unknown option is found, opt->arg_required otherwise */
+static int reiserfs_getopt ( struct super_block * s, char ** cur, opt_desc_t * opts, char ** opt_arg,
+			    unsigned long * bit_flags)
+{
+    char * p;
+    /* foo=bar, 
+       ^   ^  ^
+       |   |  +-- option_end
+       |   +-- arg_start
+       +-- option_start
+    */
+    const opt_desc_t * opt;
+    const arg_desc_t * arg;
+    
+    
+    p = *cur;
+    
+    /* assume argument cannot contain commas */
+    *cur = strchr (p, ',');
+    if (*cur) {
+	*(*cur) = '\0';
+	(*cur) ++;
+    }
+
+    if ( !strncmp (p, "alloc=", 6) ) {
+	/* Ugly special case, probably we should redo options parser so that
+	   it can understand several arguments for some options, also so that
+	   it can fill several bitfields with option values. */
+	reiserfs_parse_alloc_options( s, p + 6);
+	return 0;
+    }
+	
+    /* for every option in the list */
+    for (opt = opts; opt->option_name; opt ++) {
+	if (!strncmp (p, opt->option_name, strlen (opt->option_name))) {
+	    if (bit_flags && opt->bitmask != -1 )
+		set_bit (opt->bitmask, bit_flags);
+	    break;
+	}
+    }
+    if (!opt->option_name) {
+	printk ("reiserfs_getopt: unknown option \"%s\"\n", p);
+	return -1;
+    }
+    
+    p += strlen (opt->option_name);
+    switch (*p) {
+    case '=':
+	if (!opt->arg_required) {
+	    printk ("reiserfs_getopt: the option \"%s\" does not require an argument\n",
+		    opt->option_name);
+	    return -1;
+	}
+	break;
+	
+    case 0:
+	if (opt->arg_required) {
+	    printk ("reiserfs_getopt: the option \"%s\" requires an argument\n", opt->option_name);
+	    return -1;
+	}
+	break;
+    default:
+	printk ("reiserfs_getopt: head of option \"%s\" is only correct\n", opt->option_name);
+	return -1;
+    }
+	
+    /* move to the argument, or to next option if argument is not required */
+    p ++;
+    
+    if ( opt->arg_required && !strlen (p) ) {
+	/* this catches "option=," */
+	printk ("reiserfs_getopt: empty argument for \"%s\"\n", opt->option_name);
+	return -1;
+    }
+    
+    if (!opt->values) {
+	/* *opt_arg contains pointer to argument */
+	*opt_arg = p;
+	return opt->arg_required;
+    }
+    
+    /* values possible for this option are listed in opt->values */
+    for (arg = opt->values; arg->value; arg ++) {
+	if (!strcmp (p, arg->value)) {
+	    if (bit_flags && arg->bitmask != -1 )
+		set_bit (arg->bitmask, bit_flags);
+	    return opt->arg_required;
+	}
+    }
+    
+    printk ("reiserfs_getopt: bad value \"%s\" for option \"%s\"\n", p, opt->option_name);
+    return -1;
+}
+
+
+/* returns 0 if something is wrong in option string, 1 - otherwise */
+static int reiserfs_parse_options (struct super_block * s, char * options, /* string given via mount's -o */
+				   unsigned long * mount_options,
+				   /* after the parsing phase, contains the
+				      collection of bitflags defining what
+				      mount options were selected. */
+				   unsigned long * blocks) /* strtol-ed from NNN of resize=NNN */
+{
+    int c;
+    char * arg = NULL;
+    char * pos;
+    opt_desc_t opts[] = {
+		{"tails", 't', tails, -1},
+		{"notail", 0, 0, -1}, /* Compatibility stuff, so that -o notail for old setups still work */
+		{"conv", 0, 0, REISERFS_CONVERT}, 
+		{"nolog", 0, 0, -1},
+		{"replayonly", 0, 0, REPLAYONLY},
+		
+		{"block-allocator", 'a', balloc, -1}, 
+		{"hash", 'h', hash, FORCE_HASH_DETECT},
+		
+		{"resize", 'r', 0, -1},
+		{NULL, 0, 0, 0}
+    };
+	
     *blocks = 0;
-    if (!options)
+    if (!options || !*options)
 	/* use default configuration: create tails, journaling on, no
-           conversion to newest format */
+	   conversion to newest format */
 	return 1;
-    for (this_char = strtok (options, ","); this_char != NULL; this_char = strtok (NULL, ",")) {
-	if ((value = strchr (this_char, '=')) != NULL)
-	    *value++ = 0;
-	if (!strcmp (this_char, "notail")) {
-	    set_bit (NOTAIL, mount_options);
-	} else if (!strcmp (this_char, "conv")) {
-	    // if this is set, we update super block such that
-	    // the partition will not be mounable by 3.5.x anymore
-	    set_bit (REISERFS_CONVERT, mount_options);
-	} else if (!strcmp (this_char, "noborder")) {
-				/* this is used for benchmarking
-                                   experimental variations, it is not
-                                   intended for users to use, only for
-                                   developers who want to casually
-                                   hack in something to test */
-	    set_bit (REISERFS_NO_BORDER, mount_options);
-	} else if (!strcmp (this_char, "no_unhashed_relocation")) {
-	    set_bit (REISERFS_NO_UNHASHED_RELOCATION, mount_options);
-	} else if (!strcmp (this_char, "hashed_relocation")) {
-	    set_bit (REISERFS_HASHED_RELOCATION, mount_options);
-	} else if (!strcmp (this_char, "test4")) {
-	    set_bit (REISERFS_TEST4, mount_options);
-	} else if (!strcmp (this_char, "nolog")) {
-	    reiserfs_warning("reiserfs: nolog mount option not supported yet\n");
-	} else if (!strcmp (this_char, "replayonly")) {
-	    set_bit (REPLAYONLY, mount_options);
-	} else if (!strcmp (this_char, "resize")) {
-	    if (value && *value){
-		*blocks = simple_strtoul (value, &value, 0);
-	    } else {
-	  	printk("reiserfs: resize option requires a value\n");
+    else
+	/* Drop defaults to zeroes */
+	*mount_options = 0;
+    
+    for (pos = options; pos; ) {
+	c = reiserfs_getopt (s, &pos, opts, &arg, mount_options);
+	if (c == -1)
+	    /* wrong option is given */
+	    return 0;
+	
+	if (c == 'r') {
+	    char * p;
+	    
+	    p = 0;
+	    /* "resize=NNN" */
+	    *blocks = simple_strtoul (arg, &p, 0);
+	    if (*p != '\0') {
+		/* NNN does not look like a number */
+		printk ("reiserfs_parse_options: bad value %s\n", arg);
 		return 0;
 	    }
-	} else if (!strcmp (this_char, "hash")) {
-	    if (value && *value) {
-		/* if they specify any hash option, we force detection
-		** to make sure they aren't using the wrong hash
-		*/
-	        if (!strcmp(value, "rupasov")) {
-		    set_bit (FORCE_RUPASOV_HASH, mount_options);
-		    set_bit (FORCE_HASH_DETECT, mount_options);
-		} else if (!strcmp(value, "tea")) {
-		    set_bit (FORCE_TEA_HASH, mount_options);
-		    set_bit (FORCE_HASH_DETECT, mount_options);
-		} else if (!strcmp(value, "r5")) {
-		    set_bit (FORCE_R5_HASH, mount_options);
-		    set_bit (FORCE_HASH_DETECT, mount_options);
-		} else if (!strcmp(value, "detect")) {
-		    set_bit (FORCE_HASH_DETECT, mount_options);
-		} else {
-		    printk("reiserfs: invalid hash function specified\n") ;
-		    return 0 ;
-		}
-	    } else {
-	  	printk("reiserfs: hash option requires a value\n");
-		return 0 ;
-	    }
-	} else if (!strcmp (this_char, "attrs")) {
-	    set_bit (REISERFS_ATTRS, mount_options);
-	} else {
-	    printk ("reiserfs: Unrecognized mount option %s\n", this_char);
-	    return 0;
 	}
     }
+    
     return 1;
 }
 
@@ -524,14 +628,7 @@
 	}
 }
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
-static int reiserfs_remount (struct super_block * s, int * flags, char * data)
+static int reiserfs_remount (struct super_block * s, int * mount_flags, char * data)
 {
   struct reiserfs_super_block * rs;
   struct reiserfs_transaction_handle th ;
@@ -540,7 +637,7 @@
 
   rs = SB_DISK_SUPER_BLOCK (s);
 
-  if (!parse_options(data, &mount_options, &blocks))
+  if (!reiserfs_parse_options(s, data, &mount_options, &blocks))
   	return 0;
 
 #define SET_OPT( opt, bits, super )					\
@@ -548,7 +645,8 @@
 	    ( super ) -> u.reiserfs_sb.s_mount_opt |= ( 1 << ( opt ) )
 
   /* set options in the super-block bitmask */
-  SET_OPT( NOTAIL, mount_options, s );
+  SET_OPT( REISERFS_SMALLTAIL, mount_options, s );
+  SET_OPT( REISERFS_LARGETAIL, mount_options, s );
   SET_OPT( REISERFS_NO_BORDER, mount_options, s );
   SET_OPT( REISERFS_NO_UNHASHED_RELOCATION, mount_options, s );
   SET_OPT( REISERFS_HASHED_RELOCATION, mount_options, s );
@@ -564,12 +662,11 @@
 	  return rc;
   }
 
-  if ((unsigned long)(*flags & MS_RDONLY) == (s->s_flags & MS_RDONLY)) {
-    /* there is nothing to do to remount read-only fs as read-only fs */
-    return 0;
-  }
-  
-  if (*flags & MS_RDONLY) {
+  if (*mount_flags & MS_RDONLY) {
+    /* remount rean-only */
+    if (s->s_flags & MS_RDONLY)
+      /* it is read-only already */
+      return 0;
     /* try to remount file system with read-only permissions */
     if (sb_state(rs) == REISERFS_VALID_FS || s->u.reiserfs_sb.s_mount_state != REISERFS_VALID_FS) {
       return 0;
@@ -585,7 +682,7 @@
     s->u.reiserfs_sb.s_mount_state = sb_state(rs) ;
     s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
     journal_begin(&th, s, 10) ;
-
+    
     /* Mount a partition which is read-only, read-write */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
     s->u.reiserfs_sb.s_mount_state = sb_state(rs);
@@ -600,38 +697,90 @@
   SB_JOURNAL(s)->j_must_wait = 1 ;
   journal_end(&th, s, 10) ;
 
-  if (!( *flags & MS_RDONLY ) )
+  if (!( *mount_flags & MS_RDONLY ) )
     finish_unfinished( s );
 
   return 0;
 }
 
+/* load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure from disk.
+ * @sb - superblock for this filesystem
+ * @bi - the bitmap info to be loaded. Requires that bi->bh is valid.
+ *
+ * This routine counts how many free bits there are, finding the first zero
+ * as a side effect. Could also be implemented as a loop of test_bit() calls, or
+ * a loop of find_first_zero_bit() calls. This implementation is similar to
+ * find_first_zero_bit(), but doesn't return after it finds the first bit.
+ * Should only be called on fs mount, but should be fairly efficient anyways.
+ *
+ * bi->first_zero_hint is considered unset if it == 0, since the bitmap itself
+ * will * invariably occupt block 0 represented in the bitmap. The only
+ * exception to this is when free_count also == 0, since there will be no
+ * free blocks at all.
+ */
+static void load_bitmap_info_data (struct super_block *sb,
+                                   struct reiserfs_bitmap_info *bi)
+{
+    __u32 *cur = (__u32 *)bi->bh->b_data;
+
+    while ((char *)cur < (bi->bh->b_data + sb->s_blocksize)) {
+
+	/* No need to scan if all 0's or all 1's.
+	 * Since we're only counting 0's, we can simply ignore all 1's */
+	if (*cur == 0) {
+	    if (bi->first_zero_hint == 0) {
+		bi->first_zero_hint = ((char *)cur - bi->bh->b_data) << 3;
+	    }
+	    bi->free_count += 32;
+	} else if (*cur != ~0L) {
+	    int b;
+	    for (b = 0; b < 32; b++) {
+		if (!test_bit (b, cur)) {
+		    bi->free_count ++;
+		    if (bi->first_zero_hint == 0)
+			bi->first_zero_hint =
+					(((char *)cur - bi->bh->b_data) << 3) + b;
+		    }
+		}
+	    }
+	cur ++;
+    }
+
+#ifdef CONFIG_REISERFS_CHECK
+// This outputs a lot of unneded info on big FSes
+//    reiserfs_warning ("bitmap loaded from block %d: %d free blocks\n",
+//		      bi->bh->b_blocknr, bi->free_count);
+#endif
+}
 
 static int read_bitmaps (struct super_block * s)
 {
     int i, bmp;
 
-    SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * SB_BMAP_NR(s), GFP_NOFS, s);
+    SB_AP_BITMAP (s) = vmalloc (sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
     if (SB_AP_BITMAP (s) == 0)
       return 1;
+    memset (SB_AP_BITMAP (s), 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
+
     for (i = 0, bmp = REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1;
  	 i < SB_BMAP_NR(s); i++, bmp = s->s_blocksize * 8 * i) {
-      SB_AP_BITMAP (s)[i] = getblk (s->s_dev, bmp, s->s_blocksize);
-      if (!buffer_uptodate(SB_AP_BITMAP(s)[i]))
-	ll_rw_block(READ, 1, SB_AP_BITMAP(s) + i); 
+      SB_AP_BITMAP (s)[i].bh = sb_getblk (s, bmp);
+      if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh))
+	ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh); 
     }
     for (i = 0; i < SB_BMAP_NR(s); i++) {
-      wait_on_buffer(SB_AP_BITMAP (s)[i]);
-      if (!buffer_uptodate(SB_AP_BITMAP(s)[i])) {
+      wait_on_buffer(SB_AP_BITMAP (s)[i].bh);
+      if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
 	reiserfs_warning("sh-2029: reiserfs read_bitmaps: "
 			 "bitmap block (#%lu) reading failed\n",
-			 SB_AP_BITMAP(s)[i]->b_blocknr);
+			 SB_AP_BITMAP(s)[i].bh->b_blocknr);
 	for (i = 0; i < SB_BMAP_NR(s); i++)
-	  brelse(SB_AP_BITMAP(s)[i]);
-	reiserfs_kfree(SB_AP_BITMAP(s), sizeof(struct buffer_head *) * SB_BMAP_NR(s), s);
+	  brelse(SB_AP_BITMAP(s)[i].bh);
+	vfree(SB_AP_BITMAP(s));
 	SB_AP_BITMAP(s) = NULL;
 	return 1;
       }
+      load_bitmap_info_data (s, SB_AP_BITMAP (s) + i);
     }   
     return 0;
 }
@@ -643,16 +792,17 @@
   int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1;  /* first of bitmap blocks */
 
   /* read true bitmap */
-  SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * sb_bmap_nr(rs), GFP_NOFS, s);
+  SB_AP_BITMAP (s) = vmalloc (sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
   if (SB_AP_BITMAP (s) == 0)
     return 1;
 
-  memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs));
+  memset (SB_AP_BITMAP (s), 0, sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
 
   for (i = 0; i < sb_bmap_nr(rs); i ++) {
-    SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp1 + i, s->s_blocksize);
-    if (!SB_AP_BITMAP (s)[i])
+    SB_AP_BITMAP (s)[i].bh = reiserfs_bread (s, bmp1 + i, s->s_blocksize);
+    if (!SB_AP_BITMAP (s)[i].bh)
       return 1;
+    load_bitmap_info_data (s, SB_AP_BITMAP (s) + i);
   }
 
   return 0;
@@ -665,7 +815,7 @@
   char * buf;
 
   while (i < SB_BLOCK_COUNT (s)) {
-    buf = SB_AP_BITMAP (s)[i / (s->s_blocksize * 8)]->b_data;
+    buf = SB_AP_BITMAP (s)[i / (s->s_blocksize * 8)].bh->b_data;
     if (!reiserfs_test_le_bit (i % (s->s_blocksize * 8), buf))
       free ++;
     i ++;
@@ -777,10 +927,11 @@
   }
 
   for (i = 0; i < SB_BMAP_NR(s) ; i++) {
-    ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i])) ;
-    wait_on_buffer(SB_AP_BITMAP(s)[i]) ;
-    if (!buffer_uptodate(SB_AP_BITMAP(s)[i])) {
-      printk("reread_meta_blocks, error reading bitmap block number %d at %ld\n", i, SB_AP_BITMAP(s)[i]->b_blocknr) ;
+    ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh)) ;
+    wait_on_buffer(SB_AP_BITMAP(s)[i].bh) ;
+    if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
+      printk("reread_meta_blocks, error reading bitmap block number %d at
+      %ld\n", i, SB_AP_BITMAP(s)[i].bh->b_blocknr) ;
       return 1 ;
     }
   }
@@ -944,13 +1095,6 @@
     return 0;
 }
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent)
 {
     int size;
@@ -969,7 +1113,12 @@
 
     memset (&s->u.reiserfs_sb, 0, sizeof (struct reiserfs_sb_info));
 
-    if (parse_options ((char *) data, &(s->u.reiserfs_sb.s_mount_opt), &blocks) == 0) {
+    /* Set default values for options: non-aggressive tails */
+    s->u.reiserfs_sb.s_mount_opt = ( 1 << REISERFS_SMALLTAIL );
+    /* default block allocator option: skip_busy */
+    s->u.reiserfs_sb.s_alloc_options.bits = ( 1 << 5);
+
+    if (reiserfs_parse_options (s, (char *) data, &(s->u.reiserfs_sb.s_mount_opt), &blocks) == 0) {
 	return NULL;
     }
 
@@ -1119,10 +1268,10 @@
     if (SB_DISK_SUPER_BLOCK (s)) {
 	for (j = 0; j < SB_BMAP_NR (s); j ++) {
 	    if (SB_AP_BITMAP (s))
-		brelse (SB_AP_BITMAP (s)[j]);
+		brelse (SB_AP_BITMAP (s)[j].bh);
 	}
 	if (SB_AP_BITMAP (s))
-	    reiserfs_kfree (SB_AP_BITMAP (s), sizeof (struct buffer_head *) * SB_BMAP_NR (s), s);
+	    vfree (SB_AP_BITMAP (s));
     }
     if (SB_BUFFER_WITH_SB (s))
 	brelse(SB_BUFFER_WITH_SB (s));
@@ -1131,34 +1280,24 @@
 }
 
 
-//
-// a portion of this function, particularly the VFS interface portion,
-// was derived from minix or ext2's analog and evolved as the
-// prototype did. You should be able to tell which portion by looking
-// at the ext2 code and comparing. It's subfunctions contain no code
-// used as a template unless they are so labeled.
-//
 static int reiserfs_statfs (struct super_block * s, struct statfs * buf)
 {
   struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
   
-				/* changed to accomodate gcc folks.*/
-  buf->f_type    =  REISERFS_SUPER_MAGIC;
-  buf->f_bsize   = s->s_blocksize;
-  buf->f_blocks  = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
+  buf->f_namelen = (REISERFS_MAX_NAME (s->s_blocksize));
+  buf->f_ffree   = -1;
+  buf->f_files   = -1;
   buf->f_bfree   = sb_free_blocks(rs);
   buf->f_bavail  = buf->f_bfree;
-  buf->f_files   = -1;
-  buf->f_ffree   = -1;
-  buf->f_namelen = (REISERFS_MAX_NAME_LEN (s->s_blocksize));
+  buf->f_blocks  = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
+  buf->f_bsize   = s->s_blocksize;
+  /* changed to accomodate gcc folks.*/
+  buf->f_type    =  REISERFS_SUPER_MAGIC;
   return 0;
 }
 
 static DECLARE_FSTYPE_DEV(reiserfs_fs_type,"reiserfs",reiserfs_read_super);
 
-//
-// this is exactly what 2.3.99-pre9's init_ext2_fs is
-//
 static int __init init_reiserfs_fs (void)
 {
 	reiserfs_proc_info_global_init();
@@ -1172,9 +1311,6 @@
 MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
 
-//
-// this is exactly what 2.3.99-pre9's init_ext2_fs is
-//
 static void __exit exit_reiserfs_fs(void)
 {
 	reiserfs_proc_unregister_global( "version" );
diff -urN linux-2.4.20-pre1/fs/reiserfs/tail_conversion.c linux-2.4.20-pre2/fs/reiserfs/tail_conversion.c
--- linux-2.4.20-pre1/fs/reiserfs/tail_conversion.c	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/fs/reiserfs/tail_conversion.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999 Hans Reiser, see reiserfs/README for licensing and copyright details
+ * Copyright 1999-2002 Hans Reiser, see reiserfs/README for licensing and copyright details
  */
 
 #include <linux/config.h>
@@ -213,7 +213,7 @@
     copy_item_head (&s_ih, PATH_PITEM_HEAD(p_s_path));
 
     tail_len = (n_new_file_size & (n_block_size - 1));
-    if (!old_format_only (p_s_sb))
+    if (get_inode_sd_version (p_s_inode) == STAT_DATA_V2)
 	round_tail_len = ROUND_UP (tail_len);
     else
 	round_tail_len = tail_len;
diff -urN linux-2.4.20-pre1/fs/reiserfs/version.c linux-2.4.20-pre2/fs/reiserfs/version.c
--- linux-2.4.20-pre1/fs/reiserfs/version.c	Mon Jan 15 12:42:32 2001
+++ linux-2.4.20-pre2/fs/reiserfs/version.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
  */
 
 char *reiserfs_get_version_string(void) {
diff -urN linux-2.4.20-pre1/include/asm-alpha/io.h linux-2.4.20-pre2/include/asm-alpha/io.h
--- linux-2.4.20-pre1/include/asm-alpha/io.h	Fri Nov  9 13:45:35 2001
+++ linux-2.4.20-pre2/include/asm-alpha/io.h	Mon Aug 12 16:34:17 2002
@@ -60,6 +60,8 @@
 	return (void *) (address + IDENT_ADDR);
 }
 
+#define page_to_phys(page)	PAGE_TO_PA(page)
+
 /*
  * Change addresses as seen by the kernel (virtual) to addresses as
  * seen by a device (bus), and vice versa.
diff -urN linux-2.4.20-pre1/include/asm-alpha/socket.h linux-2.4.20-pre2/include/asm-alpha/socket.h
--- linux-2.4.20-pre1/include/asm-alpha/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-alpha/socket.h	Mon Aug 12 16:34:17 2002
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 /*
  * Note: we only bother about making the SOL_SOCKET options
  * same as OSF/1, as that's all that "normal" programs are
diff -urN linux-2.4.20-pre1/include/asm-arm/socket.h linux-2.4.20-pre2/include/asm-arm/socket.h
--- linux-2.4.20-pre1/include/asm-arm/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-arm/socket.h	Mon Aug 12 16:34:17 2002
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -urN linux-2.4.20-pre1/include/asm-cris/pgtable.h linux-2.4.20-pre2/include/asm-cris/pgtable.h
--- linux-2.4.20-pre1/include/asm-cris/pgtable.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-cris/pgtable.h	Mon Aug 12 16:34:17 2002
@@ -167,7 +167,7 @@
  */
 #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
 /*
- * (pmds are folded into pgds so this doesnt get actually called,
+ * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
  */
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
diff -urN linux-2.4.20-pre1/include/asm-i386/fixmap.h linux-2.4.20-pre2/include/asm-i386/fixmap.h
--- linux-2.4.20-pre1/include/asm-i386/fixmap.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-i386/fixmap.h	Mon Aug 12 16:34:17 2002
@@ -61,6 +61,9 @@
 	FIX_LI_PCIA,	/* Lithium PCI Bridge A */
 	FIX_LI_PCIB,	/* Lithium PCI Bridge B */
 #endif
+#ifndef CONFIG_X86_F00F_WORKS_OK
+	FIX_F00F,
+#endif
 #ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
diff -urN linux-2.4.20-pre1/include/asm-i386/io.h linux-2.4.20-pre2/include/asm-i386/io.h
--- linux-2.4.20-pre1/include/asm-i386/io.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-i386/io.h	Mon Aug 12 16:34:17 2002
@@ -333,7 +333,7 @@
 #define __OUT2(s,s1,s2) \
 __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
 
-#ifdef CONFIG_MULTIQUAD
+#if defined (CONFIG_MULTIQUAD) && !defined(STANDALONE)
 #define __OUTQ(s,ss,x)    /* Do the equivalent of the portio op on quads */ \
 static inline void out##ss(unsigned x value, unsigned short port) { \
 	if (xquad_portio) \
@@ -361,9 +361,9 @@
 	else\
 		return 0;\
 }
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_MULTIQUAD && !STANDALONE */
 
-#ifndef CONFIG_MULTIQUAD
+#if !defined(CONFIG_MULTIQUAD) || defined(STANDALONE)
 #define __OUT(s,s1,x) \
 __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
 __OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} 
@@ -374,7 +374,7 @@
 __OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
 __OUTQ(s,s,x) \
 __OUTQ(s,s##_p,x) 
-#endif /* CONFIG_MULTIQUAD */
+#endif /* !CONFIG_MULTIQUAD || STANDALONE */
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
@@ -382,7 +382,7 @@
 #define __IN2(s,s1,s2) \
 __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
 
-#ifndef CONFIG_MULTIQUAD
+#if !defined(CONFIG_MULTIQUAD) || defined(STANDALONE)
 #define __IN(s,s1,i...) \
 __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 __IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } 
@@ -393,7 +393,7 @@
 __IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 __INQ(s,s) \
 __INQ(s,s##_p) 
-#endif /* CONFIG_MULTIQUAD */
+#endif /* !CONFIG_MULTIQUAD || STANDALONE */
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
diff -urN linux-2.4.20-pre1/include/asm-i386/kmap_types.h linux-2.4.20-pre2/include/asm-i386/kmap_types.h
--- linux-2.4.20-pre1/include/asm-i386/kmap_types.h	Mon Sep 17 13:16:30 2001
+++ linux-2.4.20-pre2/include/asm-i386/kmap_types.h	Mon Aug 12 16:34:17 2002
@@ -7,6 +7,7 @@
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
+	KM_BH_IRQ,
 	KM_TYPE_NR
 };
 
diff -urN linux-2.4.20-pre1/include/asm-i386/scatterlist.h linux-2.4.20-pre2/include/asm-i386/scatterlist.h
--- linux-2.4.20-pre1/include/asm-i386/scatterlist.h	Fri Oct 12 15:35:54 2001
+++ linux-2.4.20-pre2/include/asm-i386/scatterlist.h	Mon Aug 12 16:34:17 2002
@@ -1,6 +1,24 @@
 #ifndef _I386_SCATTERLIST_H
 #define _I386_SCATTERLIST_H
 
+/*
+ * Drivers must set either ->address or (preferred) ->page and ->offset
+ * to indicate where data must be transferred to/from.
+ *
+ * Using ->page is recommended since it handles highmem data as well as
+ * low mem. ->address is restricted to data which has a virtual mapping, and
+ * it will go away in the future. Updating to ->page can be automated very
+ * easily -- something like
+ *
+ * sg->address = some_ptr;
+ *
+ * can be rewritten as
+ *
+ * sg->page = virt_to_page(some_ptr);
+ * sg->offset = (unsigned long) some_ptr & ~PAGE_MASK;
+ *
+ * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
+ */
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to, NULL for
 			 * highmem page */
diff -urN linux-2.4.20-pre1/include/asm-i386/socket.h linux-2.4.20-pre2/include/asm-i386/socket.h
--- linux-2.4.20-pre1/include/asm-i386/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-i386/socket.h	Mon Aug 12 16:34:17 2002
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -urN linux-2.4.20-pre1/include/asm-i386/spinlock.h linux-2.4.20-pre2/include/asm-i386/spinlock.h
--- linux-2.4.20-pre1/include/asm-i386/spinlock.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-i386/spinlock.h	Mon Aug 12 16:34:17 2002
@@ -49,7 +49,7 @@
  * We make no fairness assumptions. They have a cost.
  */
 
-#define spin_is_locked(x)	(*(volatile char *)(&(x)->lock) <= 0)
+#define spin_is_locked(x)	(*(volatile signed char *)(&(x)->lock) <= 0)
 #define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
 
 #define spin_lock_string \
diff -urN linux-2.4.20-pre1/include/asm-i386/system.h linux-2.4.20-pre2/include/asm-i386/system.h
--- linux-2.4.20-pre1/include/asm-i386/system.h	Thu Nov 22 11:46:18 2001
+++ linux-2.4.20-pre2/include/asm-i386/system.h	Mon Aug 12 16:34:17 2002
@@ -154,6 +154,11 @@
  * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
  * might have an implicit FPU-save as a cost, so it's not
  * clear which path to go.)
+ *
+ * chmxchg8b must be used with the lock prefix here to allow
+ * the instruction to be executed atomically, see page 3-102
+ * of the instruction set reference 24319102.pdf. We need
+ * the reader side to see the coherent 64bit value.
  */
 static inline void __set_64bit (unsigned long long * ptr,
 		unsigned int low, unsigned int high)
@@ -162,7 +167,7 @@
 		"\n1:\t"
 		"movl (%0), %%eax\n\t"
 		"movl 4(%0), %%edx\n\t"
-		"cmpxchg8b (%0)\n\t"
+		"lock cmpxchg8b (%0)\n\t"
 		"jnz 1b"
 		: /* no outputs */
 		:	"D"(ptr),
diff -urN linux-2.4.20-pre1/include/asm-ia64/module.h linux-2.4.20-pre2/include/asm-ia64/module.h
--- linux-2.4.20-pre1/include/asm-ia64/module.h	Fri Nov  9 14:26:17 2001
+++ linux-2.4.20-pre2/include/asm-ia64/module.h	Mon Aug 12 16:34:17 2002
@@ -72,7 +72,7 @@
 		return 1;
 	}
 	if (!mod_bound(archdata->segment_base, 0, mod)) {
-		printk(KERN_ERR "module_arch_init: archdata->unw_table out of bounds.\n");
+		printk(KERN_ERR "module_arch_init: archdata->segment_base out of bounds.\n");
 		return 1;
 	}
 
diff -urN linux-2.4.20-pre1/include/asm-ia64/socket.h linux-2.4.20-pre2/include/asm-ia64/socket.h
--- linux-2.4.20-pre1/include/asm-ia64/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-ia64/socket.h	Mon Aug 12 16:34:17 2002
@@ -10,7 +10,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -urN linux-2.4.20-pre1/include/asm-m68k/mac_via.h linux-2.4.20-pre2/include/asm-m68k/mac_via.h
--- linux-2.4.20-pre1/include/asm-m68k/mac_via.h	Sat Sep  4 13:06:41 1999
+++ linux-2.4.20-pre2/include/asm-m68k/mac_via.h	Mon Aug 12 16:34:17 2002
@@ -3,7 +3,7 @@
  *
  *	There are two of these on the Mac II. Some IRQ's are vectored
  *	via them as are assorted bits and bobs - eg rtc, adb. The picture
- *	is a bit incomplete as the Mac documentation doesnt cover this well
+ *	is a bit incomplete as the Mac documentation doesn't cover this well
  */
  
 #ifndef _ASM_MAC_VIA_H_
diff -urN linux-2.4.20-pre1/include/asm-m68k/socket.h linux-2.4.20-pre2/include/asm-m68k/socket.h
--- linux-2.4.20-pre1/include/asm-m68k/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-m68k/socket.h	Mon Aug 12 16:34:17 2002
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -urN linux-2.4.20-pre1/include/asm-mips/socket.h linux-2.4.20-pre2/include/asm-mips/socket.h
--- linux-2.4.20-pre1/include/asm-mips/socket.h	Mon Jul  2 13:56:40 2001
+++ linux-2.4.20-pre2/include/asm-mips/socket.h	Mon Aug 12 16:34:17 2002
@@ -4,7 +4,7 @@
 #include <asm/sockios.h>
 
 /*
- * For setsockoptions(2)
+ * For setsockopt(2)
  *
  * This defines are ABI conformant as far as Linux supports these ...
  */
diff -urN linux-2.4.20-pre1/include/asm-mips64/socket.h linux-2.4.20-pre2/include/asm-mips64/socket.h
--- linux-2.4.20-pre1/include/asm-mips64/socket.h	Wed Jul  4 11:50:39 2001
+++ linux-2.4.20-pre2/include/asm-mips64/socket.h	Mon Aug 12 16:34:17 2002
@@ -12,7 +12,7 @@
 #include <asm/sockios.h>
 
 /*
- * For setsockoptions(2)
+ * For setsockopt(2)
  *
  * This defines are ABI conformant as far as Linux supports these ...
  */
diff -urN linux-2.4.20-pre1/include/asm-parisc/socket.h linux-2.4.20-pre2/include/asm-parisc/socket.h
--- linux-2.4.20-pre1/include/asm-parisc/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-parisc/socket.h	Mon Aug 12 16:34:17 2002
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	0xffff
 
 #define SO_DEBUG	0x0001
diff -urN linux-2.4.20-pre1/include/asm-ppc/board.h linux-2.4.20-pre2/include/asm-ppc/board.h
--- linux-2.4.20-pre1/include/asm-ppc/board.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre2/include/asm-ppc/board.h	Wed Dec 31 16:00:00 1969
@@ -1,47 +0,0 @@
-/*
- * BK Id: SCCS/s.board.h 1.5 05/17/01 18:14:24 cort
- */
-/*
- *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: board.h
- *
- *    Description:
- *	A generic include file which pulls in appropriate include files
- *      for specific board types based on configuration settings.
- *
- */
-
-#ifdef __KERNEL__
-#ifndef __BOARD_H__
-#define	__BOARD_H__
-
-#include <linux/config.h>
-
-#if defined(CONFIG_OAK)
-#include <asm/oak.h>
-#endif
-
-#if defined(CONFIG_WALNUT)
-#include <asm/walnut.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The "residual" board information structure the boot loader passes
- * into the kernel.
- */
-
-extern unsigned char __res[];
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __BOARD_H__ */
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/bseip.h linux-2.4.20-pre2/include/asm-ppc/bseip.h
--- linux-2.4.20-pre1/include/asm-ppc/bseip.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.20-pre2/include/asm-ppc/bseip.h	Wed Dec 31 16:00:00 1969
@@ -1,42 +0,0 @@
-/*
- * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus
- */
-
-/*
- * A collection of structures, addresses, and values associated with
- * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_BSEIP_DEFS
-#define __MACH_BSEIP_DEFS
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
-	unsigned char	bi_enetaddr[6];
-	unsigned int	bi_baudrate;
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
-/* Memory map is configured by the PROM startup.
- * All we need to get started is the IMMR.
- */
-#define IMAP_ADDR		((uint)0xff000000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-#define PCMCIA_MEM_ADDR		((uint)0x04000000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
-#endif	/* !__ASSEMBLY__ */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif
diff -urN linux-2.4.20-pre1/include/asm-ppc/est8260.h linux-2.4.20-pre2/include/asm-ppc/est8260.h
--- linux-2.4.20-pre1/include/asm-ppc/est8260.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre2/include/asm-ppc/est8260.h	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-/*
- * BK Id: SCCS/s.est8260.h 1.5 05/17/01 18:14:24 cort
- */
-
-/* Board information for the EST8260, which should be generic for
- * all 8260 boards.  The IMMR is now given to us so the hard define
- * will soon be removed.  All of the clock values are computed from
- * the configuration SCMR and the Power-On-Reset word.
- */
-
-#define IMAP_ADDR	((uint)0xf0000000)
-
-
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in MHz */
-	unsigned int	bi_cpmfreq;	/* CPM Freq, in MHz */
-	unsigned int	bi_brgfreq;	/* BRG Freq, in MHz */
-	unsigned int	bi_vco;		/* VCO Out from PLL */
-	unsigned int	bi_baudrate;	/* Default console baud rate */
-	unsigned int	bi_immr;	/* IMMR when called from boot rom */
-	unsigned char	bi_enetaddr[6];
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
diff -urN linux-2.4.20-pre1/include/asm-ppc/fads.h linux-2.4.20-pre2/include/asm-ppc/fads.h
--- linux-2.4.20-pre1/include/asm-ppc/fads.h	Fri Nov  2 17:43:54 2001
+++ linux-2.4.20-pre2/include/asm-ppc/fads.h	Wed Dec 31 16:00:00 1969
@@ -1,61 +0,0 @@
-/*
- * BK Id: SCCS/s.fads.h 1.14 10/26/01 10:14:09 trini
- */
-
-/*
- * A collection of structures, addresses, and values associated with
- * the Motorola 860T FADS board.  Copied from the MBX stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifdef __KERNEL__
-#ifndef __ASM_FADS_H__
-#define __ASM_FADS_H__
-
-#include <linux/config.h>
-
-#include <asm/ppcboot.h>
-
-/* Memory map is configured by the PROM startup.
- * I tried to follow the FADS manual, although the startup PROM
- * dictates this and we simply have to move some of the physical
- * addresses for Linux.
- */
-#define BCSR_ADDR		((uint)0xff010000)
-#define BCSR_SIZE		((uint)(64 * 1024))
-#define	BCSR0			((uint)0xff010000)
-#define	BCSR1			((uint)0xff010004)
-#define	BCSR2			((uint)0xff010008)
-#define	BCSR3			((uint)0xff01000c)
-#define	BCSR4			((uint)0xff010010)
-
-#define IMAP_ADDR		((uint)0xff000000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-
-#define PCMCIA_MEM_ADDR		((uint)0xff020000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
-
-/* Bits of interest in the BCSRs.
- */
-#define BCSR1_ETHEN		((uint)0x20000000)
-#define BCSR1_RS232EN_1		((uint)0x01000000)
-#define BCSR1_RS232EN_2		((uint)0x00040000)
-#define BCSR4_ETHLOOP		((uint)0x80000000)	/* EEST Loopback */
-#define BCSR4_EEFDX		((uint)0x40000000)	/* EEST FDX enable */
-#define BCSR4_FETH_EN		((uint)0x08000000)	/* PHY enable */
-#define BCSR4_FETHCFG0		((uint)0x04000000)	/* PHY autoneg mode */
-#define BCSR4_FETHCFG1		((uint)0x00400000)	/* PHY autoneg mode */
-#define BCSR4_FETHFDE		((uint)0x02000000)	/* PHY FDX advertise */
-#define BCSR4_FETHRST		((uint)0x00200000)	/* PHY Reset */
-
-/* Interrupt level assignments.
- */
-#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
-#define PHY_INTERRUPT	SIU_IRQ2	/* PHY link change interrupt */
-
-/* We don't use the 8259.
- */
-#define NR_8259_INTS	0
-
-#endif /* __ASM_FADS_H__ */
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/gemini.h linux-2.4.20-pre2/include/asm-ppc/gemini.h
--- linux-2.4.20-pre1/include/asm-ppc/gemini.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre2/include/asm-ppc/gemini.h	Wed Dec 31 16:00:00 1969
@@ -1,171 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini.h 1.5 05/17/01 18:14:24 cort
- */
-/*
- *  include/asm-ppc/gemini.h
- *
- *
- *  Onboard registers and descriptions for Synergy Microsystems' 
- *  "Gemini" boards.
- *
- */
-#ifdef __KERNEL__
-#ifndef __PPC_GEMINI_H
-#define __PPC_GEMINI_H
-
-/*  Registers  */
-
-#define GEMINI_SERIAL_B     (0xffeffb00)
-#define GEMINI_SERIAL_A     (0xffeffb08)
-#define GEMINI_USWITCH      (0xffeffd00)
-#define GEMINI_BREV         (0xffeffe00)
-#define GEMINI_BECO         (0xffeffe08)
-#define GEMINI_FEAT         (0xffeffe10)
-#define GEMINI_BSTAT        (0xffeffe18)
-#define GEMINI_CPUSTAT      (0xffeffe20)
-#define GEMINI_L2CFG        (0xffeffe30)
-#define GEMINI_MEMCFG       (0xffeffe38)
-#define GEMINI_FLROM        (0xffeffe40)
-#define GEMINI_P0PCI        (0xffeffe48)
-#define GEMINI_FLWIN        (0xffeffe50)
-#define GEMINI_P0INTMASK    (0xffeffe60)
-#define GEMINI_P0INTAP      (0xffeffe68)
-#define GEMINI_PCIERR       (0xffeffe70)
-#define GEMINI_LEDBASE      (0xffeffe80)
-#define GEMINI_RTC          (0xffe9fff8)
-#define GEMINI_LEDS         8
-#define GEMINI_SWITCHES     8
-
-
-/* Flash ROM bit definitions */
-#define GEMINI_FLS_WEN      (1<<0)
-#define GEMINI_FLS_JMP      (1<<6)
-#define GEMINI_FLS_BOOT     (1<<7)
-
-/* Memory bit definitions */
-#define GEMINI_MEM_TYPE_MASK 0xc0
-#define GEMINI_MEM_SIZE_MASK 0x38
-#define GEMINI_MEM_BANK_MASK 0x07
-
-/* L2 cache bit definitions */
-#define GEMINI_L2_SIZE_MASK  0xc0
-#define GEMINI_L2_RATIO_MASK 0x03
-
-/* Timebase register bit definitons */
-#define GEMINI_TIMEB0_EN     (1<<0)
-#define GEMINI_TIMEB1_EN     (1<<1)
-#define GEMINI_TIMEB2_EN     (1<<2)
-#define GEMINI_TIMEB3_EN     (1<<3)
-
-/* CPU status bit definitions */
-#define GEMINI_CPU_ID_MASK   0x03
-#define GEMINI_CPU_COUNT_MASK 0x0c
-#define GEMINI_CPU0_HALTED   (1<<4)
-#define GEMINI_CPU1_HALTED   (1<<5)
-#define GEMINI_CPU2_HALTED   (1<<6)
-#define GEMINI_CPU3_HALTED   (1<<7)
-
-/* Board status bit definitions */
-#define GEMINI_BRD_FAIL      (1<<0)   /* FAIL led is lit */
-#define GEMINI_BRD_BUS_MASK  0x0c     /* PowerPC bus speed */
-
-/* Board family/feature bit descriptions */
-#define GEMINI_FEAT_HAS_FLASH (1<<0)
-#define GEMINI_FEAT_HAS_ETH   (1<<1)
-#define GEMINI_FEAT_HAS_SCSI  (1<<2)
-#define GEMINI_FEAT_HAS_P0    (1<<3)
-#define GEMINI_FEAT_FAM_MASK  0xf0
-
-/* Mod/ECO bit definitions */
-#define GEMINI_ECO_LEVEL_MASK 0x0f
-#define GEMINI_MOD_MASK       0xf0
-
-/* Type/revision bit definitions */
-#define GEMINI_REV_MASK       0x0f
-#define GEMINI_TYPE_MASK      0xf0
-
-/* User switch definitions */
-#define GEMINI_SWITCH_VERBOSE    1     /* adds "debug" to boot cmd line */
-#define GEMINI_SWITCH_SINGLE_USER 7    /* boots into "single-user" mode */
-
-#define SGS_RTC_CONTROL  0
-#define SGS_RTC_SECONDS  1
-#define SGS_RTC_MINUTES  2
-#define SGS_RTC_HOURS    3
-#define SGS_RTC_DAY      4
-#define SGS_RTC_DAY_OF_MONTH 5
-#define SGS_RTC_MONTH    6
-#define SGS_RTC_YEAR     7
-
-#define SGS_RTC_SET  0x80
-#define SGS_RTC_IS_STOPPED 0x80
-
-#define GRACKLE_CONFIG_ADDR_ADDR  (0xfec00000)
-#define GRACKLE_CONFIG_DATA_ADDR  (0xfee00000)
-
-#define GEMINI_BOOT_INIT  (0xfff00100)
-
-#ifndef __ASSEMBLY__
-
-static inline void grackle_write( unsigned long addr, unsigned long data )
-{
-  __asm__ __volatile__(
-  " stwbrx %1, 0, %0\n \
-    sync\n \
-    stwbrx %3, 0, %2\n \
-    sync "
-  : /* no output */
-  : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr),
-    "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data));
-}
-
-static inline unsigned long grackle_read( unsigned long addr )
-{
-  unsigned long val;
-
-  __asm__ __volatile__(
-  " stwbrx %1, 0, %2\n \
-    sync\n \
-    lwbrx %0, 0, %3\n \
-    sync "
-  : "=r" (val)
-  : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR),
-    "r" (GRACKLE_CONFIG_DATA_ADDR));
-
-  return val;
-}
-
-static inline void gemini_led_on( int led )
-{
-  if (led >= 0 && led < GEMINI_LEDS)
-    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1;
-}
-
-static inline void gemini_led_off(int led)
-{
-  if (led >= 0 && led < GEMINI_LEDS)
-    *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0;
-}
-
-static inline int gemini_led_val(int led)
-{
-  int val = 0;
-  if (led >= 0 && led < GEMINI_LEDS)
-    val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3));
-  return (val & 0x1);
-}
-
-/* returns processor id from the board */
-static inline int gemini_processor(void)
-{
-  unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT);
-  return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK));
-}
-
-
-extern void _gemini_reboot(void);
-extern void gemini_prom_init(void);
-extern void gemini_init_l2(void);
-#endif /* __ASSEMBLY__ */
-#endif
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/gemini_serial.h linux-2.4.20-pre2/include/asm-ppc/gemini_serial.h
--- linux-2.4.20-pre1/include/asm-ppc/gemini_serial.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre2/include/asm-ppc/gemini_serial.h	Wed Dec 31 16:00:00 1969
@@ -1,44 +0,0 @@
-/*
- * BK Id: SCCS/s.gemini_serial.h 1.5 05/17/01 18:14:24 cort
- */
-#ifdef __KERNEL__
-#ifndef __ASMPPC_GEMINI_SERIAL_H
-#define __ASMPPC_GEMINI_SERIAL_H
-
-#include <linux/config.h>
-#include <asm/gemini.h>
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE  64
-#else
-#define RS_TABLE_SIZE  4
-#endif
-
-/* Rate for the 24.576 Mhz clock for the onboard serial chip */
-#define BASE_BAUD  (24576000 / 16)
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
-#endif
-
-#define STD_SERIAL_PORT_DEFNS \
-        { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \
-        { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \
-
-#ifdef CONFIG_GEMINI_PU32
-#define PU32_SERIAL_PORT_DEFNS \
-        { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS },
-#else
-#define PU32_SERIAL_PORT_DEFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
-        STD_SERIAL_PORT_DEFNS \
-        PU32_SERIAL_PORT_DEFNS
-
-#endif
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/hw_irq.h linux-2.4.20-pre2/include/asm-ppc/hw_irq.h
--- linux-2.4.20-pre1/include/asm-ppc/hw_irq.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre2/include/asm-ppc/hw_irq.h	Mon Aug 12 16:34:17 2002
@@ -10,7 +10,8 @@
 
 extern unsigned long timer_interrupt_intercept;
 extern unsigned long do_IRQ_intercept;
-int timer_interrupt(struct pt_regs *);
+extern int timer_interrupt(struct pt_regs *);
+extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
 
 extern void __sti(void);
 extern void __cli(void);
diff -urN linux-2.4.20-pre1/include/asm-ppc/i8259.h linux-2.4.20-pre2/include/asm-ppc/i8259.h
--- linux-2.4.20-pre1/include/asm-ppc/i8259.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/asm-ppc/i8259.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,16 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+
+#ifndef _PPC_KERNEL_i8259_H
+#define _PPC_KERNEL_i8259_H
+
+#include <linux/irq.h>
+
+extern struct hw_interrupt_type i8259_pic;
+
+extern void i8259_init(long);
+extern int i8259_irq(void);
+extern int i8259_poll(void);
+
+#endif /* _PPC_KERNEL_i8259_H */
diff -urN linux-2.4.20-pre1/include/asm-ppc/ivms8.h linux-2.4.20-pre2/include/asm-ppc/ivms8.h
--- linux-2.4.20-pre1/include/asm-ppc/ivms8.h	Fri Nov  2 17:43:54 2001
+++ linux-2.4.20-pre2/include/asm-ppc/ivms8.h	Wed Dec 31 16:00:00 1969
@@ -1,59 +0,0 @@
-/*
- * BK Id: SCCS/s.ivms8.h 1.8 10/26/01 10:14:09 trini
- */
-/*
- * Speech Design Integrated Voicemail board specific definitions
- * - IVMS8  (small,  8 channels)
- * - IVML24 (large, 24 channels)
- *
- * In 2.5 when we force a new bootloader, we can merge these two, and add
- * in _MACH_'s for them. -- Tom
- *
- * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de)
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_IVMS8_H__
-#define __ASM_IVMS8_H__
-
-#include <linux/config.h>
-
-#include <asm/ppcboot.h>
-
-#define IVMS_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
-#define IVMS_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
-
-#define IMAP_ADDR	IVMS_IMMR_BASE	/* phys. base address of IMMR area */
-#define IMAP_SIZE	IVMS_IMAP_SIZE	/* mapped size of IMMR area */
-
-#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
-#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
-
-#define FEC_INTERRUPT	 9		/* = SIU_LEVEL4 */
-#define IDE0_INTERRUPT	10		/* = IRQ5 */
-#define CPM_INTERRUPT	11		/* = SIU_LEVEL5 (was: SIU_LEVEL2) */
-#define PHY_INTERRUPT	12		/* = IRQ6 */
-
-/* override the default number of IDE hardware interfaces */
-#define MAX_HWIFS	1
-
-/*
- * Definitions for IDE0 Interface
- */
-#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory */
-#define IDE0_DATA_REG_OFFSET		0x0000
-#define IDE0_ERROR_REG_OFFSET		0x0081
-#define IDE0_NSECTOR_REG_OFFSET		0x0082
-#define IDE0_SECTOR_REG_OFFSET		0x0083
-#define IDE0_LCYL_REG_OFFSET		0x0084
-#define IDE0_HCYL_REG_OFFSET		0x0085
-#define IDE0_SELECT_REG_OFFSET		0x0086
-#define IDE0_STATUS_REG_OFFSET		0x0087
-#define IDE0_CONTROL_REG_OFFSET		0x0106
-#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
-
-/* We don't use the 8259. */
-#define NR_8259_INTS	0
-
-#endif /* __ASM_IVMS8_H__ */
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/kmap_types.h linux-2.4.20-pre2/include/asm-ppc/kmap_types.h
--- linux-2.4.20-pre1/include/asm-ppc/kmap_types.h	Mon Sep 17 13:16:30 2001
+++ linux-2.4.20-pre2/include/asm-ppc/kmap_types.h	Mon Aug 12 16:34:17 2002
@@ -11,6 +11,7 @@
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
+	KM_BH_IRQ,
 	KM_TYPE_NR
 };
 
diff -urN linux-2.4.20-pre1/include/asm-ppc/mbx.h linux-2.4.20-pre2/include/asm-ppc/mbx.h
--- linux-2.4.20-pre1/include/asm-ppc/mbx.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.20-pre2/include/asm-ppc/mbx.h	Wed Dec 31 16:00:00 1969
@@ -1,98 +0,0 @@
-/*
- * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus
- */
-/*
- * A collection of structures, addresses, and values associated with
- * the Motorola MBX boards.  This was originally created for the
- * MBX860, and probably needs revisions for other boards (like the 821).
- * When this file gets out of control, we can split it up into more
- * meaningful pieces.
- *
- * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
- */
-#ifdef __KERNEL__
-#ifndef __MACH_MBX_DEFS
-#define __MACH_MBX_DEFS
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * EPPC-Bug starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_tag;		/* Should be 0x42444944 "BDID" */
-	unsigned int	bi_size;	/* Size of this structure */
-	unsigned int	bi_revision;	/* revision of this structure */
-	unsigned int	bi_bdate;	/* EPPCbug date, i.e. 0x11061997 */
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
-	unsigned int	bi_clun;	/* Boot device controller */
-	unsigned int	bi_dlun;	/* Boot device logical dev */
-
-	/* These fields are not part of the board information structure
-	 * provided by the boot rom.  They are filled in by embed_config.c
-	 * so we have the information consistent with other platforms.
-	 */
-	unsigned char	bi_enetaddr[6];
-	unsigned int	bi_baudrate;
-} bd_t;
-
-/* Memory map for the MBX as configured by EPPC-Bug.  We could reprogram
- * The SIU and PCI bridge, and try to use larger MMU pages, but the
- * performance gain is not measureable and it certainly complicates the
- * generic MMU model.
- *
- * In a effort to minimize memory usage for embedded applications, any
- * PCI driver or ISA driver must request or map the region required by
- * the device.  For convenience (and since we can map up to 4 Mbytes with
- * a single page table page), the MMU initialization will map the
- * NVRAM, Status/Control registers, CPM Dual Port RAM, and the PCI
- * Bridge CSRs 1:1 into the kernel address space.
- */
-#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
-#define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
-#define PCI_IDE_ADDR		((unsigned)0x81000000)
-#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
-#define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
-#define PCMCIA_MEM_ADDR		((uint)0xe0000000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024 * 1024))
-#define PCMCIA_DMA_ADDR		((uint)0xe4000000)
-#define PCMCIA_DMA_SIZE		((uint)(64 * 1024 * 1024))
-#define PCMCIA_ATTRB_ADDR	((uint)0xe8000000)
-#define PCMCIA_ATTRB_SIZE	((uint)(64 * 1024 * 1024))
-#define PCMCIA_IO_ADDR		((uint)0xec000000)
-#define PCMCIA_IO_SIZE		((uint)(64 * 1024 * 1024))
-#define NVRAM_ADDR		((uint)0xfa000000)
-#define NVRAM_SIZE		((uint)(1 * 1024 * 1024))
-#define MBX_CSR_ADDR		((uint)0xfa100000)
-#define MBX_CSR_SIZE		((uint)(1 * 1024 * 1024))
-#define IMAP_ADDR		((uint)0xfa200000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-#define PCI_CSR_ADDR		((uint)0xfa210000)
-#define PCI_CSR_SIZE		((uint)(64 * 1024))
-
-/* Map additional physical space into well known virtual addresses.  Due
- * to virtual address mapping, these physical addresses are not accessible
- * in a 1:1 virtual to physical mapping.
- */
-#define ISA_IO_VIRT_ADDR	((uint)0xfa220000)
-#define ISA_IO_VIRT_SIZE	((uint)64 * 1024)
-
-/* Interrupt assignments.
- * These are defined (and fixed) by the MBX hardware implementation.
- */
-#define POWER_FAIL_INT	SIU_IRQ0	/* Power fail */
-#define TEMP_HILO_INT	SIU_IRQ1	/* Temperature sensor */
-#define QSPAN_INT	SIU_IRQ2	/* PCI Bridge (DMA CTLR?) */
-#define ISA_BRIDGE_INT	SIU_IRQ3	/* All those PC things */
-#define COMM_L_INT	SIU_IRQ6	/* MBX Comm expansion connector pin */
-#define STOP_ABRT_INT	SIU_IRQ7	/* Stop/Abort header pin */
-#endif /* !__ASSEMBLY__ */
-
-/* The MBX uses the 8259.
-*/
-#define NR_8259_INTS	16
-
-#endif
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/mpc8260.h linux-2.4.20-pre2/include/asm-ppc/mpc8260.h
--- linux-2.4.20-pre1/include/asm-ppc/mpc8260.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre2/include/asm-ppc/mpc8260.h	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.mpc8260.h 1.5 05/17/01 18:14:25 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 
 /* This is the single file included by all MPC8260 build options.
@@ -17,7 +17,7 @@
 #ifdef CONFIG_8260
 
 #ifdef CONFIG_EST8260
-#include <asm/est8260.h>
+#include <platforms/est8260.h>
 #endif
 
 /* I don't yet have the ISA or PCI stuff done....no 8260 with
@@ -43,5 +43,5 @@
 		       void *dev_id);
 
 #endif /* CONFIG_8260 */
-#endif
+#endif /* !__CONFIG_8260_DEFS */
 #endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/mpc8xx.h linux-2.4.20-pre2/include/asm-ppc/mpc8xx.h
--- linux-2.4.20-pre1/include/asm-ppc/mpc8xx.h	Fri Nov  2 17:43:54 2001
+++ linux-2.4.20-pre2/include/asm-ppc/mpc8xx.h	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.mpc8xx.h 1.15 11/01/01 12:48:53 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 
 /* This is the single file included by all MPC8xx build options.
@@ -17,40 +17,37 @@
 #ifdef CONFIG_8xx
 
 #ifdef CONFIG_MBX
-#include <asm/mbx.h>
+#include <platforms/mbx.h>
 #endif
 
 #ifdef CONFIG_FADS
-#include <asm/fads.h>
+#include <platforms/fads.h>
 #endif
 
 #ifdef CONFIG_RPXLITE
-#include <asm/rpxlite.h>
+#include <platforms/rpxlite.h>
 #endif
 
 #ifdef CONFIG_BSEIP
-#include <asm/bseip.h>
+#include <platforms/bseip.h>
 #endif
 
 #ifdef CONFIG_RPXCLASSIC
-#include <asm/rpxclassic.h>
+#include <platforms/rpxclassic.h>
 #endif
 
 #if defined(CONFIG_TQM8xxL)
-#include <asm/tqm8xx.h>
+#include <platforms/tqm8xx.h>
 #endif
 
 #if defined(CONFIG_SPD823TS)
-#include <asm/spd8xx.h>
+#include <platforms/spd8xx.h>
 #endif
 
 #if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
-#include <asm/ivms8.h>
+#include <platforms/ivms8.h>
 #endif
 
-/* I need this to get pt_regs.......
-*/
-#include <asm/ptrace.h>
 
 /* Currently, all 8xx boards that support a processor to PCI/ISA bridge
  * use the same memory map.
@@ -83,6 +80,7 @@
  */
 extern unsigned char __res[];
 
+struct pt_regs;
 extern int request_8xxirq(unsigned int irq,
 		       void (*handler)(int, void *, struct pt_regs *),
 		       unsigned long flags, 
@@ -90,5 +88,5 @@
 		       void *dev_id);
 #endif /* !__ASSEMBLY__ */
 #endif /* CONFIG_8xx */
-#endif
+#endif /* __CONFIG_8xx_DEFS */
 #endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/oak.h linux-2.4.20-pre2/include/asm-ppc/oak.h
--- linux-2.4.20-pre1/include/asm-ppc/oak.h	Fri Nov  2 17:43:54 2001
+++ linux-2.4.20-pre2/include/asm-ppc/oak.h	Wed Dec 31 16:00:00 1969
@@ -1,65 +0,0 @@
-/*
- * BK Id: SCCS/s.oak.h 1.12 10/11/01 13:05:07 trini
- */
-/*
- *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oak.h
- *
- *    Description:
- *	Macros, definitions, and data structures specific to the IBM PowerPC
- *      403G{A,B,C,CX} "Oak" evaluation board. Anything specific to the pro-
- *      cessor itself is defined elsewhere.
- *
- */
-
-#ifdef __KERNEL__
-#ifndef	__OAK_H__
-#define	__OAK_H__
-
-#define _IO_BASE	0
-#define _ISA_MEM_BASE	0
-#define PCI_DRAM_OFFSET	0
-
-/* Memory map for the "Oak" evaluation board */
-
-#define	PPC403SPU_IO_BASE      	0x40000000	/* 403 On-chip serial port */
-#define	PPC403SPU_IO_SIZE      	0x00000008
-#define	OAKSERIAL_IO_BASE	0x7E000000	/* NS16550DV serial port */
-#define	OAKSERIAL_IO_SIZE	0x00000008
-#define	OAKNET_IO_BASE		0xF4000000	/* NS83902AV Ethernet */
-#define	OAKNET_IO_SIZE		0x00000040
-#define	OAKPROM_IO_BASE		0xFFFE0000	/* AMD 29F010 Flash ROM */
-#define	OAKPROM_IO_SIZE		0x00020000
-
-
-/* Interrupt assignments fixed by the hardware implementation */
-
-/* This is annoying kbuild-2.4 problem. -- Tom */
-
-#define	PPC403SPU_RX_INT	4	/* AIC_INT4 */
-#define	PPC403SPU_TX_INT	5	/* AIC_INT5 */
-#define	OAKNET_INT		27	/* AIC_INT27 */
-#define	OAKSERIAL_INT		28	/* AIC_INT28 */
-
-#ifndef __ASSEMBLY__
-/*
- * Data structure defining board information maintained by the boot
- * ROM on IBM's "Oak" evaluation board. An effort has been made to
- * keep the field names consistent with the 8xx 'bd_t' board info
- * structures.
- */
-
-typedef struct board_info {
-	unsigned char	 bi_s_version[4];	/* Version of this structure */
-	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
-	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
-	unsigned char	 bi_enetaddr[6];	/* Ethernet MAC address */
-	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	 bi_busfreq;		/* Bus speed, in Hz */
-} bd_t;
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __OAK_H__ */
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/open_pic.h linux-2.4.20-pre2/include/asm-ppc/open_pic.h
--- linux-2.4.20-pre1/include/asm-ppc/open_pic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/asm-ppc/open_pic.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,69 @@
+/*
+ * BK Id: SCCS/s.open_pic.h 1.14 10/11/01 12:09:12 trini
+ */
+/*
+ *  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 _PPC_KERNEL_OPEN_PIC_H
+#define _PPC_KERNEL_OPEN_PIC_H
+
+#include <linux/config.h>
+#include <linux/irq.h>
+
+#define OPENPIC_SIZE	0x40000
+
+/*
+ *  Non-offset'ed vector numbers
+ */
+
+#define OPENPIC_VEC_TIMER	64	/* and up */
+#define OPENPIC_VEC_IPI		72	/* and up */
+#define OPENPIC_VEC_SPURIOUS	127
+
+/* 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 u_int openpic_irq(void);
+extern void openpic_eoi(void);
+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_reset_processor_phys(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 void smp_openpic_message_pass(int target, int msg, unsigned long data,
+				     int wait);
+
+extern inline int openpic_to_irq(int irq)
+{
+	/* IRQ 0 usually means 'disabled'.. don't mess with it 
+	 * exceptions to this (sandpoint maybe?) 
+	 * shouldn't use openpic_to_irq 
+	 */
+	if (irq != 0){
+		return irq += NUM_8259_INTERRUPTS;
+	} else {
+		return 0;
+	}
+}
+/*extern int open_pic_irq_offset;*/
+#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -urN linux-2.4.20-pre1/include/asm-ppc/pci-bridge.h linux-2.4.20-pre2/include/asm-ppc/pci-bridge.h
--- linux-2.4.20-pre1/include/asm-ppc/pci-bridge.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre2/include/asm-ppc/pci-bridge.h	Mon Aug 12 16:34:17 2002
@@ -1,10 +1,13 @@
 /*
- * BK Id: SCCS/s.pci-bridge.h 1.11 05/21/01 01:31:30 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 #ifdef __KERNEL__
 #ifndef _ASM_PCI_BRIDGE_H
 #define _ASM_PCI_BRIDGE_H
 
+#include <linux/ioport.h>
+#include <linux/pci.h>
+
 struct device_node;
 struct pci_controller;
 
@@ -16,6 +19,9 @@
 extern unsigned long pci_bus_io_base_phys(unsigned int bus);
 extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
 
+/* Allocate a new PCI host bridge structure */
+extern struct pci_controller* pcibios_alloc_controller(void);
+
 /*
  * PCI <-> OF matching functions 
  */
@@ -76,5 +82,9 @@
 int early_write_config_word(struct pci_controller *hose, int bus, int dev_fn, int where, u16 val);
 int early_write_config_dword(struct pci_controller *hose, int bus, int dev_fn, int where, u32 val);
 
+extern void setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr,
+		u32 cfg_data);
+extern void setup_grackle(struct pci_controller *hose);
+
 #endif
 #endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/pci.h linux-2.4.20-pre2/include/asm-ppc/pci.h
--- linux-2.4.20-pre1/include/asm-ppc/pci.h	Mon Feb 25 11:38:12 2002
+++ linux-2.4.20-pre2/include/asm-ppc/pci.h	Mon Aug 12 16:34:17 2002
@@ -12,8 +12,13 @@
 #define IOBASE_ISA_IO		3
 #define IOBASE_ISA_MEM		4
 
+/*
+ * Set this to 1 if you want the kernel to re-assign all PCI
+ * bus numbers
+ */
+extern int pci_assign_all_busses;
 
-extern int pcibios_assign_all_busses(void);
+#define pcibios_assign_all_busses()	(pci_assign_all_busses)
 
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
diff -urN linux-2.4.20-pre1/include/asm-ppc/ppc4xx.h linux-2.4.20-pre2/include/asm-ppc/ppc4xx.h
--- linux-2.4.20-pre1/include/asm-ppc/ppc4xx.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre2/include/asm-ppc/ppc4xx.h	Mon Aug 12 16:34:17 2002
@@ -22,22 +22,22 @@
 #ifndef __ASSEMBLY__
 
 #if defined(CONFIG_OAK)
-#include <asm/oak.h>
+#include <platforms/oak.h>
 #endif
 
 #if defined(CONFIG_WALNUT)
-#include <asm/walnut.h>
+#include <platforms/walnut.h>
 #endif
 
 /* IO_BASE is for PCI I/O.
  * ISA not supported, just here to resolve copilation.
  */
 
+#ifndef _IO_BASE
 #define _IO_BASE	0xe8000000	/* The PCI address window */
 #define _ISA_MEM_BASE	0
 #define PCI_DRAM_OFFSET	0
-
-extern unsigned long isa_io_base;
+#endif
 
 /*
  * The "residual" board information structure the boot loader passes
diff -urN linux-2.4.20-pre1/include/asm-ppc/ppc4xx_pic.h linux-2.4.20-pre2/include/asm-ppc/ppc4xx_pic.h
--- linux-2.4.20-pre1/include/asm-ppc/ppc4xx_pic.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/asm-ppc/ppc4xx_pic.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,29 @@
+/*
+ * BK Id: SCCS/s.ppc4xx_pic.h 1.8 06/15/01 13:56:56 paulus
+ */
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: ppc4xx_pic.h
+ *
+ *    Description:
+ *      Interrupt controller driver for PowerPC 4xx-based processors.
+ */
+
+#ifndef	__PPC4XX_PIC_H__
+#define	__PPC4XX_PIC_H__
+
+#include <linux/config.h>
+
+/* External Global Variables */
+
+extern struct hw_interrupt_type *ppc4xx_pic;
+
+
+/* Function Prototypes */
+
+extern void	 ppc4xx_pic_init(void);
+extern int	 ppc4xx_pic_get_irq(struct pt_regs *regs);
+
+#endif /* __PPC4XX_PIC_H__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/ppc_asm.h linux-2.4.20-pre2/include/asm-ppc/ppc_asm.h
--- linux-2.4.20-pre1/include/asm-ppc/ppc_asm.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/asm-ppc/ppc_asm.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,280 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * include/asm-ppc/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>
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base)	stw	n,GPR0+4*(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)	lwz	n,GPR0+4*(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)
+
+/*
+ * Once a version of gas that understands the AltiVec instructions
+ * is freely available, we can do this the normal way...  - paulus
+ */
+#define LVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1)
+#define STVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
+#define MFVSCR(r)	.long	(4<<26)+((r)<<21)+(770<<1)
+#define MTVSCR(r)	.long	(4<<26)+((r)<<11)+(802<<1)
+#define DSSALL		.long	(0x1f<<26)+(0x10<<21)+(0x336<<1)
+
+#define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); STVX(n,b,base)
+#define SAVE_2VR(n,b,base)	SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) 
+#define SAVE_4VR(n,b,base)	SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) 
+#define SAVE_8VR(n,b,base)	SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) 
+#define SAVE_16VR(n,b,base)	SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base)
+#define SAVE_32VR(n,b,base)	SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base)
+#define REST_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); LVX(n,b,base)
+#define REST_2VR(n,b,base)	REST_VR(n,b,base); REST_VR(n+1,b,base) 
+#define REST_4VR(n,b,base)	REST_2VR(n,b,base); REST_2VR(n+2,b,base) 
+#define REST_8VR(n,b,base)	REST_4VR(n,b,base); REST_4VR(n+4,b,base) 
+#define REST_16VR(n,b,base)	REST_8VR(n,b,base); REST_8VR(n+8,b,base) 
+#define REST_32VR(n,b,base)	REST_16VR(n,b,base); REST_16VR(n+16,b,base)
+
+#ifdef CONFIG_PPC601_SYNC_FIX
+#define SYNC				\
+BEGIN_FTR_SECTION			\
+	sync;				\
+	isync;				\
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+#define SYNC_601			\
+BEGIN_FTR_SECTION			\
+	sync;				\
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+#define ISYNC_601			\
+BEGIN_FTR_SECTION			\
+	isync;				\
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+#else
+#define	SYNC
+#define SYNC_601
+#define ISYNC_601
+#endif
+
+#ifndef CONFIG_SMP
+#define TLBSYNC
+#else /* CONFIG_SMP */
+/* tlbsync is not implemented on 601 */
+#define TLBSYNC				\
+BEGIN_FTR_SECTION			\
+	tlbsync;			\
+	sync;				\
+END_FTR_SECTION_IFCLR(CPU_FTR_601)
+#endif
+
+/*
+ * This instruction is not implemented on the PPC 603 or 601; however, on
+ * the 403GCX and 405GP tlbia IS defined and tlbie is not.
+ * All of these instructions exist in the 8xx, they have magical powers,
+ * and they must be used.
+ */
+
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
+#define tlbia					\
+	li	r4,1024;			\
+	mtctr	r4;				\
+	lis	r4,KERNELBASE@h;		\
+0:	tlbie	r4;				\
+	addi	r4,r4,0x1000;			\
+	bdnz	0b
+#endif
+
+/*
+ * On APUS (Amiga PowerPC cpu upgrade board), we don't know the
+ * physical base address of RAM at compile time.
+ */
+#define tophys(rd,rs)				\
+0:	addis	rd,rs,-KERNELBASE@h;		\
+	.section ".vtop_fixup","aw";		\
+	.align  1;				\
+	.long   0b;				\
+	.previous
+
+#define tovirt(rd,rs)				\
+0:	addis	rd,rs,KERNELBASE@h;		\
+	.section ".ptov_fixup","aw";		\
+	.align  1;				\
+	.long   0b;				\
+	.previous
+
+/*
+ * On 64-bit cpus, we use the rfid instruction instead of rfi, but
+ * we then have to make sure we preserve the top 32 bits except for
+ * the 64-bit mode bit, which we clear.
+ */
+#ifdef CONFIG_PPC64BRIDGE
+#define	FIX_SRR1(ra, rb)	\
+	mr	rb,ra;		\
+	mfmsr	ra;		\
+	clrldi	ra,ra,1;		/* turn off 64-bit mode */ \
+	rldimi	ra,rb,0,32
+#define	RFI		.long	0x4c000024	/* rfid instruction */
+#define MTMSRD(r)	.long	(0x7c000164 + ((r) << 21))	/* mtmsrd */
+#define CLR_TOP32(r)	rlwinm	(r),(r),0,0,31	/* clear top 32 bits */
+
+#else
+#define FIX_SRR1(ra, rb)
+#define	RFI		rfi
+#define MTMSRD(r)	mtmsr	r
+#define CLR_TOP32(r)
+#endif /* CONFIG_PPC64BRIDGE */
+
+/* The boring bits... */
+
+/* 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
+
+/* some stab codes */
+#define N_FUN	36
+#define N_RSYM	64
+#define N_SLINE	68
+#define N_SO	100
diff -urN linux-2.4.20-pre1/include/asm-ppc/rpxclassic.h linux-2.4.20-pre2/include/asm-ppc/rpxclassic.h
--- linux-2.4.20-pre1/include/asm-ppc/rpxclassic.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.20-pre2/include/asm-ppc/rpxclassic.h	Wed Dec 31 16:00:00 1969
@@ -1,104 +0,0 @@
-/*
- * BK Id: SCCS/s.rpxclassic.h 1.11 08/17/01 15:23:17 paulus
- */
-
-/*
- * A collection of structures, addresses, and values associated with
- * the RPCG RPX-Classic board.  Copied from the RPX-Lite stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifdef __KERNEL__
-#ifndef __MACH_RPX_DEFS
-#define __MACH_RPX_DEFS
-
-#include <linux/config.h>
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
-	unsigned char	bi_enetaddr[6];
-	unsigned int	bi_baudrate;
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
-/* Memory map is configured by the PROM startup.
- * We just map a few things we need.  The CSR is actually 4 byte-wide
- * registers that can be accessed as 8-, 16-, or 32-bit values.
- */
-#define PCI_ISA_IO_ADDR		((unsigned)0x80000000)
-#define PCI_ISA_IO_SIZE		((uint)(512 * 1024 * 1024))
-#define PCI_ISA_MEM_ADDR	((unsigned)0xc0000000)
-#define PCI_ISA_MEM_SIZE	((uint)(512 * 1024 * 1024))
-#define RPX_CSR_ADDR		((uint)0xfa400000)
-#define RPX_CSR_SIZE		((uint)(4 * 1024))
-#define IMAP_ADDR		((uint)0xfa200000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-#define PCI_CSR_ADDR		((uint)0x80000000)
-#define PCI_CSR_SIZE		((uint)(64 * 1024))
-#define PCMCIA_MEM_ADDR		((uint)0xe0000000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
-#define PCMCIA_IO_ADDR		((uint)0xe4000000)
-#define PCMCIA_IO_SIZE		((uint)(4 * 1024))
-#define PCMCIA_ATTRB_ADDR	((uint)0xe8000000)
-#define PCMCIA_ATTRB_SIZE	((uint)(4 * 1024))
-
-/* Things of interest in the CSR.
-*/
-#define BCSR0_ETHEN		((uint)0x80000000)
-#define BCSR0_ETHLPBK		((uint)0x40000000)
-#define BCSR0_COLTESTDIS	((uint)0x20000000)
-#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
-#define BCSR0_ENFLSHSEL		((uint)0x04000000)
-#define BCSR0_FLASH_SEL		((uint)0x02000000)
-#define BCSR0_ENMONXCVR		((uint)0x01000000)
-
-#define BCSR0_PCMCIAVOLT	((uint)0x000f0000)	/* CLLF */
-#define BCSR0_PCMCIA3VOLT	((uint)0x000a0000)	/* CLLF */
-#define BCSR0_PCMCIA5VOLT	((uint)0x00060000)	/* CLLF */
-
-#define BCSR1_IPB5SEL           ((uint)0x00100000)
-#define BCSR1_PCVCTL4           ((uint)0x00080000)
-#define BCSR1_PCVCTL5           ((uint)0x00040000)
-#define BCSR1_PCVCTL6           ((uint)0x00020000)
-#define BCSR1_PCVCTL7           ((uint)0x00010000)
-
-#define BCSR2_EN232XCVR		((uint)0x00008000)
-#define BCSR2_QSPACESEL		((uint)0x00004000)
-#define BCSR2_FETHLEDMODE	((uint)0x00000800)	/* CLLF */
-
-#if defined(CONFIG_HTDMSOUND)
-#include <asm/rpxhiox.h>
-#endif
-
-/* define IO_BASE for pcmcia, CLLF only */
-#if !defined(CONFIG_PCI)
-#define _IO_BASE 0x80000000
-#define _IO_BASE_SIZE 0x1000
-
-/* for pcmcia sandisk */
-#ifdef CONFIG_IDE
-#define MAX_HWIFS 1
-#define ide_request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
-#endif
-#endif
-
-/* Interrupt level assignments.
-*/
-#define FEC_INTERRUPT	SIU_LEVEL1	/* FEC interrupt */
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/rpxhiox.h linux-2.4.20-pre2/include/asm-ppc/rpxhiox.h
--- linux-2.4.20-pre1/include/asm-ppc/rpxhiox.h	Mon May 21 15:02:06 2001
+++ linux-2.4.20-pre2/include/asm-ppc/rpxhiox.h	Wed Dec 31 16:00:00 1969
@@ -1,45 +0,0 @@
-/*
- * BK Id: SCCS/s.rpxhiox.h 1.3 05/17/01 18:14:25 cort
- */
-
-/*
- * The Embedded Planet HIOX expansion card definitions.
- * There were a few different versions of these cards, but only
- * the one that escaped real production is defined here.
- *
- * Copyright (c) 2000 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_RPX_HIOX_DEFS
-#define __MACH_RPX_HIOX_DEFS
-
-#define HIOX_CSR_ADDR		((uint)0xfac00000)
-#define HIOX_CSR_SIZE		((uint)(4 * 1024))
-#define HIOX_CSR0_ADDR		HIOX_CSR_ADDR
-#define HIOX_CSR4_ADDR		((uint)0xfac00004)
-
-#define HIOX_CSR0_DEFAULT	((uint)0x380f3c00)
-#define HIOX_CSR0_ENSCC2	((uint)0x80000000)
-#define HIOX_CSR0_ENSMC2	((uint)0x04000000)
-#define HIOX_CSR0_ENVDOCLK	((uint)0x02000000)
-#define HIOX_CSR0_VDORST_HL	((uint)0x01000000)
-#define HIOX_CSR0_RS232SEL	((uint)0x0000c000)
-#define HIOX_CSR0_SCC3SEL	((uint)0x0000c000)
-#define HIOX_CSR0_SMC1SEL	((uint)0x00008000)
-#define HIOX_CSR0_SCC1SEL	((uint)0x00004000)
-#define HIOX_CSR0_ENTOUCH	((uint)0x00000080)
-#define HIOX_CSR0_PDOWN100	((uint)0x00000060)
-#define HIOX_CSR0_PDOWN10	((uint)0x00000040)
-#define HIOX_CSR0_PDOWN1	((uint)0x00000020)
-#define HIOX_CSR0_TSELSPI	((uint)0x00000010)
-#define HIOX_CSR0_TIRQSTAT	((uint)0x00000008)
-#define HIOX_CSR4_DEFAULT	((uint)0x00000000)
-#define HIOX_CSR4_ENTIRQ2	((uint)0x20000000)
-#define HIOX_CSR4_ENTIRQ3	((uint)0x10000000)
-#define HIOX_CSR4_ENAUDIO	((uint)0x00000080)
-#define HIOX_CSR4_RSTAUDIO	((uint)0x00000040)	/* 0 == reset */
-#define HIOX_CSR4_AUDCLKHI	((uint)0x00000020)
-#define HIOX_CSR4_AUDSPISEL	((uint)0x00000010)
-#define HIOX_CSR4_AUDIRQSTAT	((uint)0x00000008)
-#define HIOX_CSR4_AUDCLKSEL	((uint)0x00000007)
-
-#endif
diff -urN linux-2.4.20-pre1/include/asm-ppc/rpxlite.h linux-2.4.20-pre2/include/asm-ppc/rpxlite.h
--- linux-2.4.20-pre1/include/asm-ppc/rpxlite.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.20-pre2/include/asm-ppc/rpxlite.h	Wed Dec 31 16:00:00 1969
@@ -1,84 +0,0 @@
-/*
- * BK Id: SCCS/s.rpxlite.h 1.11 08/17/01 15:23:17 paulus
- */
-
-/*
- * A collection of structures, addresses, and values associated with
- * the RPCG RPX-Lite board.  Copied from the MBX stuff.
- *
- * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
- */
-#ifdef __KERNEL__
-#ifndef __MACH_RPX_DEFS
-#define __MACH_RPX_DEFS
-
-#include <linux/config.h>
-
-#ifndef __ASSEMBLY__
-/* A Board Information structure that is given to a program when
- * prom starts it up.
- */
-typedef struct bd_info {
-	unsigned int	bi_memstart;	/* Memory start address */
-	unsigned int	bi_memsize;	/* Memory (end) size in bytes */
-	unsigned int	bi_intfreq;	/* Internal Freq, in Hz */
-	unsigned int	bi_busfreq;	/* Bus Freq, in Hz */
-	unsigned char	bi_enetaddr[6];
-	unsigned int	bi_baudrate;
-} bd_t;
-
-extern bd_t m8xx_board_info;
-
-/* Memory map is configured by the PROM startup.
- * We just map a few things we need.  The CSR is actually 4 byte-wide
- * registers that can be accessed as 8-, 16-, or 32-bit values.
- */
-#define RPX_CSR_ADDR		((uint)0xfa400000)
-#define RPX_CSR_SIZE		((uint)(4 * 1024))
-#define IMAP_ADDR		((uint)0xfa200000)
-#define IMAP_SIZE		((uint)(64 * 1024))
-#define PCMCIA_MEM_ADDR		((uint)0x04000000)
-#define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
-#define PCMCIA_IO_ADDR		((uint)0x04400000)
-#define PCMCIA_IO_SIZE		((uint)(4 * 1024))
-
-/* Things of interest in the CSR.
-*/
-#define BCSR0_ETHEN		((uint)0x80000000)
-#define BCSR0_ETHLPBK		((uint)0x40000000)
-#define BCSR0_COLTESTDIS	((uint)0x20000000)
-#define BCSR0_FULLDPLXDIS	((uint)0x10000000)
-#define BCSR0_LEDOFF		((uint)0x08000000)
-#define BCSR0_USBDISABLE	((uint)0x04000000)
-#define BCSR0_USBHISPEED	((uint)0x02000000)
-#define BCSR0_USBPWREN		((uint)0x01000000)
-#define BCSR0_PCMCIAVOLT	((uint)0x000f0000)
-#define BCSR0_PCMCIA3VOLT	((uint)0x000a0000)
-#define BCSR0_PCMCIA5VOLT	((uint)0x00060000)
-
-#define BCSR1_IPB5SEL          ((uint)0x00100000)
-#define BCSR1_PCVCTL4          ((uint)0x00080000)
-#define BCSR1_PCVCTL5          ((uint)0x00040000)
-#define BCSR1_PCVCTL6          ((uint)0x00020000)
-#define BCSR1_PCVCTL7          ((uint)0x00010000)
-
-#if defined(CONFIG_HTDMSOUND)
-#include <asm/rpxhiox.h>
-#endif
-#endif /* !__ASSEMBLY__ */
-
-/* define IO_BASE for pcmcia */
-#define _IO_BASE 0x80000000
-#define _IO_BASE_SIZE 0x1000
-
-#ifdef CONFIG_IDE
-#define MAX_HWIFS 1
-#define ide_request_irq(irq,hand,flg,dev,id)    request_8xxirq((irq),(hand),(flg),(dev),(id))
-#endif
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/serial.h linux-2.4.20-pre2/include/asm-ppc/serial.h
--- linux-2.4.20-pre1/include/asm-ppc/serial.h	Fri Nov  2 17:43:54 2001
+++ linux-2.4.20-pre2/include/asm-ppc/serial.h	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.serial.h 1.15 10/23/01 08:09:35 trini
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  * include/asm-ppc/serial.h
@@ -11,8 +11,8 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_GEMINI
-#include <asm/gemini_serial.h>
+#if defined(CONFIG_GEMINI)
+#include <platforms/gemini_serial.h>
 #elif defined(CONFIG_4xx)
 #include <asm/ppc4xx_serial.h>
 #else
diff -urN linux-2.4.20-pre1/include/asm-ppc/socket.h linux-2.4.20-pre2/include/asm-ppc/socket.h
--- linux-2.4.20-pre1/include/asm-ppc/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-ppc/socket.h	Mon Aug 12 16:34:17 2002
@@ -12,7 +12,7 @@
 #define SIOCATMARK	0x8905
 #define SIOCGSTAMP	0x8906		/* Get stamp */
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -urN linux-2.4.20-pre1/include/asm-ppc/spd8xx.h linux-2.4.20-pre2/include/asm-ppc/spd8xx.h
--- linux-2.4.20-pre1/include/asm-ppc/spd8xx.h	Fri Nov  2 17:43:54 2001
+++ linux-2.4.20-pre2/include/asm-ppc/spd8xx.h	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-/*
- * BK Id: SCCS/s.spd8xx.h 1.8 10/27/01 13:39:41 trini
- */
-/*
- * Speech Design SPD8xxTS board specific definitions
- * 
- * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_SPD8XX_H__
-#define __ASM_SPD8XX_H__
-
-#include <linux/config.h>
- 
-#include <asm/ppcboot.h>
-
-#define SPD_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
-#define SPD_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
-
-#define IMAP_ADDR	SPD_IMMR_BASE	/* physical base address of IMMR area */
-#define IMAP_SIZE	SPD_IMAP_SIZE	/* mapped size of IMMR area */
-
-#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
-#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
-
-#define IDE0_INTERRUPT	10		/* = IRQ5 */
-#define IDE1_INTERRUPT	12		/* = IRQ6 */
-#define CPM_INTERRUPT	13		/* = SIU_LEVEL6 (was: SIU_LEVEL2) */
-
-/* override the default number of IDE hardware interfaces */
-#define MAX_HWIFS	2
-
-/*
- * Definitions for IDE0 Interface
- */
-#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory */
-#define IDE0_DATA_REG_OFFSET		0x0000
-#define IDE0_ERROR_REG_OFFSET		0x0081
-#define IDE0_NSECTOR_REG_OFFSET		0x0082
-#define IDE0_SECTOR_REG_OFFSET		0x0083
-#define IDE0_LCYL_REG_OFFSET		0x0084
-#define IDE0_HCYL_REG_OFFSET		0x0085
-#define IDE0_SELECT_REG_OFFSET		0x0086
-#define IDE0_STATUS_REG_OFFSET		0x0087
-#define IDE0_CONTROL_REG_OFFSET		0x0106
-#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
-
-/*
- * Definitions for IDE1 Interface
- */
-#define IDE1_BASE_OFFSET		0x0C00	/* Offset in PCMCIA memory */
-#define IDE1_DATA_REG_OFFSET		0x0000
-#define IDE1_ERROR_REG_OFFSET		0x0081
-#define IDE1_NSECTOR_REG_OFFSET		0x0082
-#define IDE1_SECTOR_REG_OFFSET		0x0083
-#define IDE1_LCYL_REG_OFFSET		0x0084
-#define IDE1_HCYL_REG_OFFSET		0x0085
-#define IDE1_SELECT_REG_OFFSET		0x0086
-#define IDE1_STATUS_REG_OFFSET		0x0087
-#define IDE1_CONTROL_REG_OFFSET		0x0106
-#define IDE1_IRQ_REG_OFFSET		0x000A	/* not used */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif /* __ASM_SPD8XX_H__ */
-#endif /* __KERNEL__ */
diff -urN linux-2.4.20-pre1/include/asm-ppc/tqm8xx.h linux-2.4.20-pre2/include/asm-ppc/tqm8xx.h
--- linux-2.4.20-pre1/include/asm-ppc/tqm8xx.h	Sat Sep  8 12:39:33 2001
+++ linux-2.4.20-pre2/include/asm-ppc/tqm8xx.h	Wed Dec 31 16:00:00 1969
@@ -1,54 +0,0 @@
-/*
- * BK Id: SCCS/s.tqm8xx.h 1.8 08/30/01 09:01:04 trini
- */
-/*
- * TQM8xx(L) board specific definitions
- * 
- * Copyright (c) 1999,2000,2001 Wolfgang Denk (wd@denx.de)
- */
-
-#ifndef __MACH_TQM8xx_H
-#define __MACH_TQM8xx_H
-
-#include <linux/config.h>
- 
-#include <asm/ppcboot.h>
-
-#define	TQM_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
-#define	TQM_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
-
-#define	IMAP_ADDR	TQM_IMMR_BASE	/* physical base address of IMMR area */
-#define IMAP_SIZE	TQM_IMAP_SIZE	/* mapped size of IMMR area */
-
-/*-----------------------------------------------------------------------
- * PCMCIA stuff
- *-----------------------------------------------------------------------
- *
- */
-#define PCMCIA_MEM_SIZE		( 64 << 20 )
-
-#define	MAX_HWIFS	1	/* overwrite default in include/asm-ppc/ide.h */
-
-/*
- * Definitions for IDE0 Interface
- */
-#define IDE0_BASE_OFFSET		0
-#define IDE0_DATA_REG_OFFSET		(PCMCIA_MEM_SIZE + 0x320)
-#define IDE0_ERROR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 1)
-#define IDE0_NSECTOR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 2)
-#define IDE0_SECTOR_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 3)
-#define IDE0_LCYL_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 4)
-#define IDE0_HCYL_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 5)
-#define IDE0_SELECT_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 6)
-#define IDE0_STATUS_REG_OFFSET		(2 * PCMCIA_MEM_SIZE + 0x320 + 7)
-#define IDE0_CONTROL_REG_OFFSET		0x0106
-#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used */
-
-#define	IDE0_INTERRUPT			13
-
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-#endif	/* __MACH_TQM8xx_H */
diff -urN linux-2.4.20-pre1/include/asm-ppc/xics.h linux-2.4.20-pre2/include/asm-ppc/xics.h
--- linux-2.4.20-pre1/include/asm-ppc/xics.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/asm-ppc/xics.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,24 @@
+/*
+ * BK Id: SCCS/s.xics.h 1.5 05/17/01 18:14:22 cort
+ */
+/*
+ * 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
+
+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 *);
+
+#endif /* _PPC_KERNEL_XICS_H */
diff -urN linux-2.4.20-pre1/include/asm-s390/irq.h linux-2.4.20-pre2/include/asm-s390/irq.h
--- linux-2.4.20-pre1/include/asm-s390/irq.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390/irq.h	Mon Aug 12 16:34:17 2002
@@ -10,6 +10,7 @@
  */
 #define __MAX_SUBCHANNELS 65536
 #define NR_IRQS           __MAX_SUBCHANNELS
+#define NR_CHPIDS 256
 
 #define LPM_ANYPATH 0xff /* doesn't really belong here, Ingo? */
 
@@ -362,6 +363,92 @@
   /* extended part */
       ciw_t    ciw[MAX_CIWS];      /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
+/*
+ * where we put the ssd info
+ */
+typedef struct _ssd_info {
+	__u8   valid:1;
+	__u8   type:7;          /* subchannel type */
+	__u8   chpid[8];        /* chpids */
+	__u16  fla[8];          /* full link addresses */
+} __attribute__ ((packed)) ssd_info_t;
+
+/*
+ * area for store event information
+ */
+typedef struct chsc_area_t {
+	struct {
+		/* word 0 */
+		__u16 command_code1;
+		__u16 command_code2;
+		union {
+			struct {
+				/* word 1 */
+				__u32 reserved1;
+				/* word 2 */
+				__u32 reserved2;
+			} __attribute__ ((packed,aligned(8))) sei_req;
+			struct {
+				/* word 1 */
+				__u16 reserved1;
+				__u16 f_sch;     /* first subchannel */
+				/* word 2 */
+				__u16 reserved2;
+				__u16 l_sch;    /* last subchannel */
+			} __attribute__ ((packed,aligned(8))) ssd_req;
+		} request_block_data;
+		/* word 3 */
+		__u32 reserved3;
+	} __attribute__ ((packed,aligned(8))) request_block;
+	struct {
+		/* word 0 */
+		__u16 length;
+		__u16 response_code;
+		/* word 1 */
+		__u32 reserved1;
+		union {
+			struct {
+				/* word 2 */
+				__u8  flags;
+				__u8  vf;         /* validity flags */
+				__u8  rs;         /* reporting source */
+				__u8  cc;         /* content code */
+				/* word 3 */
+				__u16 fla;        /* full link address */
+				__u16 rsid;       /* reporting source id */
+				/* word 4 */
+				__u32 reserved2;
+				/* word 5 */
+				__u32 reserved3;
+				/* word 6 */
+				__u32 ccdf;       /* content-code dependent field */
+				/* word 7 */
+				__u32 reserved4;
+				/* word 8 */
+				__u32 reserved5;
+				/* word 9 */
+				__u32 reserved6;
+			} __attribute__ ((packed,aligned(8))) sei_res;
+			struct {
+				/* word 2 */
+				__u8 sch_valid : 1;
+				__u8 dev_valid : 1;
+				__u8 st        : 3; /* subchannel type */
+				__u8 zeroes    : 3;
+				__u8  unit_addr;  /* unit address */
+				__u16 devno;      /* device number */
+				/* word 3 */
+				__u8 path_mask;  
+				__u8 fla_valid_mask;
+				__u16 sch;        /* subchannel */
+				/* words 4-5 */
+				__u8 chpid[8];    /* chpids 0-7 */
+				/* words 6-9 */
+				__u16 fla[8];     /* full link addresses 0-7 */
+			} __attribute__ ((packed,aligned(8))) ssd_res;
+		} response_block_data;
+	} __attribute__ ((packed,aligned(8))) response_block;
+} __attribute__ ((packed,aligned(PAGE_SIZE))) chsc_area_t;
 
 #endif /* __KERNEL__ */
 /*
@@ -409,12 +496,14 @@
 #define DEVSTAT_PCI                0x00000200
 #define DEVSTAT_SUSPENDED          0x00000400
 #define DEVSTAT_UNKNOWN_DEV        0x00000800
+#define DEVSTAT_UNFRIENDLY_DEV     0x00001000
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define DEVINFO_NOT_OPER           DEVSTAT_NOT_OPER
 #define DEVINFO_UNKNOWN_DEV        DEVSTAT_UNKNOWN_DEV
 #define DEVINFO_DEVICE_OWNED       DEVSTAT_DEVICE_OWNED
 #define DEVINFO_QDIO_CAPABLE       0x40000000
+#define DEVINFO_UNFRIENDLY_DEV     DEVSTAT_UNFRIENDLY_DEV
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
 #ifdef __KERNEL__
@@ -491,6 +580,7 @@
                                         /* ... for suspended CCWs */
 #define DOIO_TIMEOUT             0x0080 /* 3 secs. timeout for sync. I/O */
 #define DOIO_DONT_CALL_INTHDLR   0x0100 /* don't call interrupt handler */
+#define DOIO_CANCEL_ON_TIMEOUT   0x0200 /* cancel I/O if it timed out */
 
 /*
  * do_IO()
@@ -562,6 +652,8 @@
 
 int  s390_DevicePathVerification( int irq, __u8 domask );
 
+int s390_trigger_resense(int irq);
+
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
@@ -738,6 +830,21 @@
         return ccode;
 }
 
+extern __inline__ int xsch(int irq)
+{
+	int ccode;
+	
+	__asm__ __volatile__(
+                "   lr    1,%1\n"
+                "   .insn rre,0xb2760000,%1,0\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
+                : "cc", "1" );
+	return ccode;
+}
+
 extern __inline__ int iac( void)
 {
         int ccode;
@@ -800,6 +907,20 @@
                 : "cc" );
         return ccode;
 }
+extern __inline__ int chsc( chsc_area_t * chsc_area)
+{
+	int cc;
+	
+	__asm__ __volatile__ (
+	        ".insn	rre,0xb25f0000,%1,0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc) 
+		: "d" (chsc_area) 
+		: "cc" );
+	
+	return cc;
+}
 
 /*
  * Various low-level irq details needed by irq.c, process.c,
diff -urN linux-2.4.20-pre1/include/asm-s390/pgtable.h linux-2.4.20-pre2/include/asm-s390/pgtable.h
--- linux-2.4.20-pre1/include/asm-s390/pgtable.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390/pgtable.h	Mon Aug 12 16:34:17 2002
@@ -156,7 +156,8 @@
 
 /* Bits in the page table entry */
 #define _PAGE_PRESENT   0x001          /* Software                         */
-#define _PAGE_MKCLEAR   0x002          /* Software                         */
+#define _PAGE_MKCLEAN   0x002          /* Software                         */
+#define _PAGE_ISCLEAN   0x004	       /* Software			   */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
@@ -189,12 +190,14 @@
 /*
  * No mapping available
  */
-#define PAGE_INVALID  __pgprot(_PAGE_INVALID)
-#define PAGE_NONE     __pgprot(_PAGE_PRESENT | _PAGE_INVALID)
-#define PAGE_COPY     __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_SHARED   __pgprot(_PAGE_PRESENT)
-#define PAGE_KERNEL   __pgprot(_PAGE_PRESENT)
+#define PAGE_INVALID	  __pgprot(_PAGE_INVALID)
+#define PAGE_NONE_SHARED  __pgprot(_PAGE_PRESENT|_PAGE_INVALID)
+#define PAGE_NONE_PRIVATE __pgprot(_PAGE_PRESENT|_PAGE_INVALID|_PAGE_ISCLEAN)
+#define PAGE_RO_SHARED	  __pgprot(_PAGE_PRESENT|_PAGE_RO)
+#define PAGE_RO_PRIVATE	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_COPY	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_SHARED	  __pgprot(_PAGE_PRESENT)
+#define PAGE_KERNEL	  __pgprot(_PAGE_PRESENT)
 
 /*
  * The S390 can't do page protection for execute, and considers that the
@@ -202,21 +205,21 @@
  * the closest we can get..
  */
          /*xwr*/
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
+#define __P000  PAGE_NONE_PRIVATE
+#define __P001  PAGE_RO_PRIVATE
 #define __P010  PAGE_COPY
 #define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
+#define __P100  PAGE_RO_PRIVATE
+#define __P101  PAGE_RO_PRIVATE
 #define __P110  PAGE_COPY
 #define __P111  PAGE_COPY
 
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
+#define __S000  PAGE_NONE_SHARED
+#define __S001  PAGE_RO_SHARED
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
+#define __S100  PAGE_RO_SHARED
+#define __S101  PAGE_RO_SHARED
 #define __S110  PAGE_SHARED
 #define __S111  PAGE_SHARED
 
@@ -227,10 +230,10 @@
  */
 extern inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
-	if ((pte_val(pteval) & (_PAGE_MKCLEAR|_PAGE_INVALID))
-	    == _PAGE_MKCLEAR) 
+	if ((pte_val(pteval) & (_PAGE_MKCLEAN|_PAGE_INVALID))
+	    == _PAGE_MKCLEAN) 
 	{
-		pte_val(pteval) &= ~_PAGE_MKCLEAR;
+		pte_val(pteval) &= ~_PAGE_MKCLEAN;
                
 		asm volatile ("sske %0,%1" 
 				: : "d" (0), "a" (pte_val(pteval)));
@@ -277,6 +280,8 @@
 {
 	int skey;
 
+	if (pte_val(pte) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte)));
 	return skey & _PAGE_CHANGED;
 }
@@ -315,7 +320,8 @@
  */
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-	pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot);
+	pte_val(pte) &= PAGE_MASK | _PAGE_ISCLEAN;
+	pte_val(pte) |= pgprot_val(newprot) & ~_PAGE_ISCLEAN;
 	return pte;
 }
 
@@ -342,13 +348,11 @@
 
 extern inline pte_t pte_mkdirty(pte_t pte)
 {
-	/* We can't set the changed bit atomically. For now we
-         * set (!) the page referenced bit. */
-	asm volatile ("sske %0,%1" 
-	              : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
-		          "a" (pte_val(pte)));
-
-	pte_val(pte) &= ~_PAGE_MKCLEAR;
+	/* We do not explicitly set the dirty bit because the
+	 * sske instruction is slow. It is faster to let the
+	 * next instruction set the dirty bit.
+	 */
+	pte_val(pte) &= ~(_PAGE_MKCLEAN | _PAGE_ISCLEAN);
 	return pte;
 }
 
@@ -382,6 +386,8 @@
 {
 	int skey;
 
+	if (pte_val(*ptep) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (*ptep));
 	if ((skey & _PAGE_CHANGED) == 0)
 		return 0;
@@ -414,7 +420,7 @@
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 {
 	pte_t __pte;
 	pte_val(__pte) = physpage + pgprot_val(pgprot);
@@ -424,17 +430,15 @@
 #define mk_pte(pg, pgprot)                                                \
 ({                                                                        \
 	struct page *__page = (pg);                                       \
+	pgprot_t __pgprot = (pgprot);					  \
 	unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);  \
-	pte_t __pte = mk_pte_phys(__physpage, (pgprot));                  \
-	                                                                  \
-	if (__page != ZERO_PAGE(__physpage)) {                            \
-		int __users = page_count(__page);                         \
-		__users -= !!__page->buffers + !!__page->mapping;         \
-	                                                                  \
-		if (__users == 1)                                         \
-			pte_val(__pte) |= _PAGE_MKCLEAR;                  \
-        }                                                                 \
+	pte_t __pte = mk_pte_phys(__physpage, __pgprot);                  \
 	                                                                  \
+	if (!(pgprot_val(__pgprot) & _PAGE_ISCLEAN)) {			  \
+		int __users = !!__page->buffers + !!__page->mapping;      \
+		if (__users + page_count(__page) == 1)                    \
+			pte_val(__pte) |= _PAGE_MKCLEAN;                  \
+	}								  \
 	__pte;                                                            \
 })
 
diff -urN linux-2.4.20-pre1/include/asm-s390/s390_ext.h linux-2.4.20-pre2/include/asm-s390/s390_ext.h
--- linux-2.4.20-pre1/include/asm-s390/s390_ext.h	Tue Feb 13 14:13:44 2001
+++ linux-2.4.20-pre2/include/asm-s390/s390_ext.h	Mon Aug 12 16:34:17 2002
@@ -25,6 +25,10 @@
 extern ext_int_info_t *ext_int_hash[];
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler);
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *info);
 int unregister_external_interrupt(__u16 code, ext_int_handler_t handler);
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *info);
 
 #endif
diff -urN linux-2.4.20-pre1/include/asm-s390/s390io.h linux-2.4.20-pre2/include/asm-s390/s390io.h
--- linux-2.4.20-pre1/include/asm-s390/s390io.h	Wed Apr 11 19:02:28 2001
+++ linux-2.4.20-pre2/include/asm-s390/s390io.h	Mon Aug 12 16:34:17 2002
@@ -18,10 +18,13 @@
 typedef struct _ioinfo {
      unsigned int  irq;           /* aka. subchannel number */
      spinlock_t    irq_lock;      /* irq lock */
+     void          *private_data; /* pointer to private data */
 
      struct _ioinfo *prev;
      struct _ioinfo *next;
 
+     __u8          st;            /* subchannel type */
+
      union {
         unsigned int info;
         struct {
@@ -53,7 +56,8 @@
            unsigned int  newreq    : 1;  /* new register interface */
            unsigned int  dval      : 1;  /* device number valid */
            unsigned int  unknown   : 1;  /* unknown device - if SenseID failed */
-           unsigned int  unused    : (sizeof(unsigned int)*8 - 24); /* unused */
+	   unsigned int  unfriendly: 1;  /* device is locked by someone else */
+           unsigned int  unused    : (sizeof(unsigned int)*8 - 25); /* unused */
               } __attribute__ ((packed)) flags;
         } ui;
 
@@ -75,6 +79,7 @@
      unsigned long qintparm;      /* queued interruption parameter  */
      unsigned long qflag;         /* queued flags */
      __u8          qlpm;          /* queued logical path mask */
+     ssd_info_t    ssd_info;      /* subchannel description */
 
    } __attribute__ ((aligned(8))) ioinfo_t;
 
@@ -89,6 +94,12 @@
 #define IOINFO_FLAGS_REPALL  0x00800000
 
 extern ioinfo_t *ioinfo[];
+int s390_set_private_data(int irq, void * data);
+void * s390_get_private_data(int irq);
+
+#define CHSC_SEI_ACC_CHPID        1
+#define CHSC_SEI_ACC_LINKADDR     2
+#define CHSC_SEI_ACC_FULLLINKADDR 3
 
 #endif  /* __s390io_h */
 
diff -urN linux-2.4.20-pre1/include/asm-s390/s390mach.h linux-2.4.20-pre2/include/asm-s390/s390mach.h
--- linux-2.4.20-pre1/include/asm-s390/s390mach.h	Tue Feb 13 14:13:44 2001
+++ linux-2.4.20-pre2/include/asm-s390/s390mach.h	Mon Aug 12 16:34:17 2002
@@ -13,10 +13,23 @@
 #include <asm/types.h>
 
 typedef struct _mci {
-	__u32	to_be_defined_1 :  9;
-	__u32 cp              :  1; /* channel-report pending */
-	__u32	to_be_defined_2 : 22;
-	__u32	to_be_defined_3;
+	__u32   sd              :  1; /* 00 system damage */
+	__u32   pd              :  1; /* 01 instruction-processing damage */
+	__u32   sr              :  1; /* 02 system recovery */
+	__u32   to_be_defined_1 :  4; /* 03-06 */
+	__u32   dg              :  1; /* 07 degradation */
+	__u32   w               :  1; /* 08 warning pending */
+	__u32   cp              :  1; /* 09 channel-report pending */
+	__u32   to_be_defined_2 :  6; /* 10-15 */
+	__u32   se              :  1; /* 16 storage error uncorrected */
+	__u32   sc              :  1; /* 17 storage error corrected */
+	__u32   ke              :  1; /* 18 storage-key error uncorrected */
+	__u32   ds              :  1; /* 19 storage degradation */
+	__u32	to_be_defined_3 :  4; /* 20-23 */
+	__u32   fa              :  1; /* 24 failing storage address validity */
+	__u32   to_be_defined_4 :  7; /* 25-31 */
+	__u32   ie              :  1; /* 32 indirect storage error */
+	__u32	to_be_defined_5 : 31; /* 33-63 */
 	} mci_t;
 
 //
diff -urN linux-2.4.20-pre1/include/asm-s390/sigp.h linux-2.4.20-pre2/include/asm-s390/sigp.h
--- linux-2.4.20-pre1/include/asm-s390/sigp.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390/sigp.h	Mon Aug 12 16:34:17 2002
@@ -59,9 +59,6 @@
 typedef enum
 {
 	ec_schedule=0,
-        ec_restart,
-        ec_halt,
-        ec_power_off,
 	ec_call_function,
 	ec_bit_last
 } ec_bit_sig;
diff -urN linux-2.4.20-pre1/include/asm-s390/smp.h linux-2.4.20-pre2/include/asm-s390/smp.h
--- linux-2.4.20-pre1/include/asm-s390/smp.h	Thu Oct 11 09:43:38 2001
+++ linux-2.4.20-pre2/include/asm-s390/smp.h	Mon Aug 12 16:34:17 2002
@@ -64,7 +64,5 @@
 
 #define cpu_logical_map(cpu) (cpu)
 
-void smp_local_timer_interrupt(struct pt_regs * regs);
-
 #endif
 #endif
diff -urN linux-2.4.20-pre1/include/asm-s390/socket.h linux-2.4.20-pre2/include/asm-s390/socket.h
--- linux-2.4.20-pre1/include/asm-s390/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-s390/socket.h	Mon Aug 12 16:34:17 2002
@@ -11,7 +11,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -urN linux-2.4.20-pre1/include/asm-s390/system.h linux-2.4.20-pre2/include/asm-s390/system.h
--- linux-2.4.20-pre1/include/asm-s390/system.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390/system.h	Mon Aug 12 16:34:17 2002
@@ -249,6 +249,11 @@
 extern void save_fp_regs(s390_fp_regs *fpregs);
 extern int restore_fp_regs1(s390_fp_regs *fpregs);
 extern void restore_fp_regs(s390_fp_regs *fpregs);
+
+extern void (*_machine_restart)(char *command);
+extern void (*_machine_halt)(void);
+extern void (*_machine_power_off)(void);
+
 #endif
 
 #endif
diff -urN linux-2.4.20-pre1/include/asm-s390x/elf.h linux-2.4.20-pre2/include/asm-s390x/elf.h
--- linux-2.4.20-pre1/include/asm-s390x/elf.h	Wed Apr 11 19:02:29 2001
+++ linux-2.4.20-pre2/include/asm-s390x/elf.h	Mon Aug 12 16:34:17 2002
@@ -77,7 +77,13 @@
 #define ELF_PLATFORM (NULL)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2)			\
+do {							\
+	if (ibcs2)					\
+		set_personality(PER_SVR4);		\
+	else if (current->personality != PER_LINUX32)	\
+		set_personality(PER_LINUX);		\
+} while (0)
 #endif
 
 #endif
diff -urN linux-2.4.20-pre1/include/asm-s390x/irq.h linux-2.4.20-pre2/include/asm-s390x/irq.h
--- linux-2.4.20-pre1/include/asm-s390x/irq.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390x/irq.h	Mon Aug 12 16:34:17 2002
@@ -10,6 +10,7 @@
  */
 #define __MAX_SUBCHANNELS 65536
 #define NR_IRQS           __MAX_SUBCHANNELS
+#define NR_CHPIDS 256
 
 #define LPM_ANYPATH 0xff /* doesn't really belong here, Ingo? */
 
@@ -363,6 +364,93 @@
       ciw_t    ciw[MAX_CIWS];      /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
 
+/*
+ * where we put the ssd info
+ */
+typedef struct _ssd_info {
+	__u8   valid:1;
+	__u8   type:7;          /* subchannel type */
+	__u8   chpid[8];        /* chpids */
+	__u16  fla[8];          /* full link addresses */
+} __attribute__ ((packed)) ssd_info_t;
+
+/*
+ * area for store event information
+ */
+typedef struct chsc_area_t {
+	struct {
+		/* word 0 */
+		__u16 command_code1;
+		__u16 command_code2;
+		union {
+			struct {
+				/* word 1 */
+				__u32 reserved1;
+				/* word 2 */
+				__u32 reserved2;
+			} __attribute__ ((packed,aligned(8))) sei_req;
+			struct {
+				/* word 1 */
+				__u16 reserved1;
+				__u16 f_sch;     /* first subchannel */
+				/* word 2 */
+				__u16 reserved2;
+				__u16 l_sch;    /* last subchannel */
+			} __attribute__ ((packed,aligned(8))) ssd_req;
+		} request_block_data;
+		/* word 3 */
+		__u32 reserved3;
+	} __attribute__ ((packed,aligned(8))) request_block;
+	struct {
+		/* word 0 */
+		__u16 length;
+		__u16 response_code;
+		/* word 1 */
+		__u32 reserved1;
+		union {
+			struct {
+				/* word 2 */
+				__u8  flags;
+				__u8  vf;         /* validity flags */
+				__u8  rs;         /* reporting source */
+				__u8  cc;         /* content code */
+				/* word 3 */
+				__u16 fla;        /* full link address */
+				__u16 rsid;       /* reporting source id */
+				/* word 4 */
+				__u32 reserved2;
+				/* word 5 */
+				__u32 reserved3;
+				/* word 6 */
+				__u32 ccdf;       /* content-code dependent field */
+				/* word 7 */
+				__u32 reserved4;
+				/* word 8 */
+				__u32 reserved5;
+				/* word 9 */
+				__u32 reserved6;
+			} __attribute__ ((packed,aligned(8))) sei_res;
+			struct {
+				/* word 2 */
+				__u8 sch_valid : 1;
+				__u8 dev_valid : 1;
+				__u8 st        : 3; /* subchannel type */
+				__u8 zeroes    : 3;
+				__u8  unit_addr;  /* unit address */
+				__u16 devno;      /* device number */
+				/* word 3 */
+				__u8 path_mask;  
+				__u8 fla_valid_mask;
+				__u16 sch;        /* subchannel */
+				/* words 4-5 */
+				__u8 chpid[8];    /* chpids 0-7 */
+				/* words 6-9 */
+				__u16 fla[8];     /* full link addresses 0-7 */
+			} __attribute__ ((packed,aligned(8))) ssd_res;
+		} response_block_data;
+	} __attribute__ ((packed,aligned(8))) response_block;
+} __attribute__ ((packed,aligned(PAGE_SIZE))) chsc_area_t;
+
 #endif /* __KERNEL__ */
 /*
  * sense data
@@ -409,12 +497,14 @@
 #define DEVSTAT_PCI                0x00000200
 #define DEVSTAT_SUSPENDED          0x00000400
 #define DEVSTAT_UNKNOWN_DEV        0x00000800
+#define DEVSTAT_UNFRIENDLY_DEV     0x00001000
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define DEVINFO_NOT_OPER           DEVSTAT_NOT_OPER
 #define DEVINFO_UNKNOWN_DEV        DEVSTAT_UNKNOWN_DEV
 #define DEVINFO_DEVICE_OWNED       DEVSTAT_DEVICE_OWNED
 #define DEVINFO_QDIO_CAPABLE       0x40000000
+#define DEVINFO_UNFRIENDLY_DEV     DEVSTAT_UNFRIENDLY_DEV
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
 #ifdef __KERNEL__
@@ -491,6 +581,7 @@
                                         /* ... for suspended CCWs */
 #define DOIO_TIMEOUT             0x0080 /* 3 secs. timeout for sync. I/O */
 #define DOIO_DONT_CALL_INTHDLR   0x0100 /* don't call interrupt handler */
+#define DOIO_CANCEL_ON_TIMEOUT   0x0200 /* cancel I/O if it timed out */
 
 /*
  * do_IO()
@@ -562,6 +653,8 @@
 
 int  s390_DevicePathVerification( int irq, __u8 domask );
 
+int s390_trigger_resense(int irq);
+
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
@@ -738,6 +831,21 @@
         return ccode;
 }
 
+extern __inline__ int xsch(int irq)
+{
+	int ccode;
+	
+	__asm__ __volatile__(
+                "   lr    1,%1\n"
+                "   .insn rre,0xb2760000,%1,0\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
+                : "cc", "1" );
+	return ccode;
+}
+
 extern __inline__ int iac( void)
 {
         int ccode;
@@ -801,6 +909,21 @@
         return ccode;
 }
 
+extern __inline__ int chsc( chsc_area_t * chsc_area)
+{
+	int cc;
+	
+	__asm__ __volatile__ (
+	        ".insn	rre,0xb25f0000,%1,0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc) 
+		: "d" (chsc_area) 
+		: "cc" );
+	
+	return cc;
+}
+
 /*
  * Various low-level irq details needed by irq.c, process.c,
  * time.c, io_apic.c and smp.c
diff -urN linux-2.4.20-pre1/include/asm-s390x/lowcore.h linux-2.4.20-pre2/include/asm-s390x/lowcore.h
--- linux-2.4.20-pre1/include/asm-s390x/lowcore.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390x/lowcore.h	Mon Aug 12 16:34:17 2002
@@ -38,6 +38,8 @@
 #define __LC_IO_INT_WORD                0x0C0
 #define __LC_MCCK_CODE                  0x0E8
 
+#define __LC_DIAG44_OPCODE		0x214
+
 #define __LC_SAVE_AREA                  0xC00
 #define __LC_KERNEL_STACK               0xD40
 #define __LC_ASYNC_STACK                0xD48
@@ -146,7 +148,8 @@
 	psw_t        io_new_psw;               /* 0x1f0 */
         psw_t        return_psw;               /* 0x200 */
 	__u32        sync_io_word;             /* 0x210 */
-        __u8         pad8[0xc00-0x214];        /* 0x214 */
+	__u32        diag44_opcode;            /* 0x214 */
+        __u8         pad8[0xc00-0x218];        /* 0x218 */
         /* System info area */
 	__u64        save_area[16];            /* 0xc00 */
         __u8         pad9[0xd40-0xc80];        /* 0xc80 */
diff -urN linux-2.4.20-pre1/include/asm-s390x/page.h linux-2.4.20-pre2/include/asm-s390x/page.h
--- linux-2.4.20-pre1/include/asm-s390x/page.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390x/page.h	Mon Aug 12 16:34:17 2002
@@ -91,13 +91,22 @@
         unsigned long pmd0;
         unsigned long pmd1; 
         } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
+typedef unsigned int pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
 
 #define pte_val(x)      ((x).pte)
 #define pmd_val(x)      ((x).pmd0)
 #define pmd_val1(x)     ((x).pmd1)
-#define pgd_val(x)      ((x).pgd)
+
+static inline unsigned long __pgd_val(pgd_t *pgdp)
+{
+	unsigned long addr = (unsigned long) pgdp;
+	unsigned long *pgd_slot = (unsigned long *) (addr & -8);
+
+	return *pgd_slot + ((addr & 4) << 11);
+}
+#define pgd_val(pgd) __pgd_val(&(pgd))
+
 #define pgprot_val(x)   ((x).pgprot)
 
 #define __pte(x)        ((pte_t) { (x) } )
diff -urN linux-2.4.20-pre1/include/asm-s390x/pgalloc.h linux-2.4.20-pre2/include/asm-s390x/pgalloc.h
--- linux-2.4.20-pre1/include/asm-s390x/pgalloc.h	Wed Jul 25 14:12:02 2001
+++ linux-2.4.20-pre2/include/asm-s390x/pgalloc.h	Mon Aug 12 16:34:17 2002
@@ -16,6 +16,7 @@
 #include <linux/config.h>
 #include <asm/processor.h>
 #include <linux/threads.h>
+#include <linux/slab.h>
 
 #define pgd_quicklist (S390_lowcore.cpu_data.pgd_quick)
 #define pmd_quicklist (S390_lowcore.cpu_data.pmd_quick)
@@ -36,7 +37,7 @@
 	pgd_t *ret;
         int i;
 
-	ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 2);
+	ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 1);
 	if (ret != NULL)
 	        for (i = 0; i < PTRS_PER_PGD; i++) 
 	                pgd_clear(ret + i);
@@ -50,7 +51,7 @@
 	if (ret != NULL) {
 		pgd_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
-		pgtable_cache_size -= 4;
+		pgtable_cache_size -= 2;
 	}
 	return (pgd_t *) ret;
 }
@@ -69,20 +70,17 @@
 {
 	*(unsigned long *) pgd = (unsigned long) pgd_quicklist;
 	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size += 4;
+	pgtable_cache_size += 2;
 }
 
 extern __inline__ void free_pgd_slow (pgd_t *pgd)
 {
-        free_pages((unsigned long) pgd, 2);
+	free_pages((unsigned long) pgd, 1);
 }
 
 #define pgd_free(pgd)		free_pgd_fast(pgd)
 
-extern inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
-{
-	pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd);
-}
+extern pmd_t *pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd);
 
 /*
  * page middle directory allocation/free routines.
@@ -92,7 +90,7 @@
 	pmd_t *pmd;
         int i;
 
-	pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 2);
+	pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 1);
 	if (pmd != NULL) {
 		for (i=0; i < PTRS_PER_PMD; i++)
 			pmd_clear(pmd+i);
@@ -108,21 +106,25 @@
 	if (ret != NULL) {
 		pmd_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
-		pgtable_cache_size -= 4;
+		pgtable_cache_size -= 2;
 	}
 	return (pmd_t *) ret;
 }
 
+extern void pmd_free_order2(pmd_t *);
 extern __inline__ void pmd_free_fast (pmd_t *pmd)
 {
-	*(unsigned long *) pmd = (unsigned long) pmd_quicklist;
-	pmd_quicklist = (unsigned long *) pmd;
-	pgtable_cache_size += 4;
+	if (test_bit(PG_arch_1, &virt_to_page(pmd)->flags) == 0) {
+		*(unsigned long *) pmd = (unsigned long) pmd_quicklist;
+		pmd_quicklist = (unsigned long *) pmd;
+		pgtable_cache_size += 2;
+	} else
+		pmd_free_order2(pmd);
 }
 
 extern __inline__ void pmd_free_slow (pmd_t *pmd)
 {
-	free_pages((unsigned long) pmd, 2);
+	free_pages((unsigned long) pmd, 1);
 }
 
 #define pmd_free(pmd)		pmd_free_fast(pmd)
diff -urN linux-2.4.20-pre1/include/asm-s390x/pgtable.h linux-2.4.20-pre2/include/asm-s390x/pgtable.h
--- linux-2.4.20-pre1/include/asm-s390x/pgtable.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390x/pgtable.h	Mon Aug 12 16:34:17 2002
@@ -63,7 +63,7 @@
 #define PMD_MASK        (~(PMD_SIZE-1))
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT     31
+#define PGDIR_SHIFT     30
 #define PGDIR_SIZE      (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK      (~(PGDIR_SIZE-1))
 
@@ -72,7 +72,7 @@
  * currently we use a 3 level lookup
  */
 #define PTRS_PER_PTE    512
-#define PTRS_PER_PMD    1024
+#define PTRS_PER_PMD    512
 #define PTRS_PER_PGD    2048
 
 /*
@@ -103,7 +103,7 @@
 #define VMALLOC_START   (((unsigned long) high_memory + VMALLOC_OFFSET) \
                          & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END     (0x40000000000L)
+#define VMALLOC_END     (0x20000000000L)
 
 
 /*
@@ -158,23 +158,26 @@
 
 /* Bits in the page table entry */
 #define _PAGE_PRESENT   0x001          /* Software                         */
-#define _PAGE_MKCLEAR   0x002          /* Software                         */
+#define _PAGE_MKCLEAN   0x002          /* Software                         */
+#define _PAGE_ISCLEAN   0x004          /* Software                         */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
 /* Bits in the segment table entry */
-#define _PMD_ENTRY_INV   0x20          /* invalid segment table entry      */
-#define _PMD_ENTRY       0x00        
+#define _PMD_ENTRY_INV	0x20		/* invalid segment table entry      */
+#define _PMD_ENTRY	0x00        
 
 /* Bits in the region third table entry */
-#define _PGD_ENTRY_INV   0x20          /* invalid region table entry       */
-#define _PGD_ENTRY       0x07
+#define _PGD_ENTRY_INV	0x20		/* region table entry invalid bit  */
+#define _PGD_ENTRY_MASK 0x04		/* region third table entry mask   */
+#define _PGD_ENTRY_LEN(x) ((x)&3)       /* region table length bits        */
+#define _PGD_ENTRY_OFF(x) (((x)&3)<<6)  /* region table offset bits        */
 
 /*
  * User and kernel page directory
  */
 #define _REGION_THIRD       0x4
-#define _REGION_THIRD_LEN   0x3 
+#define _REGION_THIRD_LEN   0x1 
 #define _REGION_TABLE       (_REGION_THIRD|_REGION_THIRD_LEN|0x40|0x100)
 #define _KERN_REGION_TABLE  (_REGION_THIRD|_REGION_THIRD_LEN)
 
@@ -185,33 +188,35 @@
 /*
  * No mapping available
  */
-#define PAGE_INVALID    __pgprot(_PAGE_INVALID)
-#define PAGE_NONE       __pgprot(_PAGE_PRESENT | _PAGE_INVALID)
-#define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_SHARED     __pgprot(_PAGE_PRESENT )
-#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT )
+#define PAGE_INVALID	  __pgprot(_PAGE_INVALID)
+#define PAGE_NONE_SHARED  __pgprot(_PAGE_PRESENT|_PAGE_INVALID)
+#define PAGE_NONE_PRIVATE __pgprot(_PAGE_PRESENT|_PAGE_INVALID|_PAGE_ISCLEAN)
+#define PAGE_RO_SHARED	  __pgprot(_PAGE_PRESENT|_PAGE_RO)
+#define PAGE_RO_PRIVATE	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_COPY	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_SHARED	  __pgprot(_PAGE_PRESENT)
+#define PAGE_KERNEL	  __pgprot(_PAGE_PRESENT)
 
 /*
  * The S390 can't do page protection for execute, and considers that the
  * same are read. Also, write permissions imply read permissions. This is
  * the closest we can get..
  */
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
+#define __P000  PAGE_NONE_PRIVATE
+#define __P001  PAGE_RO_PRIVATE
 #define __P010  PAGE_COPY
 #define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
+#define __P100  PAGE_RO_PRIVATE
+#define __P101  PAGE_RO_PRIVATE
 #define __P110  PAGE_COPY
 #define __P111  PAGE_COPY
 
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
+#define __S000  PAGE_NONE_SHARED
+#define __S001  PAGE_RO_SHARED
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
+#define __S100  PAGE_RO_SHARED
+#define __S101  PAGE_RO_SHARED
 #define __S110  PAGE_SHARED
 #define __S111  PAGE_SHARED
 
@@ -222,10 +227,10 @@
  */
 extern inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
-	if ((pte_val(pteval) & (_PAGE_MKCLEAR|_PAGE_INVALID))
-	    == _PAGE_MKCLEAR) 
+	if ((pte_val(pteval) & (_PAGE_MKCLEAN|_PAGE_INVALID))
+	    == _PAGE_MKCLEAN) 
 	{
-		pte_val(pteval) &= ~_PAGE_MKCLEAR;
+		pte_val(pteval) &= ~_PAGE_MKCLEAN;
                
 		asm volatile ("sske %0,%1" 
 				: : "d" (0), "a" (pte_val(pteval)));
@@ -239,20 +244,37 @@
 /*
  * pgd/pmd/pte query functions
  */
-extern inline int pgd_present(pgd_t pgd)
+extern inline int __pgd_present(pgd_t *pgd)
 {
-	return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY;
+	unsigned long addr = (unsigned long) pgd;
+	unsigned long *pgd_slot = (unsigned long *) (addr & -8);
+	unsigned long offset = (addr & 4) >> 1;
+
+	if (*pgd_slot & _PGD_ENTRY_INV)
+		return 0;
+	if ((*pgd_slot & _PGD_ENTRY_OFF(3)) > _PGD_ENTRY_OFF(offset))
+		return 0;
+	if ((*pgd_slot & _PGD_ENTRY_LEN(3)) < _PGD_ENTRY_LEN(offset))
+		return 0;
+	return 1;
 }
+#define pgd_present(pgd) __pgd_present(&(pgd))
 
-extern inline int pgd_none(pgd_t pgd)
+extern inline int __pgd_none(pgd_t *pgd)
 {
-	return pgd_val(pgd) & _PGD_ENTRY_INV;
+	return !__pgd_present(pgd);
 }
+#define pgd_none(pgd) __pgd_none(&(pgd))
 
-extern inline int pgd_bad(pgd_t pgd)
+extern inline int __pgd_bad(pgd_t *pgd)
 {
-	return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY;
+	unsigned long addr = (unsigned long) pgd;
+	unsigned long *pgd_slot = (unsigned long *) (addr & -8);
+
+	return (*pgd_slot & (~PAGE_MASK & ~_PGD_ENTRY_INV & ~_PGD_ENTRY_MASK &
+		             ~_PGD_ENTRY_LEN(3) & ~_PGD_ENTRY_OFF(3))) != 0;
 }
+#define pgd_bad(pgd) __pgd_bad(&(pgd))
 
 extern inline int pmd_present(pmd_t pmd)
 {
@@ -295,6 +317,8 @@
 {
 	int skey;
 
+	if (pte_val(pte) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte)));
 	return skey & _PAGE_CHANGED;
 }
@@ -312,7 +336,27 @@
  */
 extern inline void pgd_clear(pgd_t * pgdp)
 {
-	pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY;
+	unsigned long addr = (unsigned long) pgdp;
+	unsigned long *pgd_slot = (unsigned long *) (addr & -8);
+	unsigned long offset = addr & 4;
+
+	if (*pgd_slot & _PGD_ENTRY_INV) {
+		*pgd_slot = _PGD_ENTRY_INV;
+		return;
+	}
+	if (offset == 0 && (*pgd_slot & _PGD_ENTRY_LEN(2)) != 0) {
+		/* Clear lower pmd, upper pmd still used. */
+		*pgd_slot = (*pgd_slot & PAGE_MASK) | _PGD_ENTRY_MASK |
+			    _PGD_ENTRY_OFF(2) | _PGD_ENTRY_LEN(3);
+		return;
+	}
+	if (offset == 4 && (*pgd_slot & _PGD_ENTRY_OFF(2)) == 0) {
+		/* Clear upped pmd, lower pmd still used. */
+		*pgd_slot = (*pgd_slot & PAGE_MASK) | _PGD_ENTRY_MASK |
+			    _PGD_ENTRY_OFF(0) | _PGD_ENTRY_LEN(1);
+		return;
+	}
+	*pgd_slot = _PGD_ENTRY_INV;
 }
 
 extern inline void pmd_clear(pmd_t * pmdp)
@@ -334,7 +378,8 @@
  */
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-	pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot);
+	pte_val(pte) &= PAGE_MASK | _PAGE_ISCLEAN;
+	pte_val(pte) |= pgprot_val(newprot) & ~_PAGE_ISCLEAN;
 	return pte; 
 }
 
@@ -361,13 +406,11 @@
 
 extern inline pte_t pte_mkdirty(pte_t pte)
 { 
-	/* We can't set the changed bit atomically either. For now we
-         * set (!) the page referenced bit. */
-	asm volatile ("sske %0,%1" 
-	              : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
-		          "a" (pte_val(pte)));
-
-	pte_val(pte) &= ~_PAGE_MKCLEAR;
+	/* We do not explicitly set the dirty bit because the
+	 * sske instruction is slow. It is faster to let the
+	 * next instruction set the dirty bit.
+	 */
+	pte_val(pte) &= ~(_PAGE_MKCLEAN | _PAGE_ISCLEAN);
 	return pte;
 }
 
@@ -401,6 +444,8 @@
 {
 	int skey;
 
+	if (pte_val(*ptep) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (*ptep));
 	if ((skey & _PAGE_CHANGED) == 0)
 		return 0;
@@ -443,17 +488,15 @@
 #define mk_pte(pg, pgprot)                                                \
 ({                                                                        \
 	struct page *__page = (pg);                                       \
+	pgprot_t __pgprot = (pgprot);					  \
 	unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);  \
-	pte_t __pte = mk_pte_phys(__physpage, (pgprot));                  \
-	                                                                  \
-	if (__page != ZERO_PAGE(__physpage)) {                            \
-		int __users = page_count(__page);                         \
-		__users -= !!__page->buffers + !!__page->mapping;         \
-	                                                                  \
-		if (__users == 1)                                         \
-			pte_val(__pte) |= _PAGE_MKCLEAR;                  \
-        }                                                                 \
-	                                                                  \
+	pte_t __pte = mk_pte_phys(__physpage, __pgprot);                  \
+ 	                                                                  \
+	if (!(pgprot_val(__pgprot) & _PAGE_ISCLEAN)) {			  \
+		int __users = !!__page->buffers + !!__page->mapping;      \
+		if (__users + page_count(__page) == 1)                    \
+			pte_val(__pte) |= _PAGE_MKCLEAN;                  \
+	}								  \
 	__pte;                                                            \
 })
 
@@ -466,15 +509,15 @@
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
 #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
 
-#define pgd_page(pmd) \
-        ((unsigned long) __va(pgd_val(pmd) & PAGE_MASK))
+#define pgd_page(pgd) \
+        ((unsigned long) __va(__pgd_val(pgd) & PAGE_MASK))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(dir,addr) \
-	((pmd_t *) pgd_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
+	((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) \
diff -urN linux-2.4.20-pre1/include/asm-s390x/processor.h linux-2.4.20-pre2/include/asm-s390x/processor.h
--- linux-2.4.20-pre1/include/asm-s390x/processor.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390x/processor.h	Mon Aug 12 16:34:17 2002
@@ -16,6 +16,7 @@
 #include <asm/page.h>
 #include <asm/ptrace.h>
 
+#ifdef __KERNEL__
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -59,7 +60,7 @@
 /*
  * User space process size: 4TB (default).
  */
-#define TASK_SIZE       (0x40000000000UL)
+#define TASK_SIZE       (0x20000000000UL)
 #define TASK31_SIZE     (0x80000000UL)
 
 /* This decides where the kernel will search for a free chunk of vm
@@ -155,13 +156,9 @@
 #define KSTK_ESP(tsk)	(__KSTK_PTREGS(tsk)->gprs[15])
 
 /* Allocation and freeing of basic task resources. */
-/*
- * NOTE! The task struct and the stack go together
- */
-#define alloc_task_struct() \
-        ((struct task_struct *) __get_free_pages(GFP_KERNEL,2))
-#define free_task_struct(p)     free_pages((unsigned long)(p),2)
-#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
+extern struct task_struct *alloc_task_struct(void);
+extern void free_task_struct(struct task_struct *tsk);
+extern void get_task_struct(struct task_struct *tsk);
 
 #define init_task       (init_task_union.task)
 #define init_stack      (init_task_union.stack)
@@ -267,5 +264,7 @@
                       : : "a" (dw_psw), "a" (&ctl_buf) : "cc", "0", "1");
 }
 
+#endif
+
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
 
diff -urN linux-2.4.20-pre1/include/asm-s390x/s390_ext.h linux-2.4.20-pre2/include/asm-s390x/s390_ext.h
--- linux-2.4.20-pre1/include/asm-s390x/s390_ext.h	Tue Feb 13 14:13:44 2001
+++ linux-2.4.20-pre2/include/asm-s390x/s390_ext.h	Mon Aug 12 16:34:17 2002
@@ -25,6 +25,10 @@
 extern ext_int_info_t *ext_int_hash[];
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler);
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *info);
 int unregister_external_interrupt(__u16 code, ext_int_handler_t handler);
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *info);
 
 #endif
diff -urN linux-2.4.20-pre1/include/asm-s390x/s390io.h linux-2.4.20-pre2/include/asm-s390x/s390io.h
--- linux-2.4.20-pre1/include/asm-s390x/s390io.h	Wed Apr 11 19:02:29 2001
+++ linux-2.4.20-pre2/include/asm-s390x/s390io.h	Mon Aug 12 16:34:17 2002
@@ -18,10 +18,13 @@
 typedef struct _ioinfo {
      unsigned int  irq;           /* aka. subchannel number */
      spinlock_t    irq_lock;      /* irq lock */
+     void          *private_data; /* pointer to private data */
 
      struct _ioinfo *prev;
      struct _ioinfo *next;
 
+     __u8          st;            /* subchannel type */	
+
      union {
         unsigned int info;
         struct {
@@ -53,7 +56,8 @@
            unsigned int  newreq    : 1;  /* new register interface */
            unsigned int  dval      : 1;  /* device number valid */
            unsigned int  unknown   : 1;  /* unknown device - if SenseID failed */
-           unsigned int  unused    : (sizeof(unsigned int)*8 - 24); /* unused */
+	   unsigned int  unfriendly: 1;  /* device is locked by someone else */
+           unsigned int  unused    : (sizeof(unsigned int)*8 - 25); /* unused */
               } __attribute__ ((packed)) flags;
         } ui;
 
@@ -75,6 +79,7 @@
      unsigned long qintparm;      /* queued interruption parameter  */
      unsigned long qflag;         /* queued flags */
      __u8          qlpm;          /* queued logical path mask */
+     ssd_info_t    ssd_info;      /* subchannel description */
 
    } __attribute__ ((aligned(8))) ioinfo_t;
 
@@ -89,6 +94,12 @@
 #define IOINFO_FLAGS_REPALL  0x00800000
 
 extern ioinfo_t *ioinfo[];
+int s390_set_private_data(int irq, void * data);
+void * s390_get_private_data(int irq);
+
+#define CHSC_SEI_ACC_CHPID        1
+#define CHSC_SEI_ACC_LINKADDR     2
+#define CHSC_SEI_ACC_FULLLINKADDR 3
 
 #endif  /* __s390io_h */
 
diff -urN linux-2.4.20-pre1/include/asm-s390x/s390mach.h linux-2.4.20-pre2/include/asm-s390x/s390mach.h
--- linux-2.4.20-pre1/include/asm-s390x/s390mach.h	Tue Feb 13 14:13:44 2001
+++ linux-2.4.20-pre2/include/asm-s390x/s390mach.h	Mon Aug 12 16:34:17 2002
@@ -13,10 +13,23 @@
 #include <asm/types.h>
 
 typedef struct _mci {
-	__u32	to_be_defined_1 :  9;
-	__u32 cp              :  1; /* channel-report pending */
-	__u32	to_be_defined_2 : 22;
-	__u32	to_be_defined_3;
+	__u32   sd              :  1; /* 00 system damage */
+	__u32   pd              :  1; /* 01 instruction-processing damage */
+	__u32   sr              :  1; /* 02 system recovery */
+	__u32   to_be_defined_1 :  4; /* 03-06 */
+	__u32   dg              :  1; /* 07 degradation */
+	__u32   w               :  1; /* 08 warning pending */
+	__u32   cp              :  1; /* 09 channel-report pending */
+	__u32   to_be_defined_2 :  6; /* 10-15 */
+	__u32   se              :  1; /* 16 storage error uncorrected */
+	__u32   sc              :  1; /* 17 storage error corrected */
+	__u32   ke              :  1; /* 18 storage-key error uncorrected */
+	__u32   ds              :  1; /* 19 storage degradation */
+	__u32	to_be_defined_3 :  4; /* 20-23 */
+	__u32   fa              :  1; /* 24 failing storage address validity */
+	__u32   to_be_defined_4 :  7; /* 25-31 */
+	__u32   ie              :  1; /* 32 indirect storage error */
+	__u32	to_be_defined_5 : 31; /* 33-63 */
 	} mci_t;
 
 //
diff -urN linux-2.4.20-pre1/include/asm-s390x/setup.h linux-2.4.20-pre2/include/asm-s390x/setup.h
--- linux-2.4.20-pre1/include/asm-s390x/setup.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.20-pre2/include/asm-s390x/setup.h	Mon Aug 12 16:34:17 2002
@@ -25,11 +25,12 @@
  */
 extern unsigned long machine_flags;
 
-#define MACHINE_IS_VM    (machine_flags & 1)
-#define MACHINE_IS_P390  (machine_flags & 4)
-#define MACHINE_HAS_MVPG (machine_flags & 16)
+#define MACHINE_IS_VM		(machine_flags & 1)
+#define MACHINE_IS_P390		(machine_flags & 4)
+#define MACHINE_HAS_MVPG	(machine_flags & 16)
+#define MACHINE_HAS_DIAG44	(machine_flags & 32)
 
-#define MACHINE_HAS_HWC  (!MACHINE_IS_P390)
+#define MACHINE_HAS_HWC		(!MACHINE_IS_P390)
 
 /*
  * Console mode. Override with conmode=
diff -urN linux-2.4.20-pre1/include/asm-s390x/sigp.h linux-2.4.20-pre2/include/asm-s390x/sigp.h
--- linux-2.4.20-pre1/include/asm-s390x/sigp.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390x/sigp.h	Mon Aug 12 16:34:17 2002
@@ -59,9 +59,6 @@
 typedef enum
 {
 	ec_schedule=0,
-        ec_restart,
-        ec_halt,
-        ec_power_off,
 	ec_call_function,
 	ec_bit_last
 } ec_bit_sig;
diff -urN linux-2.4.20-pre1/include/asm-s390x/smp.h linux-2.4.20-pre2/include/asm-s390x/smp.h
--- linux-2.4.20-pre1/include/asm-s390x/smp.h	Thu Oct 11 09:43:38 2001
+++ linux-2.4.20-pre2/include/asm-s390x/smp.h	Mon Aug 12 16:34:17 2002
@@ -64,7 +64,5 @@
 
 #define cpu_logical_map(cpu) (cpu)
 
-void smp_local_timer_interrupt(struct pt_regs * regs);
-
 #endif
 #endif
diff -urN linux-2.4.20-pre1/include/asm-s390x/spinlock.h linux-2.4.20-pre2/include/asm-s390x/spinlock.h
--- linux-2.4.20-pre1/include/asm-s390x/spinlock.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390x/spinlock.h	Mon Aug 12 16:34:17 2002
@@ -12,6 +12,20 @@
 #define __ASM_SPINLOCK_H
 
 /*
+ * Grmph, take care of %&#! user space programs that include
+ * asm/spinlock.h. The diagnose is only available in kernel
+ * context.
+ */
+#ifdef __KERNEL__
+#include <asm/lowcore.h>
+#define __DIAG44_INSN "ex"
+#define __DIAG44_OPERAND __LC_DIAG44_OPCODE
+#else
+#define __DIAG44_INSN "#"
+#define __DIAG44_OPERAND 0
+#endif
+
+/*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
  *
@@ -31,12 +45,13 @@
 {
 	unsigned long reg1, reg2;
         __asm__ __volatile("    bras  %1,1f\n"
-                           "0:  # diag  0,0,68\n"
+                           "0:  " __DIAG44_INSN " 0,%3\n"
                            "1:  slr   %0,%0\n"
                            "    cs    %0,%1,0(%2)\n"
                            "    jl    0b\n"
                            : "=&d" (reg1), "=&d" (reg2)
-                           : "a" (&lp->lock) : "cc", "memory" );
+                           : "a" (&lp->lock), "i" (__DIAG44_OPERAND)
+			   : "cc", "memory" );
 }
 
 extern inline int spin_trylock(spinlock_t *lp)
@@ -79,40 +94,44 @@
 #define read_lock(rw)   \
         asm volatile("   lg    2,0(%0)\n"   \
                      "   j     1f\n"     \
-                     "0: # diag  0,0,68\n" \
+                     "0: " __DIAG44_INSN " 0,%1\n" \
                      "1: nihh  2,0x7fff\n" /* clear high (=write) bit */ \
                      "   la    3,1(2)\n"   /* one more reader */  \
                      "   csg   2,3,0(%0)\n" /* try to write new value */ \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" )
+                     : : "a" (&(rw)->lock), "i" (__DIAG44_OPERAND) \
+		     : "2", "3", "cc", "memory" )
 
 #define read_unlock(rw) \
         asm volatile("   lg    2,0(%0)\n"   \
                      "   j     1f\n"     \
-                     "0: # diag  0,0,68\n" \
+                     "0: " __DIAG44_INSN " 0,%1\n" \
                      "1: lgr   3,2\n"    \
                      "   bctgr 3,0\n"    /* one less reader */ \
                      "   csg   2,3,0(%0)\n" \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" )
+                     : : "a" (&(rw)->lock), "i" (__DIAG44_OPERAND) \
+		     : "2", "3", "cc", "memory" )
 
 #define write_lock(rw) \
         asm volatile("   llihh 3,0x8000\n" /* new lock value = 0x80...0 */ \
                      "   j     1f\n"       \
-                     "0: # diag  0,0,68\n"   \
+                     "0: " __DIAG44_INSN " 0,%1\n"   \
                      "1: slgr  2,2\n"      /* old lock value must be 0 */ \
                      "   csg   2,3,0(%0)\n" \
                      "   jl    0b"         \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" )
+                     : : "a" (&(rw)->lock), "i" (__DIAG44_OPERAND) \
+		     : "2", "3", "cc", "memory" )
 
 #define write_unlock(rw) \
         asm volatile("   slgr  3,3\n"      /* new lock value = 0 */ \
                      "   j     1f\n"       \
-                     "0: # diag  0,0,68\n"   \
+                     "0: " __DIAG44_INSN " 0,%1\n"   \
                      "1: llihh 2,0x8000\n" /* old lock value must be 0x8..0 */\
                      "   csg   2,3,0(%0)\n"   \
                      "   jl    0b"         \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" )
+                     : : "a" (&(rw)->lock), "i" (__DIAG44_OPERAND) \
+		     : "2", "3", "cc", "memory" )
 
 #endif /* __ASM_SPINLOCK_H */
 
diff -urN linux-2.4.20-pre1/include/asm-s390x/system.h linux-2.4.20-pre2/include/asm-s390x/system.h
--- linux-2.4.20-pre1/include/asm-s390x/system.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/asm-s390x/system.h	Mon Aug 12 16:34:17 2002
@@ -253,12 +253,17 @@
 #endif
 
 #ifdef __KERNEL__
-extern struct task_struct *resume(void *,void *);
+extern struct task_struct *resume(void *, void *);
 
 extern int save_fp_regs1(s390_fp_regs *fpregs);
 extern void save_fp_regs(s390_fp_regs *fpregs);
 extern int restore_fp_regs1(s390_fp_regs *fpregs);
 extern void restore_fp_regs(s390_fp_regs *fpregs);
+
+extern void (*_machine_restart)(char *command);
+extern void (*_machine_halt)(void);
+extern void (*_machine_power_off)(void);
+
 #endif
 
 #endif
diff -urN linux-2.4.20-pre1/include/asm-sh/pgtable-2level.h linux-2.4.20-pre2/include/asm-sh/pgtable-2level.h
--- linux-2.4.20-pre1/include/asm-sh/pgtable-2level.h	Sat Sep  8 12:29:09 2001
+++ linux-2.4.20-pre2/include/asm-sh/pgtable-2level.h	Mon Aug 12 16:34:17 2002
@@ -42,7 +42,7 @@
  */
 #define set_pte(pteptr, pteval) (*(pteptr) = pteval)
 /*
- * (pmds are folded into pgds so this doesnt get actually called,
+ * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
  */
 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
diff -urN linux-2.4.20-pre1/include/asm-sh/socket.h linux-2.4.20-pre2/include/asm-sh/socket.h
--- linux-2.4.20-pre1/include/asm-sh/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-sh/socket.h	Mon Aug 12 16:34:17 2002
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -urN linux-2.4.20-pre1/include/asm-sparc/highmem.h linux-2.4.20-pre2/include/asm-sparc/highmem.h
--- linux-2.4.20-pre1/include/asm-sparc/highmem.h	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/include/asm-sparc/highmem.h	Mon Aug 12 16:34:17 2002
@@ -36,8 +36,10 @@
 extern pgprot_t kmap_prot;
 extern pte_t *pkmap_page_table;
 
-/* these two get calculated in arch/sparc/mm/srmmu.c */
+/* This gets set in {srmmu,sun4c}_paging_init() */
 extern unsigned long fix_kmap_begin;
+
+/* Only used and set with srmmu? */
 extern unsigned long pkmap_base;
 
 extern void kmap_init(void) __init;
diff -urN linux-2.4.20-pre1/include/asm-sparc/kmap_types.h linux-2.4.20-pre2/include/asm-sparc/kmap_types.h
--- linux-2.4.20-pre1/include/asm-sparc/kmap_types.h	Mon Sep 17 13:16:30 2001
+++ linux-2.4.20-pre2/include/asm-sparc/kmap_types.h	Mon Aug 12 16:34:17 2002
@@ -7,6 +7,7 @@
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
+	KM_BH_IRQ,
 	KM_TYPE_NR
 };
 
diff -urN linux-2.4.20-pre1/include/asm-sparc/socket.h linux-2.4.20-pre2/include/asm-sparc/socket.h
--- linux-2.4.20-pre1/include/asm-sparc/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-sparc/socket.h	Mon Aug 12 16:34:17 2002
@@ -4,7 +4,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	0xffff
 
 #define SO_DEBUG	0x0001
diff -urN linux-2.4.20-pre1/include/asm-sparc64/socket.h linux-2.4.20-pre2/include/asm-sparc64/socket.h
--- linux-2.4.20-pre1/include/asm-sparc64/socket.h	Wed Jun 20 21:00:55 2001
+++ linux-2.4.20-pre2/include/asm-sparc64/socket.h	Mon Aug 12 16:34:17 2002
@@ -4,7 +4,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	0xffff
 
 #define SO_DEBUG	0x0001
diff -urN linux-2.4.20-pre1/include/linux/blkdev.h linux-2.4.20-pre2/include/linux/blkdev.h
--- linux-2.4.20-pre1/include/linux/blkdev.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/blkdev.h	Mon Aug 12 16:34:17 2002
@@ -7,6 +7,8 @@
 #include <linux/tqueue.h>
 #include <linux/list.h>
 
+#include <asm/io.h>
+
 struct request_queue;
 typedef struct request_queue request_queue_t;
 struct elevator_s;
@@ -36,7 +38,7 @@
 	unsigned long hard_sector, hard_nr_sectors;
 	unsigned int nr_segments;
 	unsigned int nr_hw_segments;
-	unsigned long current_nr_sectors;
+	unsigned long current_nr_sectors, hard_cur_sectors;
 	void * special;
 	char * buffer;
 	struct completion * waiting;
@@ -123,6 +125,8 @@
 	 */
 	char			head_active;
 
+	unsigned long		bounce_pfn;
+
 	/*
 	 * Is meant to protect the queue in the future instead of
 	 * io_request_lock
@@ -135,6 +139,38 @@
 	wait_queue_head_t	wait_for_requests[2];
 };
 
+extern unsigned long blk_max_low_pfn, blk_max_pfn;
+
+#define BLK_BOUNCE_HIGH		(blk_max_low_pfn << PAGE_SHIFT)
+#define BLK_BOUNCE_ANY		(blk_max_pfn << PAGE_SHIFT)
+
+extern void blk_queue_bounce_limit(request_queue_t *, u64);
+
+#ifdef CONFIG_HIGHMEM
+extern struct buffer_head *create_bounce(int, struct buffer_head *);
+extern inline struct buffer_head *blk_queue_bounce(request_queue_t *q, int rw,
+						   struct buffer_head *bh)
+{
+	struct page *page = bh->b_page;
+
+#ifndef CONFIG_DISCONTIGMEM
+	if (page - mem_map <= q->bounce_pfn)
+#else
+	if ((page - page_zone(page)->zone_mem_map) + (page_zone(page)->zone_start_paddr >> PAGE_SHIFT) <= q->bounce_pfn)
+#endif
+		return bh;
+
+	return create_bounce(rw, bh);
+}
+#else
+#define blk_queue_bounce(q, rw, bh)	(bh)
+#endif
+
+#define bh_phys(bh)		(page_to_phys((bh)->b_page) + bh_offset((bh)))
+
+#define BH_CONTIG(b1, b2)	(bh_phys((b1)) + (b1)->b_size == bh_phys((b2)))
+#define BH_PHYS_4G(b1, b2)	((bh_phys((b1)) | 0xffffffff) == ((bh_phys((b2)) + (b2)->b_size - 1) | 0xffffffff))
+
 struct blk_dev_struct {
 	/*
 	 * queue_proc has to be atomic
@@ -174,6 +210,7 @@
 extern void blk_queue_headactive(request_queue_t *, int);
 extern void blk_queue_make_request(request_queue_t *, make_request_fn *);
 extern void generic_unplug_device(void *);
+extern inline int blk_seg_merge_ok(struct buffer_head *, struct buffer_head *);
 
 extern int * blk_size[MAX_BLKDEV];
 
diff -urN linux-2.4.20-pre1/include/linux/bootmem.h linux-2.4.20-pre2/include/linux/bootmem.h
--- linux-2.4.20-pre1/include/linux/bootmem.h	Thu Nov 22 11:47:23 2001
+++ linux-2.4.20-pre2/include/linux/bootmem.h	Mon Aug 12 16:34:17 2002
@@ -16,6 +16,7 @@
 
 extern unsigned long max_low_pfn;
 extern unsigned long min_low_pfn;
+extern unsigned long max_pfn;
 
 /*
  * node_bootmem_map is a map pointer - the bits represent all physical 
diff -urN linux-2.4.20-pre1/include/linux/brlock.h linux-2.4.20-pre2/include/linux/brlock.h
--- linux-2.4.20-pre1/include/linux/brlock.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.20-pre2/include/linux/brlock.h	Mon Aug 12 16:34:17 2002
@@ -19,7 +19,7 @@
  *
  *                 David S. Miller <davem@redhat.com>
  *
- * David has an implementation that doesnt use atomic operations in
+ * David has an implementation that doesn't use atomic operations in
  * the read branch via memory ordering tricks - i guess we need to
  * split this up into a per-arch thing? The atomicity issue is a
  * secondary item in profiles, at least on x86 platforms.
diff -urN linux-2.4.20-pre1/include/linux/genhd.h linux-2.4.20-pre2/include/linux/genhd.h
--- linux-2.4.20-pre1/include/linux/genhd.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/genhd.h	Mon Aug 12 16:34:17 2002
@@ -62,8 +62,8 @@
 	unsigned long start_sect;
 	unsigned long nr_sects;
 	devfs_handle_t de;              /* primary (master) devfs entry  */
-	int number;                     /* stupid old code wastes space  */
 
+#ifdef CONFIG_BLK_STATS
 	/* Performance stats: */
 	unsigned int ios_in_flight;
 	unsigned int io_ticks;
@@ -79,6 +79,7 @@
 	unsigned int wr_merges;
 	unsigned int wr_ticks;
 	unsigned int wr_sectors;	
+#endif /* CONFIG_BLK_STATS */
 };
 
 #define GENHD_FL_REMOVABLE  1
@@ -259,18 +260,22 @@
 
 char *disk_name (struct gendisk *hd, int minor, char *buf);
 
-/*
- * disk_round_stats is used to round off the IO statistics for a disk
- * for a complete clock tick.
- */
-void disk_round_stats(struct hd_struct *hd);
-
 /* 
  * Account for the completion of an IO request (used by drivers which 
  * bypass the normal end_request processing) 
  */
 struct request;
-void req_finished_io(struct request *);
+
+#ifdef CONFIG_BLK_STATS
+extern void disk_round_stats(struct hd_struct *hd);
+extern void req_new_io(struct request *req, int merge, int sectors);
+extern void req_merged_io(struct request *req);
+extern void req_finished_io(struct request *req);
+#else
+static inline void req_new_io(struct request *req, int merge, int sectors) { }
+static inline void req_merged_io(struct request *req) { }
+static inline void req_finished_io(struct request *req) { }
+#endif /* CONFIG_BLK_STATS */
 
 extern void devfs_register_partitions (struct gendisk *dev, int minor,
 				       int unregister);
diff -urN linux-2.4.20-pre1/include/linux/highmem.h linux-2.4.20-pre2/include/linux/highmem.h
--- linux-2.4.20-pre1/include/linux/highmem.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/highmem.h	Mon Aug 12 16:34:17 2002
@@ -13,8 +13,7 @@
 /* declarations for linux/mm/highmem.c */
 unsigned int nr_free_highpages(void);
 
-extern struct buffer_head * create_bounce(int rw, struct buffer_head * bh_orig);
-
+extern struct buffer_head *create_bounce(int rw, struct buffer_head * bh_orig);
 
 static inline char *bh_kmap(struct buffer_head *bh)
 {
@@ -26,6 +25,42 @@
 	kunmap(bh->b_page);
 }
 
+/*
+ * remember to add offset! and never ever reenable interrupts between a
+ * bh_kmap_irq and bh_kunmap_irq!!
+ */
+static inline char *bh_kmap_irq(struct buffer_head *bh, unsigned long *flags)
+{
+	unsigned long addr;
+
+	__save_flags(*flags);
+
+	/*
+	 * could be low
+	 */
+	if (!PageHighMem(bh->b_page))
+		return bh->b_data;
+
+	/*
+	 * it's a highmem page
+	 */
+	__cli();
+	addr = (unsigned long) kmap_atomic(bh->b_page, KM_BH_IRQ);
+
+	if (addr & ~PAGE_MASK)
+		BUG();
+
+	return (char *) addr + bh_offset(bh);
+}
+
+static inline void bh_kunmap_irq(char *buffer, unsigned long *flags)
+{
+	unsigned long ptr = (unsigned long) buffer & PAGE_MASK;
+
+	kunmap_atomic((void *) ptr, KM_BH_IRQ);
+	__restore_flags(*flags);
+}
+
 #else /* CONFIG_HIGHMEM */
 
 static inline unsigned int nr_free_highpages(void) { return 0; }
@@ -37,8 +72,10 @@
 #define kmap_atomic(page,idx)		kmap(page)
 #define kunmap_atomic(page,idx)		kunmap(page)
 
-#define bh_kmap(bh)	((bh)->b_data)
-#define bh_kunmap(bh)	do { } while (0)
+#define bh_kmap(bh)			((bh)->b_data)
+#define bh_kunmap(bh)			do { } while (0)
+#define bh_kmap_irq(bh, flags)		((bh)->b_data)
+#define bh_kunmap_irq(bh, flags)	do { *(flags) = 0; } while (0)
 
 #endif /* CONFIG_HIGHMEM */
 
diff -urN linux-2.4.20-pre1/include/linux/ide.h linux-2.4.20-pre2/include/linux/ide.h
--- linux-2.4.20-pre1/include/linux/ide.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/ide.h	Mon Aug 12 16:34:17 2002
@@ -552,6 +552,7 @@
 	unsigned	reset      : 1;	/* reset after probe */
 	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
 	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
+	unsigned	no_highio  : 1; /* don't trust pci dma mask, bounce */
 	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	struct pci_dev	*pci_dev;	/* for pci chipsets */
@@ -874,6 +875,21 @@
 } ide_action_t;
 
 /*
+ * temporarily mapping a (possible) highmem bio
+ */
+#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
+
+extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
+{
+	return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq);
+}
+
+extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
+{
+	bh_kunmap_irq(buffer, flags);
+}
+
+/*
  * This function issues a special IDE device request
  * onto the request queue.
  *
diff -urN linux-2.4.20-pre1/include/linux/if_ether.h linux-2.4.20-pre2/include/linux/if_ether.h
--- linux-2.4.20-pre1/include/linux/if_ether.h	Tue Oct 30 15:08:12 2001
+++ linux-2.4.20-pre2/include/linux/if_ether.h	Mon Aug 12 16:34:17 2002
@@ -95,6 +95,6 @@
 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
 	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
 	unsigned short	h_proto;		/* packet type ID field	*/
-};
+} __attribute__((packed));
 
 #endif	/* _LINUX_IF_ETHER_H */
diff -urN linux-2.4.20-pre1/include/linux/iobuf.h linux-2.4.20-pre2/include/linux/iobuf.h
--- linux-2.4.20-pre1/include/linux/iobuf.h	Thu Nov 22 11:46:26 2001
+++ linux-2.4.20-pre2/include/linux/iobuf.h	Mon Aug 12 16:34:17 2002
@@ -37,19 +37,11 @@
 	int		offset;		/* Offset to start of valid data */
 	int		length;		/* Number of valid bytes of data */
 
-	/* Keep separate track of the physical addresses and page
-	 * structs involved.  If we do IO to a memory-mapped device
-	 * region, there won't necessarily be page structs defined for
-	 * every address. */
-
-	struct page **	maplist;
-
 	unsigned int	locked : 1;	/* If set, pages has been locked */
-	
-	/* Always embed enough struct pages for atomic IO */
-	struct page *	map_array[KIO_STATIC_PAGES];
-	struct buffer_head * bh[KIO_MAX_SECTORS];
-	unsigned long blocks[KIO_MAX_SECTORS];
+
+	struct page **  maplist;
+	struct buffer_head ** bh;
+	unsigned long * blocks;
 
 	/* Dynamic state for IO completion: */
 	atomic_t	io_count;	/* IOs still in progress */
diff -urN linux-2.4.20-pre1/include/linux/irda.h linux-2.4.20-pre2/include/linux/irda.h
--- linux-2.4.20-pre1/include/linux/irda.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.20-pre2/include/linux/irda.h	Mon Aug 12 16:34:17 2002
@@ -67,6 +67,9 @@
 	IRDA_AIRPORT_DONGLE      = 6,
 	IRDA_OLD_BELKIN_DONGLE   = 7,
 	IRDA_EP7211_IR           = 8,
+	IRDA_MCP2120_DONGLE      = 9,
+	IRDA_ACT200L_DONGLE      = 10,
+	IRDA_MA600_DONGLE        = 11,
 } IRDA_DONGLE;
 
 /* Protocol types to be used for SOCK_DGRAM */
diff -urN linux-2.4.20-pre1/include/linux/kernel.h linux-2.4.20-pre2/include/linux/kernel.h
--- linux-2.4.20-pre1/include/linux/kernel.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/kernel.h	Mon Aug 12 16:34:17 2002
@@ -12,6 +12,7 @@
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/compiler.h>
+#include <asm/byteorder.h>
 
 /* Optimization barrier */
 /* The "volatile" is due to gcc bugs */
@@ -107,6 +108,8 @@
 extern int tainted;
 extern const char *print_tainted(void);
 
+extern void dump_stack(void);
+
 #if DEBUG
 #define pr_debug(fmt,arg...) \
 	printk(KERN_DEBUG fmt,##arg)
@@ -128,11 +131,17 @@
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[3]
 
+#if defined(__LITTLE_ENDIAN)
 #define HIPQUAD(addr) \
 	((unsigned char *)&addr)[3], \
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[1], \
 	((unsigned char *)&addr)[0]
+#elif defined(__BIG_ENDIAN)
+#define HIPQUAD	NIPQUAD
+#else
+#error "Please fix asm/byteorder.h"
+#endif /* __LITTLE_ENDIAN */
 
 /*
  * min()/max() macros that also do
diff -urN linux-2.4.20-pre1/include/linux/mmzone.h linux-2.4.20-pre2/include/linux/mmzone.h
--- linux-2.4.20-pre1/include/linux/mmzone.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/mmzone.h	Mon Aug 12 16:34:17 2002
@@ -158,6 +158,60 @@
 
 extern pg_data_t contig_page_data;
 
+/**
+ * for_each_pgdat - helper macro to iterate over all nodes
+ * @pgdat - pg_data_t * variable
+ *
+ * Meant to help with common loops of the form
+ * pgdat = pgdat_list;
+ * while(pgdat) {
+ * 	...
+ * 	pgdat = pgdat->node_next;
+ * }
+ */
+#define for_each_pgdat(pgdat) \
+	for (pgdat = pgdat_list; pgdat; pgdat = pgdat->node_next)
+
+
+/*
+ * next_zone - helper magic for for_each_zone()
+ * Thanks to William Lee Irwin III for this piece of ingenuity.
+ */
+static inline zone_t *next_zone(zone_t *zone)
+{
+	pg_data_t *pgdat = zone->zone_pgdat;
+
+	if (zone - pgdat->node_zones < MAX_NR_ZONES - 1)
+		zone++;
+
+	else if (pgdat->node_next) {
+		pgdat = pgdat->node_next;
+		zone = pgdat->node_zones;
+	} else
+		zone = NULL;
+
+	return zone;
+}
+
+/**
+ * for_each_zone - helper macro to iterate over all memory zones
+ * @zone - zone_t * variable
+ *
+ * The user only needs to declare the zone variable, for_each_zone
+ * fills it in. This basically means for_each_zone() is an
+ * easier to read version of this piece of code:
+ *
+ * for(pgdat = pgdat_list; pgdat; pgdat = pgdat->node_next)
+ * 	for(i = 0; i < MAX_NR_ZONES; ++i) {
+ * 		zone_t * z = pgdat->node_zones + i;
+ * 		...
+ * 	}
+ * }
+ */
+#define for_each_zone(zone) \
+	for(zone = pgdat_list->node_zones; zone; zone = next_zone(zone))
+
+
 #ifndef CONFIG_DISCONTIGMEM
 
 #define NODE_DATA(nid)		(&contig_page_data)
diff -urN linux-2.4.20-pre1/include/linux/netdevice.h linux-2.4.20-pre2/include/linux/netdevice.h
--- linux-2.4.20-pre1/include/linux/netdevice.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/netdevice.h	Mon Aug 12 16:34:17 2002
@@ -162,7 +162,7 @@
 	unsigned fastroute_deferred_out;
 	unsigned fastroute_latency_reduction;
 	unsigned cpu_collision;
-} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+} ____cacheline_aligned;
 
 extern struct netif_rx_stats netdev_rx_stat[];
 
@@ -206,7 +206,8 @@
 	__LINK_STATE_START,
 	__LINK_STATE_PRESENT,
 	__LINK_STATE_SCHED,
-	__LINK_STATE_NOCARRIER
+	__LINK_STATE_NOCARRIER,
+	__LINK_STATE_RX_SCHED
 };
 
 
@@ -330,6 +331,10 @@
 	void                    *ip6_ptr;       /* IPv6 specific data */
 	void			*ec_ptr;	/* Econet specific data	*/
 
+	struct list_head	poll_list;	/* Link to poll list	*/
+	int			quota;
+	int			weight;
+
 	struct Qdisc		*qdisc;
 	struct Qdisc		*qdisc_sleeping;
 	struct Qdisc		*qdisc_list;
@@ -373,6 +378,8 @@
 	int			(*stop)(struct net_device *dev);
 	int			(*hard_start_xmit) (struct sk_buff *skb,
 						    struct net_device *dev);
+#define HAVE_NETDEV_POLL
+	int			(*poll) (struct net_device *dev, int *quota);
 	int			(*hard_header) (struct sk_buff *skb,
 						struct net_device *dev,
 						unsigned short type,
@@ -492,9 +499,12 @@
 	int			cng_level;
 	int			avg_blog;
 	struct sk_buff_head	input_pkt_queue;
+	struct list_head	poll_list;
 	struct net_device	*output_queue;
 	struct sk_buff		*completion_queue;
-} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+
+	struct net_device	blog_dev;	/* Sorry. 8) */
+} ____cacheline_aligned;
 
 
 extern struct softnet_data softnet_data[NR_CPUS];
@@ -547,6 +557,7 @@
 	return test_bit(__LINK_STATE_START, &dev->state);
 }
 
+
 /* Use this variant when it is known for sure that it
  * is executing from interrupt context.
  */
@@ -578,6 +589,8 @@
 extern void		net_call_rx_atomic(void (*fn)(void));
 #define HAVE_NETIF_RX 1
 extern int		netif_rx(struct sk_buff *skb);
+#define HAVE_NETIF_RECEIVE_SKB 1
+extern int		netif_receive_skb(struct sk_buff *skb);
 extern int		dev_ioctl(unsigned int cmd, void *);
 extern int		dev_change_flags(struct net_device *, unsigned);
 extern void		dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
@@ -699,6 +712,78 @@
 #define netif_msg_hw(p)		((p)->msg_enable & NETIF_MSG_HW)
 #define netif_msg_wol(p)	((p)->msg_enable & NETIF_MSG_WOL)
 
+/* Schedule rx intr now? */
+
+static inline int netif_rx_schedule_prep(struct net_device *dev)
+{
+	return netif_running(dev) &&
+		!test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+/* Add interface to tail of rx poll list. This assumes that _prep has
+ * already been called and returned 1.
+ */
+
+static inline void __netif_rx_schedule(struct net_device *dev)
+{
+	unsigned long flags;
+	int cpu = smp_processor_id();
+
+	local_irq_save(flags);
+	dev_hold(dev);
+	list_add_tail(&dev->poll_list, &softnet_data[cpu].poll_list);
+	if (dev->quota < 0)
+		dev->quota += dev->weight;
+	else
+		dev->quota = dev->weight;
+	__cpu_raise_softirq(cpu, NET_RX_SOFTIRQ);
+	local_irq_restore(flags);
+}
+
+/* Try to reschedule poll. Called by irq handler. */
+
+static inline void netif_rx_schedule(struct net_device *dev)
+{
+	if (netif_rx_schedule_prep(dev))
+		__netif_rx_schedule(dev);
+}
+
+/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete().
+ * Do not inline this?
+ */
+static inline int netif_rx_reschedule(struct net_device *dev, int undo)
+{
+	if (netif_rx_schedule_prep(dev)) {
+		unsigned long flags;
+		int cpu = smp_processor_id();
+
+		dev->quota += undo;
+
+		local_irq_save(flags);
+		list_add_tail(&dev->poll_list, &softnet_data[cpu].poll_list);
+		__cpu_raise_softirq(cpu, NET_RX_SOFTIRQ);
+		local_irq_restore(flags);
+		return 1;
+	}
+	return 0;
+}
+
+/* Remove interface from poll list: it must be in the poll list
+ * on current cpu. This primitive is called by dev->poll(), when
+ * it completes the work. The device cannot be out of poll list at this
+ * moment, it is BUG().
+ */
+static inline void netif_rx_complete(struct net_device *dev)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) BUG();
+	list_del(&dev->poll_list);
+	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+	local_irq_restore(flags);
+}
+
 /* These functions live elsewhere (drivers/net/net_init.c, but related) */
 
 extern void		ether_setup(struct net_device *dev);
@@ -723,6 +808,7 @@
 extern int		netdev_register_fc(struct net_device *dev, void (*stimul)(struct net_device *dev));
 extern void		netdev_unregister_fc(int bit);
 extern int		netdev_max_backlog;
+extern int		weight_p;
 extern unsigned long	netdev_fc_xoff;
 extern atomic_t netdev_dropping;
 extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack.h	Mon Aug 12 16:34:17 2002
@@ -6,6 +6,7 @@
 
 #include <linux/config.h>
 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <asm/atomic.h>
 
 enum ip_conntrack_info
 {
@@ -42,12 +43,57 @@
 	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
 };
 
+#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
+
+/* per conntrack: protocol private data */
+union ip_conntrack_proto {
+	/* insert conntrack proto private data here */
+	struct ip_ct_tcp tcp;
+	struct ip_ct_icmp icmp;
+};
+
+union ip_conntrack_expect_proto {
+	/* insert expect proto private data here */
+};
+
+/* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+
+/* per expectation: application helper private data */
+union ip_conntrack_expect_help {
+	/* insert conntrack helper private data (expect) here */
+	struct ip_ct_ftp_expect exp_ftp_info;
+	struct ip_ct_irc_expect exp_irc_info;
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+	union {
+		/* insert nat helper private data (expect) here */
+	} nat;
+#endif
+};
+
+/* per conntrack: application helper private data */
+union ip_conntrack_help {
+	/* insert conntrack helper private data (master) here */
+	struct ip_ct_ftp_master ct_ftp_info;
+	struct ip_ct_irc_master ct_irc_info;
+};
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+#include <linux/netfilter_ipv4/ip_nat.h>
+
+/* per conntrack: nat application helper private data */
+union ip_conntrack_nat_help {
+	/* insert nat helper private data here */
+};
+#endif
+
 #ifdef __KERNEL__
 
 #include <linux/types.h>
 #include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
 
 #ifdef CONFIG_NF_DEBUG
 #define IP_NF_ASSERT(x)							\
@@ -64,26 +110,45 @@
 
 struct ip_conntrack_expect
 {
-	/* Internal linked list */
+	/* Internal linked list (global expectation list) */
 	struct list_head list;
 
+	/* reference count */
+	atomic_t use;
+
+	/* expectation list for this master */
+	struct list_head expected_list;
+
+	/* The conntrack of the master connection */
+	struct ip_conntrack *expectant;
+
+	/* The conntrack of the sibling connection, set after
+	 * expectation arrived */
+	struct ip_conntrack *sibling;
+
+	/* Tuple saved for conntrack */
+	struct ip_conntrack_tuple ct_tuple;
+
+	/* Timer function; deletes the expectation. */
+	struct timer_list timeout;
+
+	/* Data filled out by the conntrack helpers follow: */
+
 	/* We expect this tuple, with the following mask */
 	struct ip_conntrack_tuple tuple, mask;
 
 	/* Function to call after setup and insertion */
 	int (*expectfn)(struct ip_conntrack *new);
 
-	/* The conntrack we are part of (set iff we're live) */
-	struct ip_conntrack *expectant;
-};
+	/* At which sequence number did this expectation occur */
+	u_int32_t seq;
+  
+	union ip_conntrack_expect_proto proto;
 
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-#include <linux/netfilter_ipv4/ip_nat.h>
-#endif
-
-#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+	union ip_conntrack_expect_help help;
+};
 
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 struct ip_conntrack
 {
 	/* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
@@ -101,10 +166,13 @@
 
 	/* If we're expecting another related connection, this will be
            in expected linked list */
-	struct ip_conntrack_expect expected;
+	struct list_head sibling_list;
+	
+	/* Current number of expected connections */
+	unsigned int expecting;
 
-	/* If we were expected by another connection, this will be it */
-	struct nf_ct_info master;
+	/* If we were expected by an expectation, this will be it */
+	struct ip_conntrack_expect *master;
 
 	/* Helper, if any. */
 	struct ip_conntrack_helper *helper;
@@ -115,22 +183,14 @@
 
 	/* Storage reserved for other modules: */
 
-	union {
-		struct ip_ct_tcp tcp;
-		struct ip_ct_icmp icmp;
-	} proto;
+	union ip_conntrack_proto proto;
 
-	union {
-		struct ip_ct_ftp ct_ftp_info;
-		struct ip_ct_irc ct_irc_info;
-	} help;
+	union ip_conntrack_help help;
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
 	struct {
 		struct ip_nat_info info;
-		union {
-			/* insert nat helper private data here */
-		} help;
+		union ip_conntrack_nat_help help;
 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
 	defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
 		int masq_index;
@@ -140,6 +200,9 @@
 
 };
 
+/* get master conntrack via master expectation */
+#define master_ct(conntr) (conntr->master ? conntr->master->expectant : NULL)
+
 /* Alter reply tuple (maybe alter helper).  If it's already taken,
    return 0 and don't do alteration. */
 extern int
@@ -156,6 +219,16 @@
 extern struct ip_conntrack *
 ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo);
 
+/* decrement reference count on a conntrack */
+extern inline void ip_conntrack_put(struct ip_conntrack *ct);
+
+/* find unconfirmed expectation based on tuple */
+struct ip_conntrack_expect *
+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple);
+
+/* decrement reference count on an expectation */
+void ip_conntrack_expect_put(struct ip_conntrack_expect *exp);
+
 extern struct module *ip_conntrack_module;
 
 extern int invert_tuplepr(struct ip_conntrack_tuple *inverse,
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_core.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_core.h	Fri Apr 27 14:15:01 2001
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_core.h	Mon Aug 12 16:34:17 2002
@@ -15,7 +15,7 @@
 extern void ip_conntrack_cleanup(void);
 
 struct ip_conntrack_protocol;
-extern struct ip_conntrack_protocol *find_proto(u_int8_t protocol);
+extern struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol);
 /* Like above, but you already have conntrack read lock. */
 extern struct ip_conntrack_protocol *__find_proto(u_int8_t protocol);
 extern struct list_head protocol_list;
@@ -45,7 +45,7 @@
 }
 
 extern struct list_head *ip_conntrack_hash;
-extern struct list_head expect_list;
+extern struct list_head ip_conntrack_expect_list;
 DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
 #endif /* _IP_CONNTRACK_CORE_H */
 
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_ftp.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Wed Apr 25 15:00:28 2001
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Mon Aug 12 16:34:17 2002
@@ -2,15 +2,17 @@
 #define _IP_CONNTRACK_FTP_H
 /* FTP tracking. */
 
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
+#ifdef __KERNEL__
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
 /* Protects ftp part of conntracks */
 DECLARE_LOCK_EXTERN(ip_ftp_lock);
 
+#define FTP_PORT	21
+
+#endif /* __KERNEL__ */
+
 enum ip_ct_ftp_type
 {
 	/* PORT command from client */
@@ -23,18 +25,20 @@
 	IP_CT_FTP_EPSV,
 };
 
-/* We record seq number and length of ftp ip/port text here: all in
-   host order. */
-struct ip_ct_ftp
+/* This structure is per expected connection */
+struct ip_ct_ftp_expect
 {
-	/* This tells NAT that this is an ftp connection */
-	int is_ftp;
-	u_int32_t seq;
-	/* 0 means not found yet */
-	u_int32_t len;
-	enum ip_ct_ftp_type ftptype;
-	/* Port that was to be used */
-	u_int16_t port;
+	/* We record seq number and length of ftp ip/port text here: all in
+	 * host order. */
+
+ 	/* sequence number of IP address in packet is in ip_conntrack_expect */
+	u_int32_t len;			/* length of IP address */
+	enum ip_ct_ftp_type ftptype;	/* PORT or PASV ? */
+	u_int16_t port; 		/* TCP port that was to be used */
+};
+
+/* This structure exists only once per master */
+struct ip_ct_ftp_master {
 	/* Next valid seq position for cmd matching after newline */
 	u_int32_t seq_aft_nl[IP_CT_DIR_MAX];
 	/* 0 means seq_match_aft_nl not set */
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_helper.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_helper.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_helper.h	Mon Dec 11 13:31:23 2000
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_helper.h	Mon Aug 12 16:34:17 2002
@@ -5,10 +5,19 @@
 
 struct module;
 
+/* Reuse expectation when max_expected reached */
+#define IP_CT_HELPER_F_REUSE_EXPECT	0x01
+
 struct ip_conntrack_helper
 {	
-	/* Internal use. */
-	struct list_head list;
+	struct list_head list; 		/* Internal use. */
+
+	const char *name;		/* name of the module */
+	unsigned char flags;		/* Flags (see above) */
+	struct module *me;		/* pointer to self */
+	unsigned int max_expected;	/* Maximum number of concurrent 
+					 * expected connections */
+	unsigned int timeout;		/* timeout for expecteds */
 
 	/* Mask of things we will help (compared against server response) */
 	struct ip_conntrack_tuple tuple;
@@ -24,11 +33,13 @@
 extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
 extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
 
-/* Add an expected connection: can only have one per connection */
+extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
+
+/* Add an expected connection: can have more than one per connection */
 extern int ip_conntrack_expect_related(struct ip_conntrack *related_to,
-				       const struct ip_conntrack_tuple *tuple,
-				       const struct ip_conntrack_tuple *mask,
-				       int (*expectfn)(struct ip_conntrack *));
-extern void ip_conntrack_unexpect_related(struct ip_conntrack *related_to);
+				       struct ip_conntrack_expect *exp);
+extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
+				      struct ip_conntrack_tuple *newtuple);
+extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
 
 #endif /*_IP_CONNTRACK_HELPER_H*/
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_irc.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_irc.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Tue Oct 30 15:08:12 2001
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Mon Aug 12 16:34:17 2002
@@ -14,13 +14,28 @@
 #ifndef _IP_CONNTRACK_IRC_H
 #define _IP_CONNTRACK_IRC_H
 
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
+/* We record seq number and length of irc ip/port text here: all in
+   host order. */
+
+/* This structure is per expected connection */
+struct ip_ct_irc_expect
+{
+	/* length of IP address */
+	u_int32_t len;
+	/* Port that was to be used */
+	u_int16_t port;
+};
+
+/* This structure exists only once per master */
+struct ip_ct_irc_master {
+};
+
+
+#ifdef __KERNEL__
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
-#define IP_CONNTR_IRC	2
+#define IRC_PORT	6667
 
 struct dccproto {
 	char* match;
@@ -30,18 +45,6 @@
 /* Protects irc part of conntracks */
 DECLARE_LOCK_EXTERN(ip_irc_lock);
 
-/* We record seq number and length of irc ip/port text here: all in
-   host order. */
-struct ip_ct_irc
-{
-	/* This tells NAT that this is an IRC connection */
-	int is_irc;
-	/* sequence number where address part of DCC command begins */
-	u_int32_t seq;
-	/* 0 means not found yet */
-	u_int32_t len;
-	/* Port that was to be used */
-	u_int16_t port;
-};
+#endif /* __KERNEL__ */
 
 #endif /* _IP_CONNTRACK_IRC_H */
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Mon Aug 12 16:34:17 2002
@@ -45,6 +45,10 @@
 	/* Called when a conntrack entry is destroyed */
 	void (*destroy)(struct ip_conntrack *conntrack);
 
+	/* Has to decide if a expectation matches one packet or not */
+	int (*exp_matches_pkt)(struct ip_conntrack_expect *exp,
+			       struct sk_buff **pskb);
+
 	/* Module (if any) which this is connected to. */
 	struct module *me;
 };
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_tcp.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	Fri Aug  4 13:07:24 2000
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	Mon Aug 12 16:34:17 2002
@@ -2,10 +2,6 @@
 #define _IP_CONNTRACK_TCP_H
 /* TCP tracking. */
 
-#ifndef __KERNEL__
-#error Only in kernel.
-#endif
-
 enum tcp_conntrack {
 	TCP_CONNTRACK_NONE,
 	TCP_CONNTRACK_ESTABLISHED,
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_nat.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_nat.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_nat.h	Mon Aug 12 16:34:17 2002
@@ -60,22 +60,6 @@
 	struct ip_nat_range range[1];
 };
 
-#ifdef __KERNEL__
-#include <linux/list.h>
-#include <linux/netfilter_ipv4/lockhelp.h>
-
-/* Protects NAT hash tables, and NAT-private part of conntracks. */
-DECLARE_RWLOCK_EXTERN(ip_nat_lock);
-
-/* Hashes for by-source and IP/protocol. */
-struct ip_nat_hash
-{
-	struct list_head list;
-
-	/* conntrack we're embedded in: NULL if not in hash. */
-	struct ip_conntrack *conntrack;
-};
-
 /* Worst case: local-out manip + 1 post-routing, and reverse dirn. */
 #define IP_NAT_MAX_MANIPS (2*3)
 
@@ -93,7 +77,23 @@
 	/* Manipulations to occur at each conntrack in this dirn. */
 	struct ip_conntrack_manip manip;
 };
-	
+
+#ifdef __KERNEL__
+#include <linux/list.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+/* Protects NAT hash tables, and NAT-private part of conntracks. */
+DECLARE_RWLOCK_EXTERN(ip_nat_lock);
+
+/* Hashes for by-source and IP/protocol. */
+struct ip_nat_hash
+{
+	struct list_head list;
+
+	/* conntrack we're embedded in: NULL if not in hash. */
+	struct ip_conntrack *conntrack;
+};
+
 /* The structure embedded in the conntrack structure. */
 struct ip_nat_info
 {
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_nat_helper.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_nat_helper.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_nat_helper.h	Wed Apr 25 15:00:28 2001
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_nat_helper.h	Mon Aug 12 16:34:17 2002
@@ -6,23 +6,37 @@
 
 struct sk_buff;
 
+/* Flags */
+/* NAT helper must be called on every packet (for TCP) */
+#define IP_NAT_HELPER_F_ALWAYS		0x01
+/* Standalone NAT helper, without a conntrack part */
+#define IP_NAT_HELPER_F_STANDALONE	0x02
+
 struct ip_nat_helper
 {
-	/* Internal use */
-	struct list_head list;
+	struct list_head list;		/* Internal use */
 
+	const char *name;		/* name of the module */
+	unsigned char flags;		/* Flags (see above) */
+	struct module *me;		/* pointer to self */
+	
 	/* Mask of things we will help: vs. tuple from server */
 	struct ip_conntrack_tuple tuple;
 	struct ip_conntrack_tuple mask;
 	
 	/* Helper function: returns verdict */
 	unsigned int (*help)(struct ip_conntrack *ct,
+			     struct ip_conntrack_expect *exp,
 			     struct ip_nat_info *info,
 			     enum ip_conntrack_info ctinfo,
 			     unsigned int hooknum,
 			     struct sk_buff **pskb);
 
-	const char *name;
+	/* Returns verdict and sets up NAT for this connection */
+	unsigned int (*expect)(struct sk_buff **pskb,
+			       unsigned int hooknum,
+			       struct ip_conntrack *ct,
+			       struct ip_nat_info *info);
 };
 
 extern struct list_head helpers;
@@ -39,5 +53,5 @@
 extern int ip_nat_seq_adjust(struct sk_buff *skb,
 				struct ip_conntrack *ct,
 				enum ip_conntrack_info ctinfo);
-extern void ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph);
+extern void ip_nat_delete_sack(struct sk_buff *skb);
 #endif
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_nat_rule.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_nat_rule.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ip_nat_rule.h	Mon Dec 11 13:31:32 2000
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ip_nat_rule.h	Mon Aug 12 16:34:17 2002
@@ -5,24 +5,7 @@
 #include <linux/netfilter_ipv4/ip_nat.h>
 
 #ifdef __KERNEL__
-/* Want to be told when we first NAT an expected packet for a conntrack? */
-struct ip_nat_expect
-{
-	struct list_head list;
 
-	/* Returns 1 (and sets verdict) if it has setup NAT for this
-           connection */
-	int (*expect)(struct sk_buff **pskb,
-		      unsigned int hooknum,
-		      struct ip_conntrack *ct,
-		      struct ip_nat_info *info,
-		      struct ip_conntrack *master,
-		      struct ip_nat_info *masterinfo,
-		      unsigned int *verdict);
-};
-
-extern int ip_nat_expect_register(struct ip_nat_expect *expect);
-extern void ip_nat_expect_unregister(struct ip_nat_expect *expect);
 extern int ip_nat_rule_init(void) __init;
 extern void ip_nat_rule_cleanup(void);
 extern int ip_nat_rule_find(struct sk_buff **pskb,
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_DSCP.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_DSCP.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_DSCP.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_DSCP.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,20 @@
+/* iptables module for setting the IPv4 DSCP field
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * ipt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
+*/
+#ifndef _IPT_DSCP_TARGET_H
+#define _IPT_DSCP_TARGET_H
+#include <linux/netfilter_ipv4/ipt_dscp.h>
+
+/* target info */
+struct ipt_DSCP_info {
+	u_int8_t dscp;
+};
+
+#endif /* _IPT_DSCP_TARGET_H */
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_ECN.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_ECN.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_ECN.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_ECN.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,31 @@
+/* Header file for iptables ipt_ECN target
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ECN.h,v 1.3 2002/05/29 12:17:40 laforge Exp
+*/
+#ifndef _IPT_ECN_TARGET_H
+#define _IPT_ECN_TARGET_H
+#include <linux/netfilter_ipv4/ipt_DSCP.h>
+
+#define IPT_ECN_IP_MASK	(~IPT_DSCP_MASK)
+
+#define IPT_ECN_OP_SET_IP	0x01	/* set ECN bits of IPv4 header */
+#define IPT_ECN_OP_SET_ECE	0x10	/* set ECE bit of TCP header */
+#define IPT_ECN_OP_SET_CWR	0x20	/* set CWR bit of TCP header */
+
+#define IPT_ECN_OP_MASK		0xce
+
+struct ipt_ECN_info {
+	u_int8_t operation;	/* bitset of operations */
+	u_int8_t ip_ect;	/* ECT codepoint of IPv4 header, pre-shifted */
+	union {
+		struct {
+			u_int8_t ece:1, cwr:1; /* TCP ECT bits */
+		} tcp;
+	} proto;
+};
+
+#endif /* _IPT_ECN_TARGET_H */
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_conntrack.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_conntrack.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_conntrack.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,38 @@
+/* Header file for kernel module to match connection tracking information.
+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
+ */
+
+#ifndef _IPT_CONNTRACK_H
+#define _IPT_CONNTRACK_H
+
+#define IPT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
+#define IPT_CONNTRACK_STATE_INVALID (1 << 0)
+
+#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
+#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
+
+/* flags, invflags: */
+#define IPT_CONNTRACK_STATE	0x01
+#define IPT_CONNTRACK_PROTO	0x02
+#define IPT_CONNTRACK_ORIGSRC	0x04
+#define IPT_CONNTRACK_ORIGDST	0x08
+#define IPT_CONNTRACK_REPLSRC	0x10
+#define IPT_CONNTRACK_REPLDST	0x20
+#define IPT_CONNTRACK_STATUS	0x40
+#define IPT_CONNTRACK_EXPIRES	0x80
+
+struct ipt_conntrack_info
+{
+	unsigned int statemask, statusmask;
+
+	struct ip_conntrack_tuple tuple[IP_CT_DIR_MAX];
+	struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
+
+	unsigned long expires_min, expires_max;
+
+	/* Flags word */
+	u_int8_t flags;
+	/* Inverse flags */
+	u_int8_t invflags;
+};
+#endif /*_IPT_CONNTRACK_H*/
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_dscp.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_dscp.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_dscp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_dscp.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,23 @@
+/* iptables module for matching the IPv4 DSCP field
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * ipt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
+*/
+#ifndef _IPT_DSCP_H
+#define _IPT_DSCP_H
+
+#define IPT_DSCP_MASK	0xfc	/* 11111100 */
+#define IPT_DSCP_SHIFT	2
+#define IPT_DSCP_MAX	0x3f	/* 00111111 */
+
+/* match info */
+struct ipt_dscp_info {
+	u_int8_t dscp;
+	u_int8_t invert;
+};
+
+#endif /* _IPT_DSCP_H */
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_ecn.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_ecn.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_ecn.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_ecn.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,33 @@
+/* iptables module for matching the ECN header in IPv4 and TCP header
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ecn.h,v 1.4 2002/08/05 19:39:00 laforge Exp
+*/
+#ifndef _IPT_ECN_H
+#define _IPT_ECN_H
+#include <linux/netfilter_ipv4/ipt_dscp.h>
+
+#define IPT_ECN_IP_MASK	(~IPT_DSCP_MASK)
+
+#define IPT_ECN_OP_MATCH_IP	0x01
+#define IPT_ECN_OP_MATCH_ECE	0x10
+#define IPT_ECN_OP_MATCH_CWR	0x20
+
+#define IPT_ECN_OP_MATCH_MASK	0xce
+
+/* match info */
+struct ipt_ecn_info {
+	u_int8_t operation;
+	u_int8_t invert;
+	u_int8_t ip_ect;
+	union {
+		struct {
+			u_int8_t ect;
+		} tcp;
+	} proto;
+};
+
+#endif /* _IPT_ECN_H */
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_helper.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_helper.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_helper.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_helper.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,8 @@
+#ifndef _IPT_HELPER_H
+#define _IPT_HELPER_H
+
+struct ipt_helper_info {
+	int invert;
+	char name[30];
+};
+#endif /* _IPT_HELPER_H */
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_owner.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_owner.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_owner.h	Fri Mar 17 10:56:20 2000
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_owner.h	Mon Aug 12 16:34:17 2002
@@ -6,12 +6,14 @@
 #define IPT_OWNER_GID	0x02
 #define IPT_OWNER_PID	0x04
 #define IPT_OWNER_SID	0x08
+#define IPT_OWNER_COMM	0x10
 
 struct ipt_owner_info {
     uid_t uid;
     gid_t gid;
     pid_t pid;
     pid_t sid;
+    char comm[16];
     u_int8_t match, invert;	/* flags */
 };
 
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_pkttype.h linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_pkttype.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv4/ipt_pkttype.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv4/ipt_pkttype.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,8 @@
+#ifndef _IPT_PKTTYPE_H
+#define _IPT_PKTTYPE_H
+
+struct ipt_pkttype_info {
+	int	pkttype;
+	int	invert;
+};
+#endif /*_IPT_PKTTYPE_H*/
diff -urN linux-2.4.20-pre1/include/linux/netfilter_ipv6/ip6t_length.h linux-2.4.20-pre2/include/linux/netfilter_ipv6/ip6t_length.h
--- linux-2.4.20-pre1/include/linux/netfilter_ipv6/ip6t_length.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/netfilter_ipv6/ip6t_length.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,10 @@
+#ifndef _IP6T_LENGTH_H
+#define _IP6T_LENGTH_H
+
+struct ip6t_length_info {
+	u_int16_t  min, max;
+	u_int8_t   invert;
+};
+
+#endif /*_IP6T_LENGTH_H*/
+	
diff -urN linux-2.4.20-pre1/include/linux/nfs_xdr.h linux-2.4.20-pre2/include/linux/nfs_xdr.h
--- linux-2.4.20-pre1/include/linux/nfs_xdr.h	Mon Jan 29 12:07:43 2001
+++ linux-2.4.20-pre2/include/linux/nfs_xdr.h	Mon Aug 12 16:34:17 2002
@@ -1,9 +1,6 @@
 #ifndef _LINUX_NFS_XDR_H
 #define _LINUX_NFS_XDR_H
 
-extern struct rpc_program	nfs_program;
-extern struct rpc_stat		nfs_rpcstat;
-
 struct nfs_fattr {
 	unsigned short		valid;		/* which fields are valid */
 	__u64			pre_size;	/* pre_op_attr.size	  */
@@ -372,5 +369,6 @@
 extern struct rpc_version	nfs_version2;
 extern struct rpc_version	nfs_version3;
 extern struct rpc_program	nfs_program;
+extern struct rpc_stat		nfs_rpcstat;
 
 #endif
diff -urN linux-2.4.20-pre1/include/linux/nfsd/export.h linux-2.4.20-pre2/include/linux/nfsd/export.h
--- linux-2.4.20-pre1/include/linux/nfsd/export.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/nfsd/export.h	Mon Aug 12 16:34:17 2002
@@ -39,7 +39,8 @@
 #define NFSEXP_NOSUBTREECHECK	0x0400
 #define	NFSEXP_NOAUTHNLM	0x0800		/* Don't authenticate NLM requests - just trust */
 #define NFSEXP_MSNFS		0x1000	/* do silly things that MS clients expect */
-#define NFSEXP_ALLFLAGS		0x1FFF
+#define NFSEXP_FSID		0x2000
+#define NFSEXP_ALLFLAGS		0x3FFF
 
 
 #ifdef __KERNEL__
@@ -55,11 +56,13 @@
 	struct in_addr		cl_addr[NFSCLNT_ADDRMAX];
 	struct svc_uidmap *	cl_umap;
 	struct list_head	cl_export[NFSCLNT_EXPMAX];
+	struct list_head	cl_expfsid[NFSCLNT_EXPMAX];
 	struct list_head	cl_list;
 };
 
 struct svc_export {
 	struct list_head	ex_hash;
+	struct list_head	ex_fsid_hash;
 	struct list_head	ex_list;
 	char			ex_path[NFS_MAXPATHLEN+1];
 	struct svc_export *	ex_parent;
@@ -71,6 +74,7 @@
 	ino_t			ex_ino;
 	uid_t			ex_anon_uid;
 	gid_t			ex_anon_gid;
+	int			ex_fsid;
 };
 
 #define EX_SECURE(exp)		(!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
@@ -92,6 +96,7 @@
 struct svc_client *	exp_getclient(struct sockaddr_in *sin);
 void			exp_putclient(struct svc_client *clp);
 struct svc_export *	exp_get(struct svc_client *clp, kdev_t dev, ino_t ino);
+struct svc_export *	exp_get_fsid(struct svc_client *clp, int fsid);
 int			exp_rootfh(struct svc_client *, kdev_t, ino_t,
 					char *path, struct knfsd_fh *, int maxsize);
 int			nfserrno(int errno);
diff -urN linux-2.4.20-pre1/include/linux/raid/md_compatible.h linux-2.4.20-pre2/include/linux/raid/md_compatible.h
--- linux-2.4.20-pre1/include/linux/raid/md_compatible.h	Thu Nov 22 11:48:07 2001
+++ linux-2.4.20-pre2/include/linux/raid/md_compatible.h	Mon Aug 12 16:34:17 2002
@@ -34,7 +34,7 @@
 	return test_bit(X86_FEATURE_MMX,  &boot_cpu_data.x86_capability);
 }
 #else
-#define md_cpu_has_mmx(x)	(0)
+#define md_cpu_has_mmx()       (0)
 #endif
 
 /* 002 */
diff -urN linux-2.4.20-pre1/include/linux/raid/md_k.h linux-2.4.20-pre2/include/linux/raid/md_k.h
--- linux-2.4.20-pre1/include/linux/raid/md_k.h	Mon Nov 26 05:29:17 2001
+++ linux-2.4.20-pre2/include/linux/raid/md_k.h	Mon Aug 12 16:34:17 2002
@@ -59,7 +59,7 @@
 typedef struct mdk_rdev_s mdk_rdev_t;
 
 #if (MINORBITS != 8)
-#error MD doesnt handle bigger kdev yet
+#error MD does not handle bigger kdev yet
 #endif
 
 #define MAX_MD_DEVS  (1<<MINORBITS)	/* Max number of md dev */
diff -urN linux-2.4.20-pre1/include/linux/reiserfs_fs.h linux-2.4.20-pre2/include/linux/reiserfs_fs.h
--- linux-2.4.20-pre1/include/linux/reiserfs_fs.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/reiserfs_fs.h	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ * Copyright 1996-2002 Hans Reiser, see reiserfs/README for licensing and copyright details
  */
 
 				/* this file has an amazingly stupid
@@ -55,6 +55,7 @@
 #define USE_INODE_GENERATION_COUNTER
 
 #define REISERFS_PREALLOCATE
+#define DISPLACE_NEW_PACKING_LOCALITIES
 #define PREALLOCATION_SIZE 8
 
 /* n must be power of 2 */
@@ -75,9 +76,9 @@
 /** always check a condition and panic if it's false. */
 #define RASSERT( cond, format, args... )					\
 if( !( cond ) ) 								\
-  reiserfs_panic( 0, "reiserfs[%i]: assertion " #cond " failed at "		\
-		  __FILE__ ":%i:" __FUNCTION__ ": " format "\n",		\
-		  in_interrupt() ? -1 : current -> pid, __LINE__ , ##args )
+  reiserfs_panic( 0, "reiserfs[%i]: assertion " #cond " failed at "	\
+		  __FILE__ ":%i:%s: " format "\n",		\
+		  in_interrupt() ? -1 : current -> pid, __LINE__ , __FUNCTION__ , ##args )
 
 #if defined( CONFIG_REISERFS_CHECK )
 #define RFALSE( cond, format, args... ) RASSERT( !( cond ), format, ##args )
@@ -184,7 +185,7 @@
    time cost for a 4 block file and saves an amount of space that is
    less significant as a percentage of space, or so goes the hypothesis.
    -Hans */
-#define STORE_TAIL_IN_UNFM(n_file_size,n_tail_size,n_block_size) \
+#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
 (\
   (!(n_tail_size)) || \
   (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
@@ -197,6 +198,18 @@
      ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
 )
 
+/* Another strategy for tails, this one means only create a tail if all the
+   file would fit into one DIRECT item.
+   Primary intention for this one is to increase performance by decreasing
+   seeking.
+*/   
+#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
+)
+
+
 
 /*
  * values for s_state field
@@ -953,9 +966,7 @@
 #define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
 
 // two entries per block (at least)
-//#define REISERFS_MAX_NAME_LEN(block_size) 
-//((block_size - BLKH_SIZE - IH_SIZE - DEH_SIZE * 2) / 2)
-#define REISERFS_MAX_NAME_LEN(block_size) 255
+#define REISERFS_MAX_NAME(block_size) 255
 
 
 /* this structure is used for operations on directory entries. It is
@@ -1325,6 +1336,10 @@
 
   int fs_gen;                  /* saved value of `reiserfs_generation' counter
 			          see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+  struct key  key;	      /* key pointer, to pass to block allocator or
+				 another low-level subsystem */
+#endif
 } ;
 
 /* These are modes of balancing */
@@ -1530,6 +1545,8 @@
 /* After several hours of tedious analysis, the following hash
  * function won.  Do not mess with it... -DaveM
  */
+/* The two definitions below were borrowed from fs/buffer.c file of Linux kernel
+ * sources and are not licensed by Namesys to its non-GPL license customers */
 #define _jhashfn(dev,block)	\
 	((((dev)<<(JBH_HASH_SHIFT - 6)) ^ ((dev)<<(JBH_HASH_SHIFT - 9))) ^ \
 	 (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
@@ -1558,7 +1575,7 @@
 int push_journal_writer(char *w) ;
 int pop_journal_writer(int windex) ;
 int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
-int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, unsigned long bl, int size, int searchall, unsigned long *next) ;
+int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, int bmap_nr, int bit_nr, int size, int searchall, unsigned int *next) ;
 int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
 struct super_block *reiserfs_get_super(kdev_t dev) ;
 void flush_async_commits(struct super_block *p_s_sb) ;
@@ -1576,7 +1593,7 @@
 
 				/* why is this kerplunked right here? */
 static inline int reiserfs_buffer_prepared(const struct buffer_head *bh) {
-  if (bh && test_bit(BH_JPrepared, ( struct buffer_head * ) &bh->b_state))
+  if (bh && test_bit(BH_JPrepared, &( (struct buffer_head *)bh)->b_state))
     return 1 ;
   else
     return 0 ;
@@ -1585,7 +1602,7 @@
 /* buffer was journaled, waiting to get to disk */
 static inline int buffer_journal_dirty(const struct buffer_head *bh) {
   if (bh)
-    return test_bit(BH_JDirty_wait, ( struct buffer_head * ) &bh->b_state) ;
+    return test_bit(BH_JDirty_wait, &( (struct buffer_head *)bh)->b_state) ;
   else
     return 0 ;
 }
@@ -1706,8 +1723,8 @@
 #define file_size(inode) ((inode)->i_size)
 #define tail_size(inode) (file_size (inode) & (block_size (inode) - 1))
 
-#define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\
-!STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), block_size (inode)))
+#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
+!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), block_size (inode)):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), block_size (inode)):0 )
 
 void padd_item (char * item, int total_length, int length);
 
@@ -1733,7 +1750,7 @@
 
 
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th, 
-				   const struct inode * dir, int mode, 
+				   struct inode * dir, int mode, 
 				   const char * symname, int item_len,
 				   struct dentry *dentry, struct inode *inode, int * err);
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
@@ -1909,22 +1926,87 @@
 struct buffer_head * get_FEB (struct tree_balance *);
 
 /* bitmap.c */
+
+/* structure contains hints for block allocator, and it is a container for
+ * arguments, such as node, search path, transaction_handle, etc. */
+ struct __reiserfs_blocknr_hint {
+     struct inode * inode;		/* inode passed to allocator, if we allocate unf. nodes */
+     long block;			/* file offset, in blocks */
+     struct key key;
+     struct path * path;		/* search path, used by allocator to deternine search_start by
+					 * various ways */
+     struct reiserfs_transaction_handle * th; /* transaction handle is needed to log super blocks and
+					       * bitmap blocks changes  */
+     b_blocknr_t beg, end;
+     b_blocknr_t search_start;		/* a field used to transfer search start value (block number)
+					 * between different block allocator procedures
+					 * (determine_search_start() and others) */
+    int prealloc_size;			/* is set in determine_prealloc_size() function, used by underlayed
+					 * function that do actual allocation */
+
+    int formatted_node:1;		/* the allocator uses different polices for getting disk space for
+					 * formatted/unformatted blocks with/without preallocation */
+    int preallocate:1;
+};
+
+typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
+
+int reiserfs_parse_alloc_options (struct super_block *, char *);
 int is_reusable (struct super_block * s, unsigned long block, int bit_value);
 void reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long);
-int reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th,
-			   unsigned long * pblocknrs, unsigned long start_from, int amount_needed);
-int reiserfs_new_unf_blocknrs (struct reiserfs_transaction_handle *th,
-			       unsigned long * pblocknr, unsigned long start_from);
+int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t * , int, int);
+extern inline int reiserfs_new_form_blocknrs (struct tree_balance * tb,
+					      b_blocknr_t *new_blocknrs, int amount_needed)
+{
+    reiserfs_blocknr_hint_t hint = {
+	th:tb->transaction_handle,
+	path: tb->tb_path,
+	inode: NULL,
+	key: tb->key,
+	block: 0,
+	formatted_node:1
+    };
+    return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed, 0);
+}
+
+extern inline int reiserfs_new_unf_blocknrs (struct reiserfs_transaction_handle *th,
+					     b_blocknr_t *new_blocknrs,
+					     struct path * path, long block)
+{
+    reiserfs_blocknr_hint_t hint = {
+	th: th,
+	path: path,
+	inode: NULL,
+	block: block,
+	formatted_node: 0,
+	preallocate: 0
+    };
+    return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+}
+
 #ifdef REISERFS_PREALLOCATE
-int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th, 
-				struct inode * inode,
-				unsigned long * pblocknr, 
-				unsigned long start_from);
+extern inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle *th,
+					     struct inode * inode,
+					     b_blocknr_t *new_blocknrs,
+					     struct path * path, long block)
+{
+    reiserfs_blocknr_hint_t hint = {
+	th: th,
+	path: path,
+	inode: inode,
+	block: block,
+	formatted_node: 0,
+	preallocate: 1
+    };
+    return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+}
 
 void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, 
 				struct inode * inode);
 void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th);
 #endif
+void reiserfs_claim_blocks_to_be_allocated( struct super_block *sb, int blocks);
+void reiserfs_release_claimed_blocks( struct super_block *sb, int blocks);
 
 /* hashes.c */
 __u32 keyed_hash (const signed char *msg, int len);
diff -urN linux-2.4.20-pre1/include/linux/reiserfs_fs_i.h linux-2.4.20-pre2/include/linux/reiserfs_fs_i.h
--- linux-2.4.20-pre1/include/linux/reiserfs_fs_i.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/reiserfs_fs_i.h	Mon Aug 12 16:34:17 2002
@@ -1,3 +1,6 @@
+/*
+ * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README
+ */
 #ifndef _REISER_FS_I
 #define _REISER_FS_I
 
@@ -41,6 +44,10 @@
     struct list_head i_prealloc_list;	/* per-transaction list of inodes which
 					 * have preallocated blocks */
   
+    int new_packing_locality:1;		/* new_packig_locality is created; new blocks
+					 * for the contents of this directory should be
+					 * displaced */
+
     /* we use these for fsync or O_SYNC to decide which transaction
     ** needs to be committed in order for this inode to be properly
     ** flushed */
diff -urN linux-2.4.20-pre1/include/linux/reiserfs_fs_sb.h linux-2.4.20-pre2/include/linux/reiserfs_fs_sb.h
--- linux-2.4.20-pre1/include/linux/reiserfs_fs_sb.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/reiserfs_fs_sb.h	Mon Aug 12 16:34:17 2002
@@ -1,4 +1,4 @@
-/* Copyright 1996-2000 Hans Reiser, see reiserfs/README for licensing
+/* Copyright 1996-2002 Hans Reiser, see reiserfs/README for licensing
  * and copyright details */
 
 #ifndef _LINUX_REISER_FS_SB
@@ -241,6 +241,8 @@
   unsigned long t_trans_id ;    /* sanity check, equals the current trans id */
   struct super_block *t_super ; /* super for this FS when journal_begin was 
                                    called. saves calls to reiserfs_get_super */
+  int displace_new_blocks:1;	/* if new block allocation occurres, that block
+				   should be displaced from others */
 } ;
 
 /*
@@ -324,6 +326,14 @@
 
 typedef __u32 (*hashf_t) (const signed char *, int);
 
+struct reiserfs_bitmap_info
+{
+    // FIXME: Won't work with block sizes > 8K
+    __u16  first_zero_hint;
+    __u16  free_count;
+    struct buffer_head *bh; /* the actual bitmap */
+};
+
 struct proc_dir_entry;
 
 #if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
@@ -368,14 +378,15 @@
   stat_cnt_t need_r_neighbor[ 5 ];
 
   stat_cnt_t free_block;
-  struct __find_forward_stats {
+  struct __scan_bitmap_stats {
 	stat_cnt_t call;
 	stat_cnt_t wait;
 	stat_cnt_t bmap;
 	stat_cnt_t retry;
 	stat_cnt_t in_journal_hint;
-	stat_cnt_t in_journal_out;
-  } find_forward;
+	stat_cnt_t in_journal_nohint;
+	stat_cnt_t stolen;
+  } scan_bitmap;
   struct __journal_stats {
 	stat_cnt_t in_journal;
 	stat_cnt_t in_journal_bitmap;
@@ -405,7 +416,7 @@
 				/* both the comment and the choice of
                                    name are unclear for s_rs -Hans */
     struct reiserfs_super_block * s_rs;           /* Pointer to the super block in the buffer */
-    struct buffer_head ** s_ap_bitmap;       /* array of buffers, holding block bitmap */
+    struct reiserfs_bitmap_info * s_ap_bitmap;
     struct reiserfs_journal *s_journal ;		/* pointer to journal information */
     unsigned short s_mount_state;                 /* reiserfs state (valid, invalid) */
   
@@ -418,6 +429,16 @@
                                    here (currently - NOTAIL, NOLOG,
                                    REPLAYONLY) */
 
+    struct {			/* This is a structure that describes block allocator options */
+	unsigned long bits;	/* Bitfield for enable/disable kind of options */
+	unsigned long large_file_size; /* size started from which we consider file to be a large one(in blocks) */
+	int border;		/* percentage of disk, border takes */
+	int preallocmin;	/* Minimal file size (in blocks) starting from which we do preallocations */
+	int preallocsize;	/* Number of blocks we try to prealloc when file
+				   reaches preallocmin size (in blocks) or
+				   prealloc_list is empty. */
+    } s_alloc_options;
+
 				/* Comment? -Hans */
     wait_queue_head_t s_wait;
 				/* To be obsoleted soon by per buffer seals.. -Hans */
@@ -444,6 +465,7 @@
     int s_is_unlinked_ok;
     reiserfs_proc_info_data_t s_proc_info_data;
     struct proc_dir_entry *procdir;
+    int reserved_blocks; /* amount of blocks reserved for further allocations */
 };
 
 /* Definitions of reiserfs on-disk properties: */
@@ -451,7 +473,8 @@
 #define REISERFS_3_6 1
 
 /* Mount options */
-#define NOTAIL 0  /* -o notail: no tails will be created in a session */
+#define REISERFS_LARGETAIL 0  /* large tails will be created in a session */
+#define REISERFS_SMALLTAIL 17  /* small (for files less than block size) tails will be created in a session */
 #define REPLAYONLY 3 /* replay journal and return 0. Use by fsck */
 #define REISERFS_NOLOG 4      /* -o nolog: turn journalling off */
 #define REISERFS_CONVERT 5    /* -o conv: causes conversion of old
@@ -499,7 +522,8 @@
 #define reiserfs_hashed_relocation(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_HASHED_RELOCATION))
 #define reiserfs_test4(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_TEST4))
 
-#define dont_have_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << NOTAIL))
+#define have_large_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_LARGETAIL))
+#define have_small_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_SMALLTAIL))
 #define replay_only(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REPLAYONLY))
 #define reiserfs_dont_log(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NOLOG))
 #define reiserfs_attrs(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_ATTRS))
diff -urN linux-2.4.20-pre1/include/linux/rtnetlink.h linux-2.4.20-pre2/include/linux/rtnetlink.h
--- linux-2.4.20-pre1/include/linux/rtnetlink.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/rtnetlink.h	Mon Aug 12 16:34:17 2002
@@ -440,12 +440,14 @@
 #define IFLA_COST IFLA_COST
 	IFLA_PRIORITY,
 #define IFLA_PRIORITY IFLA_PRIORITY
-	IFLA_MASTER
+	IFLA_MASTER,
 #define IFLA_MASTER IFLA_MASTER
+	IFLA_WIRELESS,		/* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
 };
 
 
-#define IFLA_MAX IFLA_MASTER
+#define IFLA_MAX IFLA_WIRELESS
 
 #define IFLA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
 #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
diff -urN linux-2.4.20-pre1/include/linux/sched.h linux-2.4.20-pre2/include/linux/sched.h
--- linux-2.4.20-pre1/include/linux/sched.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-pre2/include/linux/sched.h	Mon Aug 12 16:34:17 2002
@@ -458,8 +458,7 @@
 #define MAX_COUNTER	(20*HZ/100)
 #define DEF_NICE	(0)
 
-asmlinkage long sys_sched_yield(void);
-#define yield()	sys_sched_yield()
+extern void yield(void);
 
 /*
  * The default (Linux) execution domain.
@@ -611,7 +610,7 @@
 #define wake_up_interruptible_nr(x, nr)	__wake_up((x),TASK_INTERRUPTIBLE, nr)
 #define wake_up_interruptible_all(x)	__wake_up((x),TASK_INTERRUPTIBLE, 0)
 #define wake_up_interruptible_sync(x)	__wake_up_sync((x),TASK_INTERRUPTIBLE, 1)
-#define wake_up_interruptible_sync_nr(x) __wake_up_sync((x),TASK_INTERRUPTIBLE,  nr)
+#define wake_up_interruptible_sync_nr(x, nr) __wake_up_sync((x),TASK_INTERRUPTIBLE,  nr)
 asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
 
 extern int in_group_p(gid_t);
@@ -944,6 +943,17 @@
 	return res;
 }
 
-#endif /* __KERNEL__ */
+static inline int need_resched(void)
+{
+	return (unlikely(current->need_resched));
+}
 
+extern void __cond_resched(void);
+static inline void cond_resched(void)
+{
+	if (need_resched())
+		__cond_resched();
+}
+
+#endif /* __KERNEL__ */
 #endif
diff -urN linux-2.4.20-pre1/include/linux/slab.h linux-2.4.20-pre2/include/linux/slab.h
--- linux-2.4.20-pre1/include/linux/slab.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/include/linux/slab.h	Mon Aug 12 16:34:17 2002
@@ -57,6 +57,7 @@
 extern int kmem_cache_shrink(kmem_cache_t *);
 extern void *kmem_cache_alloc(kmem_cache_t *, int);
 extern void kmem_cache_free(kmem_cache_t *, void *);
+extern unsigned int kmem_cache_size(kmem_cache_t *);
 
 extern void *kmalloc(size_t, int);
 extern void kfree(const void *);
diff -urN linux-2.4.20-pre1/include/linux/sunrpc/sched.h linux-2.4.20-pre2/include/linux/sunrpc/sched.h
--- linux-2.4.20-pre1/include/linux/sunrpc/sched.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.20-pre2/include/linux/sunrpc/sched.h	Mon Aug 12 16:34:17 2002
@@ -34,13 +34,11 @@
  * This is the RPC task struct
  */
 struct rpc_task {
-	struct rpc_task *	tk_prev;	/* wait queue links */
-	struct rpc_task *	tk_next;
+	struct list_head	tk_list;	/* wait queue links */
 #ifdef RPC_DEBUG
 	unsigned long		tk_magic;	/* 0xf00baa */
 #endif
-	struct rpc_task *	tk_next_task;	/* global list of tasks */
-	struct rpc_task *	tk_prev_task;	/* global list of tasks */
+	struct list_head	tk_task;	/* global list of tasks */
 	struct rpc_clnt *	tk_client;	/* RPC client */
 	struct rpc_rqst *	tk_rqstp;	/* RPC request */
 	int			tk_status;	/* result of last operation */
@@ -88,6 +86,20 @@
 #define tk_auth			tk_client->cl_auth
 #define tk_xprt			tk_client->cl_xprt
 
+/* support walking a list of tasks on a wait queue */
+#define	task_for_each(task, pos, head) \
+	list_for_each(pos, head) \
+		if ((task=list_entry(pos, struct rpc_task, tk_list)),1)
+
+#define	task_for_first(task, head) \
+	if (!list_empty(head) &&  \
+	    ((task=list_entry((head)->next, struct rpc_task, tk_list)),1))
+
+/* .. and walking list of all tasks */
+#define	alltask_for_each(task, pos, head) \
+	list_for_each(pos, head) \
+		if ((task=list_entry(pos, struct rpc_task, tk_task)),1)
+
 typedef void			(*rpc_action)(struct rpc_task *);
 
 /*
@@ -133,16 +145,24 @@
  * RPC synchronization objects
  */
 struct rpc_wait_queue {
-	struct rpc_task *	task;
+	struct list_head	tasks;
 #ifdef RPC_DEBUG
 	char *			name;
 #endif
 };
 
 #ifndef RPC_DEBUG
-# define RPC_INIT_WAITQ(name)	((struct rpc_wait_queue) { NULL })
+# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var)})
+# define RPC_WAITQ(var,qname)      struct rpc_wait_queue var = RPC_WAITQ_INIT(var.tasks,qname)
+# define INIT_RPC_WAITQ(ptr,qname) do { \
+	INIT_LIST_HEAD(&(ptr)->tasks); \
+	} while(0)
 #else
-# define RPC_INIT_WAITQ(name)	((struct rpc_wait_queue) { NULL, name })
+# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var.tasks), qname})
+# define RPC_WAITQ(var,qname)      struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname)
+# define INIT_RPC_WAITQ(ptr,qname) do { \
+	INIT_LIST_HEAD(&(ptr)->tasks); (ptr)->name = qname; \
+	} while(0)
 #endif
 
 /*
diff -urN linux-2.4.20-pre1/include/linux/sunrpc/svc.h linux-2.4.20-pre2/include/linux/sunrpc/svc.h
--- linux-2.4.20-pre1/include/linux/sunrpc/svc.h	Thu Nov 22 11:47:20 2001
+++ linux-2.4.20-pre2/include/linux/sunrpc/svc.h	Mon Aug 12 16:34:17 2002
@@ -26,8 +26,8 @@
  * We currently do not support more than one RPC program per daemon.
  */
 struct svc_serv {
-	struct svc_rqst *	sv_threads;	/* idle server threads */
-	struct svc_sock *	sv_sockets;	/* pending sockets */
+	struct list_head	sv_threads;	/* idle server threads */
+	struct list_head	sv_sockets;	/* pending sockets */
 	struct svc_program *	sv_program;	/* RPC program */
 	struct svc_stat *	sv_stats;	/* RPC statistics */
 	spinlock_t		sv_lock;
@@ -35,7 +35,9 @@
 	unsigned int		sv_bufsz;	/* datagram buffer size */
 	unsigned int		sv_xdrsize;	/* XDR buffer size */
 
-	struct svc_sock *	sv_allsocks;	/* all sockets */
+	struct list_head	sv_permsocks;	/* all permanent sockets */
+	struct list_head	sv_tempsocks;	/* all temporary sockets */
+	int			sv_tmpcnt;	/* count of temporary sockets */
 
 	char *			sv_name;	/* service name */
 };
@@ -88,8 +90,7 @@
  * NOTE: First two items must be prev/next.
  */
 struct svc_rqst {
-	struct svc_rqst *	rq_prev;	/* idle list */
-	struct svc_rqst *	rq_next;
+	struct list_head	rq_list;	/* idle list */
 	struct svc_sock *	rq_sock;	/* socket */
 	struct sockaddr_in	rq_addr;	/* peer address */
 	int			rq_addrlen;
@@ -114,9 +115,17 @@
 	void *			rq_argp;	/* decoded arguments */
 	void *			rq_resp;	/* xdr'd results */
 
+	int			rq_reserved;	/* space on socket outq
+						 * reserved for this request
+						 */
+
 	/* Catering to nfsd */
 	struct svc_client *	rq_client;	/* RPC peer info */
 	struct svc_cacherep *	rq_cacherep;	/* cache info */
+	struct knfsd_fh *	rq_reffh;	/* Referrence filehandle, used to
+						 * determine what device number
+						 * to report (real or virtual)
+						 */
 
 	wait_queue_head_t	rq_wait;	/* synchronozation */
 };
@@ -162,6 +171,7 @@
 	unsigned int		pc_ressize;	/* result struct size */
 	unsigned int		pc_count;	/* call count */
 	unsigned int		pc_cachetype;	/* cache info (NFS) */
+	unsigned int		pc_xdrressize;	/* maximum size of XDR reply */
 };
 
 /*
@@ -179,5 +189,6 @@
 int		   svc_process(struct svc_serv *, struct svc_rqst *);
 int		   svc_register(struct svc_serv *, int, unsigned short);
 void		   svc_wake_up(struct svc_serv *);
+void		   svc_reserve(struct svc_rqst *rqstp, int space);
 
 #endif /* SUNRPC_SVC_H */
diff -urN linux-2.4.20-pre1/include/linux/sunrpc/svcsock.h linux-2.4.20-pre2/include/linux/sunrpc/svcsock.h
--- linux-2.4.20-pre1/include/linux/sunrpc/svcsock.h	Thu Nov 22 11:47:20 2001
+++ linux-2.4.20-pre2/include/linux/sunrpc/svcsock.h	Mon Aug 12 16:34:17 2002
@@ -13,38 +13,39 @@
 
 /*
  * RPC server socket.
- * NOTE: First two items must be prev/next.
  */
 struct svc_sock {
-	struct svc_sock *	sk_prev;	/* list of ready sockets */
-	struct svc_sock *	sk_next;
-	struct svc_sock *	sk_list;	/* list of all sockets */
+	struct list_head	sk_ready;	/* list of ready sockets */
+	struct list_head	sk_list;	/* list of all sockets */
 	struct socket *		sk_sock;	/* berkeley socket layer */
 	struct sock *		sk_sk;		/* INET layer */
-	spinlock_t		sk_lock;
 
 	struct svc_serv *	sk_server;	/* service for this socket */
 	unsigned char		sk_inuse;	/* use count */
-	unsigned char		sk_busy;	/* enqueued/receiving */
-	unsigned char		sk_conn;	/* conn pending */
-	unsigned char		sk_close;	/* dead or dying */
-	int			sk_data;	/* data pending */
-	unsigned int		sk_temp : 1,	/* temp socket */
-				sk_qued : 1,	/* on serv->sk_sockets */
-				sk_dead : 1;	/* socket closed */
+	unsigned int		sk_flags;
+#define	SK_BUSY		0			/* enqueued/receiving */
+#define	SK_CONN		1			/* conn pending */
+#define	SK_CLOSE	2			/* dead or dying */
+#define	SK_DATA		3			/* data pending */
+#define	SK_TEMP		4			/* temp (TCP) socket */
+#define	SK_QUED		5			/* on serv->sk_sockets */
+#define	SK_DEAD		6			/* socket closed */
+#define	SK_CHNGBUF	7			/* need to change snd/rcv buffer sizes */
+
+	int			sk_reserved;	/* space on outq that is reserved */
+
 	int			(*sk_recvfrom)(struct svc_rqst *rqstp);
 	int			(*sk_sendto)(struct svc_rqst *rqstp);
 
 	/* We keep the old state_change and data_ready CB's here */
 	void			(*sk_ostate)(struct sock *);
 	void			(*sk_odata)(struct sock *, int bytes);
+	void			(*sk_owspace)(struct sock *);
 
 	/* private TCP part */
 	int			sk_reclen;	/* length of record */
 	int			sk_tcplen;	/* current read length */
-
-	/* Debugging */
-	struct svc_rqst *	sk_rqstp;
+	time_t			sk_lastrecv;	/* time of last received request */
 };
 
 /*
@@ -55,5 +56,6 @@
 int		svc_recv(struct svc_serv *, struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
 void		svc_drop(struct svc_rqst *);
+void		svc_sock_update_bufs(struct svc_serv *serv);
 
 #endif /* SUNRPC_SVCSOCK_H */
diff -urN linux-2.4.20-pre1/include/linux/sunrpc/types.h linux-2.4.20-pre2/include/linux/sunrpc/types.h
--- linux-2.4.20-pre1/include/linux/sunrpc/types.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.20-pre2/include/linux/sunrpc/types.h	Mon Aug 12 16:34:17 2002
@@ -12,60 +12,7 @@
 #include <linux/timer.h>
 #include <linux/tqueue.h>
 #include <linux/sunrpc/debug.h>
-
-/*
- * These are the RPC list manipulation primitives used everywhere.
- */
-struct rpc_listitem	{
-	struct rpc_listitem *	prev;
-	struct rpc_listitem *	next;
-};
-
-static __inline__ void
-__rpc_append_list(struct rpc_listitem **q, struct rpc_listitem *item)
-{
-	struct rpc_listitem	*next, *prev;
-
-	if (!(next = *q)) {
-		*q = item->next = item->prev = item;
-	} else {
-		prev = next->prev;
-		prev->next = item;
-		next->prev = item;
-		item->next = next;
-		item->prev = prev;
-	}
-}
-
-static __inline__ void
-__rpc_insert_list(struct rpc_listitem **q, struct rpc_listitem *item)
-{
-	__rpc_append_list(q, item);
-	*q = item;
-}
-
-static __inline__ void
-__rpc_remove_list(struct rpc_listitem **q, struct rpc_listitem *item)
-{
-	struct rpc_listitem	*prev = item->prev,
-				*next = item->next;
-
-	if (item != prev) {
-		next->prev = prev;
-		prev->next = next;
-	} else {
-		next = NULL;
-	}
-	if (*q == item)
-		*q = next;
-}
-
-#define rpc_insert_list(q, i) \
-      __rpc_insert_list((struct rpc_listitem **) q, (struct rpc_listitem *) i)
-#define rpc_append_list(q, i) \
-      __rpc_append_list((struct rpc_listitem **) q, (struct rpc_listitem *) i)
-#define rpc_remove_list(q, i) \
-      __rpc_remove_list((struct rpc_listitem **) q, (struct rpc_listitem *) i)
+#include <linux/list.h>
 
 /*
  * Shorthands
diff -urN linux-2.4.20-pre1/include/linux/swap.h linux-2.4.20-pre2/include/linux/swap.h
--- linux-2.4.20-pre1/include/linux/swap.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/include/linux/swap.h	Mon Aug 12 16:34:17 2002
@@ -115,6 +115,7 @@
 /* linux/mm/vmscan.c */
 extern wait_queue_head_t kswapd_wait;
 extern int FASTCALL(try_to_free_pages(zone_t *, unsigned int, unsigned int));
+extern int FASTCALL(try_to_free_pages_nozone(unsigned int));
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *);
diff -urN linux-2.4.20-pre1/include/linux/sysctl.h linux-2.4.20-pre2/include/linux/sysctl.h
--- linux-2.4.20-pre1/include/linux/sysctl.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/include/linux/sysctl.h	Mon Aug 12 16:34:17 2002
@@ -205,7 +205,8 @@
 	NET_CORE_NO_CONG_THRESH=13,
 	NET_CORE_NO_CONG=14,
 	NET_CORE_LO_CONG=15,
-	NET_CORE_MOD_CONG=16
+	NET_CORE_MOD_CONG=16,
+	NET_CORE_DEV_WEIGHT=17
 };
 
 /* /proc/sys/net/ethernet */
diff -urN linux-2.4.20-pre1/include/linux/ticable.h linux-2.4.20-pre2/include/linux/ticable.h
--- linux-2.4.20-pre1/include/linux/ticable.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/ticable.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,42 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tipar/tiser/tiusb - low level driver for handling link cables
+ * designed for Texas Instruments graphing calculators.
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _TICABLE_H 
+#define _TICABLE_H 1
+
+/* Internal default constants for the kernel module */
+#define TIMAXTIME 15      /* 1.5 seconds       */
+#define IO_DELAY  10      /* 10 micro-seconds  */
+
+/* Major & minor number for character devices */
+#define TIPAR_MAJOR  115 /* 0 to 7 */
+#define TIPAR_MINOR    0
+
+#define TISER_MAJOR  115 /* 8 to 15 */
+#define TISER_MINOR    8
+
+#define TIUSB_MAJOR  115  /* 16 to 31 */
+#define TIUSB_MINOR   16
+
+/*
+ * Request values for the 'ioctl' function.
+ */
+#define IOCTL_TIPAR_DELAY     _IOW('p', 0xa8, int) /* set delay   */
+#define IOCTL_TIPAR_TIMEOUT   _IOW('p', 0xa9, int) /* set timeout */
+
+#define IOCTL_TISER_DELAY     _IOW('p', 0xa0, int) /* set delay   */
+#define IOCTL_TISER_TIMEOUT   _IOW('p', 0xa1, int) /* set timeout */
+
+#define IOCTL_TIUSB_TIMEOUT        _IOW('N', 0x20, int) /* set timeout */
+#define IOCTL_TIUSB_RESET_DEVICE   _IOW('N', 0x21, int) /* reset device */
+#define IOCTL_TIUSB_RESET_PIPES    _IOW('N', 0x22, int) /* reset both pipes*/
+
+#endif /* TICABLE_H */
diff -urN linux-2.4.20-pre1/include/linux/usb.h linux-2.4.20-pre2/include/linux/usb.h
--- linux-2.4.20-pre1/include/linux/usb.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/include/linux/usb.h	Mon Aug 12 16:34:17 2002
@@ -16,8 +16,8 @@
 #define USB_CLASS_MASS_STORAGE		8
 #define USB_CLASS_HUB			9
 #define USB_CLASS_CDC_DATA		0x0a
-#define USB_CLASS_CSCID		0x0b /* chip+ smart card */
-#define USB_CLASS_CONTENT_SEC		0x0d /* content security */
+#define USB_CLASS_CSCID			0x0b	/* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC		0x0d	/* content security */
 #define USB_CLASS_APP_SPEC		0xfe
 #define USB_CLASS_VENDOR_SPEC		0xff
 
@@ -42,8 +42,8 @@
 /*
  * USB directions
  */
-#define USB_DIR_OUT			0
-#define USB_DIR_IN			0x80
+#define USB_DIR_OUT			0		/* to device */
+#define USB_DIR_IN			0x80		/* to host */
 
 /*
  * Descriptor types
@@ -85,23 +85,23 @@
 /*
  * USB Packet IDs (PIDs)
  */
-#define USB_PID_UNDEF_0                        0xf0
-#define USB_PID_OUT                            0xe1
-#define USB_PID_ACK                            0xd2
-#define USB_PID_DATA0                          0xc3
-#define USB_PID_PING                           0xb4	/* USB 2.0 */
-#define USB_PID_SOF                            0xa5
-#define USB_PID_NYET                           0x96	/* USB 2.0 */
-#define USB_PID_DATA2                          0x87	/* USB 2.0 */
-#define USB_PID_SPLIT                          0x78	/* USB 2.0 */
-#define USB_PID_IN                             0x69
-#define USB_PID_NAK                            0x5a
-#define USB_PID_DATA1                          0x4b
-#define USB_PID_PREAMBLE                       0x3c	/* Token mode */
-#define USB_PID_ERR                            0x3c	/* USB 2.0: handshake mode */
-#define USB_PID_SETUP                          0x2d
-#define USB_PID_STALL                          0x1e
-#define USB_PID_MDATA                          0x0f	/* USB 2.0 */
+#define USB_PID_UNDEF_0			0xf0
+#define USB_PID_OUT			0xe1
+#define USB_PID_ACK			0xd2
+#define USB_PID_DATA0			0xc3
+#define USB_PID_PING			0xb4	/* USB 2.0 */
+#define USB_PID_SOF			0xa5
+#define USB_PID_NYET			0x96	/* USB 2.0 */
+#define USB_PID_DATA2			0x87	/* USB 2.0 */
+#define USB_PID_SPLIT			0x78	/* USB 2.0 */
+#define USB_PID_IN			0x69
+#define USB_PID_NAK			0x5a
+#define USB_PID_DATA1			0x4b
+#define USB_PID_PREAMBLE		0x3c	/* Token mode */
+#define USB_PID_ERR			0x3c	/* USB 2.0: handshake mode */
+#define USB_PID_SETUP			0x2d
+#define USB_PID_STALL			0x1e
+#define USB_PID_MDATA			0x0f	/* USB 2.0 */
 
 /*
  * Standard requests
@@ -152,13 +152,26 @@
 		mdelay(ms);
 }
 
-typedef struct {
-	__u8 requesttype;
-	__u8 request;
-	__u16 value;
-	__u16 index;
-	__u16 length;
-} devrequest __attribute__ ((packed));
+/**
+ * struct usb_ctrlrequest - structure used to make USB device control requests easier to create and decode
+ * @bRequestType: matches the USB bmRequestType field
+ * @bRequest: matches the USB bRequest field
+ * @wValue: matches the USB wValue field
+ * @wIndex: matches the USB wIndex field
+ * @wLength: matches the USB wLength field
+ *
+ * This structure is used to send control requests to a USB device.  It matches
+ * the different fields of the USB 2.0 Spec section 9.3, table 9-2.  See the
+ * USB spec for a fuller description of the different fields, and what they are
+ * used for.
+ */
+struct usb_ctrlrequest {
+	__u8 bRequestType;
+	__u8 bRequest;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+} __attribute__ ((packed));
 
 /*
  * USB-status codes:
@@ -174,10 +187,10 @@
 #define USB_ST_BUFFEROVERRUN	(-ECOMM)
 #define USB_ST_BUFFERUNDERRUN	(-ENOSR)
 #define USB_ST_INTERNALERROR	(-EPROTO) 			/* unknown error */
-#define USB_ST_SHORT_PACKET    	(-EREMOTEIO)
-#define USB_ST_PARTIAL_ERROR  	(-EXDEV)			/* ISO transfer only partially completed */
-#define USB_ST_URB_KILLED     	(-ENOENT)			/* URB canceled by user */
-#define USB_ST_URB_PENDING       (-EINPROGRESS)
+#define USB_ST_SHORT_PACKET	(-EREMOTEIO)
+#define USB_ST_PARTIAL_ERROR	(-EXDEV)			/* ISO transfer only partially completed */
+#define USB_ST_URB_KILLED	(-ENOENT)			/* URB canceled by user */
+#define USB_ST_URB_PENDING	(-EINPROGRESS)
 #define USB_ST_REMOVED		(-ENODEV) 			/* device not existing or removed */
 #define USB_ST_TIMEOUT		(-ETIMEDOUT)			/* communication timed out, also in urb->status**/
 #define USB_ST_NOTSUPPORTED	(-ENOSYS)			
@@ -423,28 +436,28 @@
 /*
  * urb->transfer_flags:
  */
-#define USB_DISABLE_SPD         0x0001
-#define USB_ISO_ASAP            0x0002
-#define USB_ASYNC_UNLINK        0x0008
-#define USB_QUEUE_BULK          0x0010
+#define USB_DISABLE_SPD		0x0001
+#define USB_ISO_ASAP		0x0002
+#define USB_ASYNC_UNLINK	0x0008
+#define USB_QUEUE_BULK		0x0010
 #define USB_NO_FSBR		0x0020
-#define USB_ZERO_PACKET         0x0040  // Finish bulk OUTs always with zero length packet
+#define USB_ZERO_PACKET		0x0040  // Finish bulk OUTs always with zero length packet
 #define URB_NO_INTERRUPT	0x0080	/* HINT: no non-error interrupt needed */
 					/* ... less overhead for QUEUE_BULK */
 #define USB_TIMEOUT_KILLED	0x1000	// only set by HCD!
 
-typedef struct
+struct iso_packet_descriptor
 {
 	unsigned int offset;
 	unsigned int length;		// expected length
 	unsigned int actual_length;
 	unsigned int status;
-} iso_packet_descriptor_t, *piso_packet_descriptor_t;
+};
 
 struct urb;
 typedef void (*usb_complete_t)(struct urb *);
 
-typedef struct urb
+struct urb
 {
 	spinlock_t lock;		// lock for the URB
 	void *hcpriv;			// private data for host controller
@@ -469,8 +482,8 @@
 	void *context;			// context for completion routine
 	usb_complete_t complete;	// pointer to completion routine
 	//
-	iso_packet_descriptor_t iso_frame_desc[0];
-} urb_t, *purb_t;
+	struct iso_packet_descriptor iso_frame_desc[0];
+};
 
 /**
  * FILL_CONTROL_URB - macro to help initialize a control urb
@@ -675,11 +688,11 @@
 	urb->start_frame = -1;
 }
 
-purb_t usb_alloc_urb(int iso_packets);
-void usb_free_urb (purb_t purb);
-int usb_submit_urb(purb_t purb);
-int usb_unlink_urb(purb_t purb);
-int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd,  void *data, int len, int timeout);
+struct urb *usb_alloc_urb(int iso_packets);
+void usb_free_urb (struct urb *urb);
+int usb_submit_urb(struct urb *urb);
+int usb_unlink_urb(struct urb *urb);
+int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, struct usb_ctrlrequest *cmd,  void *data, int len, int timeout);
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout);
 
 /*-------------------------------------------------------------------*
diff -urN linux-2.4.20-pre1/include/linux/vt_kern.h linux-2.4.20-pre2/include/linux/vt_kern.h
--- linux-2.4.20-pre1/include/linux/vt_kern.h	Thu Nov 22 11:47:07 2001
+++ linux-2.4.20-pre2/include/linux/vt_kern.h	Mon Aug 12 16:34:17 2002
@@ -90,6 +90,5 @@
 int vt_waitactive(int vt);
 void change_console(unsigned int);
 void reset_vc(unsigned int new_console);
-int vt_waitactive(int vt);
 
 #endif /* _VT_KERN_H */
diff -urN linux-2.4.20-pre1/include/linux/wireless.h linux-2.4.20-pre2/include/linux/wireless.h
--- linux-2.4.20-pre1/include/linux/wireless.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/include/linux/wireless.h	Mon Aug 12 16:34:17 2002
@@ -1,10 +1,10 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	13	6.12.01
+ * Version :	14	25.1.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _LINUX_WIRELESS_H
@@ -40,7 +40,7 @@
  *	# include/linux/netdevice.h (one place)
  *	# include/linux/proc_fs.h (one place)
  *
- * New driver API (2001 -> onward) :
+ * New driver API (2002 -> onward) :
  * -------------------------------
  * This file is only concerned with the user space API and common definitions.
  * The new driver API is defined and documented in :
@@ -49,6 +49,11 @@
  * Note as well that /proc/net/wireless implementation has now moved in :
  *	# include/linux/wireless.c
  *
+ * Wireless Events (2002 -> onward) :
+ * --------------------------------
+ * Events are defined at the end of this file, and implemented in :
+ *	# include/linux/wireless.c
+ *
  * Other comments :
  * --------------
  * Do not add here things that are redundant with other mechanisms
@@ -75,7 +80,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	13
+#define WIRELESS_EXT	14
 
 /*
  * Changes :
@@ -141,6 +146,13 @@
  *	- Document creation of new driver API.
  *	- Extract union iwreq_data from struct iwreq (for new driver API).
  *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
+ *
+ * V13 to V14
+ * ----------
+ *	- Wireless Events support : define struct iw_event
+ *	- Define additional specific event numbers
+ *	- Add "addr" and "param" fields in union iwreq_data
+ *	- AP scanning stuff (SIOCSIWSCAN and friends)
  */
 
 /**************************** CONSTANTS ****************************/
@@ -175,6 +187,8 @@
 #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
 #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
 #define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
+#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
+#define SIOCGIWSCAN	0x8B19		/* get scanning results */
 
 /* 802.11 specific support */
 #define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
@@ -238,6 +252,15 @@
 #define IW_IS_SET(cmd)	(!((cmd) & 0x1))
 #define IW_IS_GET(cmd)	((cmd) & 0x1)
 
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/* Those are *NOT* ioctls, do not issue request on them !!! */
+/* Most events use the same identifier as ioctl requests */
+
+#define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
+#define IWEVQUAL	0x8C01		/* Quality part of statistics */
+
+#define IWEVFIRST	0x8C00
+
 /* ------------------------- PRIVATE INFO ------------------------- */
 /*
  * The following is used with SIOCGIWPRIV. It allow a driver to define
@@ -340,6 +363,19 @@
 #define IW_RETRY_MAX		0x0002	/* Value is a maximum */
 #define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
 
+/* Scanning request flags */
+#define IW_SCAN_DEFAULT		0x0000	/* Default scan of the driver */
+#define IW_SCAN_ALL_ESSID	0x0001	/* Scan all ESSIDs */
+#define IW_SCAN_THIS_ESSID	0x0002	/* Scan only this ESSID */
+#define IW_SCAN_ALL_FREQ	0x0004	/* Scan all Frequencies */
+#define IW_SCAN_THIS_FREQ	0x0008	/* Scan only this Frequency */
+#define IW_SCAN_ALL_MODE	0x0010	/* Scan all Modes */
+#define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
+#define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
+#define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
+/* Maximum size of returned data */
+#define IW_SCAN_MAX_DATA	4096	/* In bytes */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -466,9 +502,12 @@
 
 	struct iw_point	encoding;	/* Encoding stuff : tokens */
 	struct iw_param	power;		/* PM duration/timeout */
+	struct iw_quality qual;		/* Quality part of statistics */
 
 	struct sockaddr	ap_addr;	/* Access point address */
+	struct sockaddr	addr;		/* Destination address (hw) */
 
+	struct iw_param	param;		/* Other small parameters */
 	struct iw_point	data;		/* Other large parameters */
 };
 
@@ -596,4 +635,35 @@
 	char		name[IFNAMSIZ];	/* Name of the extension */
 };
 
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/*
+ * Wireless events are carried through the rtnetlink socket to user
+ * space. They are encapsulated in the IFLA_WIRELESS field of
+ * a RTM_NEWLINK message.
+ */
+
+/*
+ * A Wireless Event. Contains basically the same data as the ioctl...
+ */
+struct iw_event
+{
+	__u16		len;			/* Real lenght of this stuff */
+	__u16		cmd;			/* Wireless IOCTL */
+	union iwreq_data	u;		/* IOCTL fixed payload */
+};
+
+/* Size of the Event prefix (including padding and alignement junk) */
+#define IW_EV_LCP_LEN	(sizeof(struct iw_event) - sizeof(union iwreq_data))
+/* Size of the various events */
+#define IW_EV_CHAR_LEN	(IW_EV_LCP_LEN + IFNAMSIZ)
+#define IW_EV_UINT_LEN	(IW_EV_LCP_LEN + sizeof(__u32))
+#define IW_EV_FREQ_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_freq))
+#define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point))
+#define IW_EV_PARAM_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_param))
+#define IW_EV_ADDR_LEN	(IW_EV_LCP_LEN + sizeof(struct sockaddr))
+#define IW_EV_QUAL_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_quality))
+
+/* Note : in the case of iw_point, the extra data will come at the
+ * end of the event */
+
 #endif	/* _LINUX_WIRELESS_H */
diff -urN linux-2.4.20-pre1/include/linux/zconf.h linux-2.4.20-pre2/include/linux/zconf.h
--- linux-2.4.20-pre1/include/linux/zconf.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/zconf.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,90 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id$ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+#if defined(__GNUC__) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+
+#if defined(__STDC__) || defined(__cplusplus)
+#  ifndef STDC
+#    define STDC
+#  endif
+#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.
+*/
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  define MAX_MEM_LEVEL 9
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef FAR
+#   define FAR
+#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;
+
+typedef void FAR *voidpf;
+typedef void     *voidp;
+
+#include <linux/types.h> /* for off_t */
+#include <linux/unistd.h>    /* for SEEK_* and off_t */
+#define z_off_t  off_t
+
+#endif /* _ZCONF_H */
diff -urN linux-2.4.20-pre1/include/linux/zlib.h linux-2.4.20-pre2/include/linux/zlib.h
--- linux-2.4.20-pre1/include/linux/zlib.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/zlib.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,654 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.3, July 9th, 1998
+
+  Copyright (C) 1995-1998 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
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include <linux/zconf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.3"
+
+/* 
+     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 will be added later and will have the same
+  stream interface.
+
+     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.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+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 */
+
+    void     *workspace; /* memory allocated for this stream */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   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.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   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 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_PACKET_FLUSH  2
+#define Z_SYNC_FLUSH    3
+#define Z_FULL_FLUSH    4
+#define Z_FINISH        5
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#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
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlib_zlibVersion OF((void));
+/* The application can compare zlibVersion 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.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+ZEXTERN int ZEXPORT zlib_deflate_workspacesize OF((void));
+/*
+   Returns the number of bytes that needs to be allocated for a per-
+   stream workspace.  A pointer to this number of bytes should be
+   returned in stream->workspace before calling zlib_deflateInit().
+*/
+
+/* 
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT zlib_deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress 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 and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  the compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+  
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).
+*/
+
+
+ZEXTERN int ZEXPORT zlib_deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+ZEXTERN int ZEXPORT zlib_inflate_workspacesize OF((void));
+/*
+   Returns the number of bytes that needs to be allocated for a per-
+   stream workspace.  A pointer to this number of bytes should be
+   returned in stream->workspace before calling zlib_inflateInit().
+*/
+
+/* 
+ZEXTERN int ZEXPORT zlib_inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, and workspace must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  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, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT zlib_inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may some
+  introduce some output latency (reading input without producing any output)
+  except when forced to flush.
+
+  The detailed semantics are as follows. inflate 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() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  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 inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_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_SYNC_FLUSH
+  and Z_FINISH, but the current implementation actually flushes as much output
+  as possible anyway.
+
+    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.
+
+     If a preset dictionary is needed at this point (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the
+  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
+  it sets strm->adler to the adler32 checksum of all output produced
+  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+  an error code as described below. At the end of the stream, inflate()
+  checks that its computed adler32 checksum is equal to that saved by the
+  compressor and returns Z_STREAM_END only if the checksum is correct.
+
+    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_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect
+  adler32 checksum), 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.
+*/
+
+
+ZEXTERN int ZEXPORT zlib_inflateEnd OF((z_streamp 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 */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*   
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+                            
+ZEXTERN int ZEXPORT zlib_deflateSetDictionary OF((z_streamp strm,
+						     const Bytef *dictionary,
+						     uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT zlib_deflateCopy OF((z_streamp dest,
+					    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT zlib_deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT zlib_deflateParams OF((z_streamp strm,
+					      int level,
+					      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+/*   
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque 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 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.
+
+      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 a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT zlib_inflateSetDictionary OF((z_streamp strm,
+						     const Bytef *dictionary,
+						     uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate
+   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the Adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT zlib_inflateSync OF((z_streamp strm));
+/* 
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point 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.
+*/
+
+ZEXTERN int ZEXPORT zlib_inflateReset OF((z_streamp 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 ZEXPORT zlib_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).
+*/
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT zlib_deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT zlib_inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT zlib_deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT zlib_inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+#define zlib_deflateInit(strm, level) \
+        zlib_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_inflateInit(strm) \
+        zlib_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        zlib_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define zlib_inflateInit2(strm, windowBits) \
+        zlib_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zlib_zError           OF((int err));
+ZEXTERN int            ZEXPORT zlib_inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT zlib_get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff -urN linux-2.4.20-pre1/include/linux/zlib_fs.h linux-2.4.20-pre2/include/linux/zlib_fs.h
--- linux-2.4.20-pre1/include/linux/zlib_fs.h	Mon Nov  5 13:40:59 2001
+++ linux-2.4.20-pre2/include/linux/zlib_fs.h	Wed Dec 31 16:00:00 1969
@@ -1,679 +0,0 @@
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.1.3, July 9th, 1998
-
-  Copyright (C) 1995-1998 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
-  jloup@gzip.org          madler@alumni.caltech.edu
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef _ZLIB_H
-#define _ZLIB_H
-
-#include "zconf.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define ZLIB_VERSION "1.1.3"
-
-/* 
-     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 will be added later and will have the same
-  stream interface.
-
-     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.
-
-     The library also supports reading and writing files in gzip (.gz) format
-  with an interface similar to that of stdio.
-
-     The library does not install any signal handler. The decoder checks
-  the consistency of the compressed data, so the library should never
-  crash even in case of corrupted input.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-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 */
-
-    void     *workspace; /* memory allocated for this stream */
-
-    int     data_type;  /* best guess about the data type: ascii or binary */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-   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.
-   If zlib is used in a multi-threaded application, zalloc and zfree must be
-   thread safe.
-
-   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 /* will be removed, use Z_SYNC_FLUSH instead */
-#define Z_SYNC_FLUSH    2
-#define Z_FULL_FLUSH    3
-#define Z_FINISH        4
-/* Allowed flush values; see deflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#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
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_ASCII    1
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-                        /* basic functions */
-
-ZEXTERN const char * ZEXPORT zlib_fs_zlibVersion OF((void));
-/* The application can compare zlibVersion 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.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/* 
-ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_deflate OF((z_streamp strm, int flush));
-/*
-    deflate compresses as much data as possible, and stops when the input
-  buffer becomes empty or the output buffer becomes full. It may introduce some
-  output latency (reading input without producing any output) except when
-  forced to flush.
-
-    The detailed semantics are as follows. deflate performs one or both of the
-  following actions:
-
-  - Compress 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 and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
-  flushed to the output buffer and the output is aligned on a byte boundary, so
-  that the decompressor can get all input data available so far. (In particular
-  avail_in is zero after the call if enough output space has been provided
-  before the call.)  Flushing may degrade compression for some compression
-  algorithms and so it should be used only when necessary.
-
-    If flush is set to Z_FULL_FLUSH, all output is flushed as with
-  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
-  restart from this point if previous compressed data has been damaged or if
-  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
-  the compression.
-
-    If deflate returns with avail_out == 0, this function must be called again
-  with the same value of the flush parameter and more output space (updated
-  avail_out), until the flush is complete (deflate returns with non-zero
-  avail_out).
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-  
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() sets strm->adler to the adler32 checksum of all input read
-  so far (that is, total_in bytes).
-
-    deflate() may update data_type if it can make a good guess about
-  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
-  (for example avail_in or avail_out was zero).
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_inflate_workspacesize OF((void));
-/*
-   Returns the number of bytes that needs to be allocated for a per-
-   stream workspace.  A pointer to this number of bytes should be
-   returned in stream->workspace before calling zlib_fs_inflateInit().
-*/
-
-/* 
-ZEXTERN int ZEXPORT zlib_fs_inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   next_in, avail_in, and workspace must be initialized before by
-   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
-   value depends on the compression method), inflateInit determines the
-   compression method from the zlib header and allocates all data structures
-   accordingly; otherwise the allocation will be deferred to the first call of
-   inflate.  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, Z_VERSION_ERROR if the zlib library version is incompatible with the
-   version assumed by the caller.  msg is set to null if there is no error
-   message. inflateInit does not perform any decompression apart from reading
-   the zlib header if present: this will be done by inflate().  (So next_in and
-   avail_in may be modified, but next_out and avail_out are unchanged.)
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_inflate OF((z_streamp strm, int flush));
-/*
-    inflate decompresses as much data as possible, and stops when the input
-  buffer becomes empty or the output buffer becomes full. It may some
-  introduce some output latency (reading input without producing any output)
-  except when forced to flush.
-
-  The detailed semantics are as follows. inflate 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() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  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 inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    If the parameter flush is set to Z_SYNC_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_SYNC_FLUSH
-  and Z_FINISH, but the current implementation actually flushes as much output
-  as possible anyway.
-
-    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.
-
-     If a preset dictionary is needed at this point (see inflateSetDictionary
-  below), inflate sets strm-adler to the adler32 checksum of the
-  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
-  it sets strm->adler to the adler32 checksum of all output produced
-  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
-  an error code as described below. At the end of the stream, inflate()
-  checks that its computed adler32 checksum is equal to that saved by the
-  compressor and returns Z_STREAM_END only if the checksum is correct.
-
-    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_NEED_DICT if a
-  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
-  corrupted (input stream not conforming to the zlib format or incorrect
-  adler32 checksum), 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.
-*/
-
-
-ZEXTERN int ZEXPORT zlib_fs_inflateEnd OF((z_streamp 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 */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*   
-ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
-                                     int  level,
-                                     int  method,
-                                     int  windowBits,
-                                     int  memLevel,
-                                     int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library.
-
-     The windowBits parameter is the base two logarithm of the window size
-   (the size of the history buffer).  It should be in the range 8..15 for this
-   version of the library. Larger values of this parameter result in better
-   compression at the expense of memory usage. The default value is 15 if
-   deflateInit is used instead.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match).  Filtered data consists mostly of small values with a
-   somewhat random distribution. In this case, the compression algorithm is
-   tuned to compress them better. The effect of Z_FILTERED is to force more
-   Huffman coding and less string matching; it is somewhat intermediate
-   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-   the compression ratio but not the correctness of the compressed output even
-   if it is not set appropriately.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
-   method). msg is set to null if there is no error message.  deflateInit2 does
-   not perform any compression: this will be done by deflate().
-*/
-                            
-ZEXTERN int ZEXPORT zlib_fs_deflateSetDictionary OF((z_streamp strm,
-						     const Bytef *dictionary,
-						     uInt  dictLength));
-/*
-     Initializes the compression dictionary from the given byte sequence
-   without producing any compressed output. This function must be called
-   immediately after deflateInit, deflateInit2 or deflateReset, before any
-   call of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and can be
-   predicted with good accuracy; the data can then be compressed better than
-   with the default empty dictionary.
-
-     Depending on the size of the compression data structures selected by
-   deflateInit or deflateInit2, a part of the dictionary may in effect be
-   discarded, for example if the dictionary is larger than the window size in
-   deflate or deflate2. Thus the strings most likely to be useful should be
-   put at the end of the dictionary, not at the front.
-
-     Upon return of this function, strm->adler is set to the Adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The Adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.)
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent (for example if deflate has already been called for this stream
-   or if the compression method is bsort). deflateSetDictionary does not
-   perform any compression: this will be done by deflate().
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_deflateCopy OF((z_streamp dest,
-					    z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_deflateParams OF((z_streamp strm,
-					      int level,
-					      int strategy));
-/*
-     Dynamically update the compression level and compression strategy.  The
-   interpretation of level and strategy is as in deflateInit2.  This can be
-   used to switch between compression and straight copy of the input data, or
-   to switch to a different kind of input data requiring a different
-   strategy. If the compression level is changed, the input available so far
-   is compressed with the old level (and may be flushed); the new level will
-   take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-/*   
-ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
-                                     int  windowBits));
-
-     This is another version of inflateInit with an extra parameter. The
-   fields next_in, avail_in, zalloc, zfree and opaque 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 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.
-
-      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 a negative
-   memLevel). msg is set to null if there is no error message.  inflateInit2
-   does not perform any decompression apart from reading the zlib header if
-   present: this will be done by inflate(). (So next_in and avail_in may be
-   modified, but next_out and avail_out are unchanged.)
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_inflateSetDictionary OF((z_streamp strm,
-						     const Bytef *dictionary,
-						     uInt  dictLength));
-/*
-     Initializes the decompression dictionary from the given uncompressed byte
-   sequence. This function must be called immediately after a call of inflate
-   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
-   can be determined from the Adler32 value returned by this call of
-   inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_inflateSync OF((z_streamp strm));
-/* 
-    Skips invalid compressed data until a full flush point (see above the
-  description of deflate with Z_FULL_FLUSH) can be found, or until all
-  available input is skipped. No output is provided.
-
-    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
-  if no more input was provided, Z_DATA_ERROR if no flush point 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.
-*/
-
-ZEXTERN int ZEXPORT zlib_fs_inflateReset OF((z_streamp 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).
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-ZEXTERN uLong ZEXPORT zlib_fs_adler32 OF((uLong adler, const 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();
-*/
-
-ZEXTERN uLong ZEXPORT zlib_fs_crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running crc with the bytes buf[0..len-1] and return the updated
-   crc. If buf is NULL, this function returns the required initial value
-   for the crc. Pre- and post-conditioning (one's complement) is performed
-   within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-ZEXTERN int ZEXPORT zlib_fs_deflateInit_ OF((z_streamp strm, int level,
-                                     const char *version, int stream_size));
-ZEXTERN int ZEXPORT zlib_fs_inflateInit_ OF((z_streamp strm,
-                                     const char *version, int stream_size));
-ZEXTERN int ZEXPORT zlib_fs_deflateInit2_ OF((z_streamp strm, int  level, int  method,
-                                      int windowBits, int memLevel,
-                                      int strategy, const char *version,
-                                      int stream_size));
-ZEXTERN int ZEXPORT zlib_fs_inflateInit2_ OF((z_streamp strm, int  windowBits,
-                                      const char *version, int stream_size));
-#define zlib_fs_deflateInit(strm, level) \
-        zlib_fs_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_fs_inflateInit(strm) \
-        zlib_fs_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_fs_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        zlib_fs_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-                      (strategy), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_fs_inflateInit2(strm, windowBits) \
-        zlib_fs_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-
-
-#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-ZEXTERN const char   * ZEXPORT zlib_fs_zError           OF((int err));
-ZEXTERN int            ZEXPORT zlib_fs_inflateSyncPoint OF((z_streamp z));
-ZEXTERN const uLongf * ZEXPORT zlib_fs_get_crc_table    OF((void));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZLIB_H */
diff -urN linux-2.4.20-pre1/include/linux/zutil.h linux-2.4.20-pre2/include/linux/zutil.h
--- linux-2.4.20-pre1/include/linux/zutil.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/include/linux/zutil.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,126 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 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.
+ */
+
+/* @(#) $Id: zutil.h,v 1.1 2000/01/01 03:32:23 davem Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include <linux/zlib.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+        /* common constants */
+
+#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 */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+         /* functions */
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+				       uInt len));
+
+
+                        /* checksum functions */
+
+#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,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+/*
+     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();
+*/
+static inline uLong zlib_adler32(uLong adler,
+				 const 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);
+	    buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+	    s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
+
+#endif /* _Z_UTIL_H */
diff -urN linux-2.4.20-pre1/include/net/irda/discovery.h linux-2.4.20-pre2/include/net/irda/discovery.h
--- linux-2.4.20-pre1/include/net/irda/discovery.h	Tue Jun 19 17:03:47 2001
+++ linux-2.4.20-pre2/include/net/irda/discovery.h	Mon Aug 12 16:34:17 2002
@@ -36,9 +36,17 @@
 #include <net/irda/irda.h>
 #include <net/irda/irqueue.h>
 
-#define DISCOVERY_EXPIRE_TIMEOUT 6*HZ
+#define DISCOVERY_EXPIRE_TIMEOUT (2*sysctl_discovery_timeout*HZ)
 #define DISCOVERY_DEFAULT_SLOTS  0
 
+/* Types of discovery */
+typedef enum {
+	DISCOVERY_LOG,		/* What's in our discovery log */
+	DISCOVERY_ACTIVE,	/* Doing our own discovery on the medium */
+	DISCOVERY_PASSIVE,	/* Peer doing discovery on the medium */
+	EXPIRY_TIMEOUT,		/* Entry expired due to timeout */
+} DISCOVERY_MODE;
+
 #define NICKNAME_MAX_LEN 21
 
 /*
diff -urN linux-2.4.20-pre1/include/net/irda/ircomm_tty.h linux-2.4.20-pre2/include/net/irda/ircomm_tty.h
--- linux-2.4.20-pre1/include/net/irda/ircomm_tty.h	Mon Dec 11 13:33:16 2000
+++ linux-2.4.20-pre2/include/net/irda/ircomm_tty.h	Mon Aug 12 16:34:17 2002
@@ -44,6 +44,11 @@
 #define IRCOMM_TTY_MAJOR 161
 #define IRCOMM_TTY_MINOR 0
 
+/* This is used as an initial value to max_header_size before the proper
+ * value is filled in (5 for ttp, 4 for lmp). This allow us to detect
+ * the state of the underlying connection. - Jean II */
+#define IRCOMM_TTY_HDR_UNITIALISED	32
+
 /*
  * IrCOMM TTY driver state
  */
diff -urN linux-2.4.20-pre1/include/net/irda/irlan_client.h linux-2.4.20-pre2/include/net/irda/irlan_client.h
--- linux-2.4.20-pre1/include/net/irda/irlan_client.h	Mon Dec 11 13:33:09 2000
+++ linux-2.4.20-pre2/include/net/irda/irlan_client.h	Mon Aug 12 16:34:17 2002
@@ -34,7 +34,7 @@
 #include <net/irda/irlan_event.h>
 
 void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout);
-void irlan_client_discovery_indication(discovery_t *, void *);
+void irlan_client_discovery_indication(discovery_t *, DISCOVERY_MODE, void *);
 void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr);
 
 void irlan_client_open_ctrl_tsap( struct irlan_cb *self);
diff -urN linux-2.4.20-pre1/include/net/irda/irlmp.h linux-2.4.20-pre2/include/net/irda/irlmp.h
--- linux-2.4.20-pre1/include/net/irda/irlmp.h	Fri Dec 21 09:42:04 2001
+++ linux-2.4.20-pre2/include/net/irda/irlmp.h	Mon Aug 12 16:34:17 2002
@@ -72,7 +72,7 @@
 	S_END,
 } SERVICE;
 
-typedef void (*DISCOVERY_CALLBACK1) (discovery_t *, void *);
+typedef void (*DISCOVERY_CALLBACK1) (discovery_t *, DISCOVERY_MODE, void *);
 typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *, void *);
 
 typedef struct {
@@ -214,7 +214,7 @@
 				 struct sk_buff *userdata);
 int  irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata);
 
-void irlmp_discovery_confirm(hashbin_t *discovery_log);
+void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE);
 void irlmp_discovery_request(int nslots);
 struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots);
 void irlmp_do_expiry(void);
diff -urN linux-2.4.20-pre1/include/net/iw_handler.h linux-2.4.20-pre2/include/net/iw_handler.h
--- linux-2.4.20-pre1/include/net/iw_handler.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/include/net/iw_handler.h	Mon Aug 12 16:34:17 2002
@@ -1,10 +1,10 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :	2	6.12.01
+ * Version :	3	17.1.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _IW_HANDLER_H
@@ -33,7 +33,7 @@
  *	o The user space interface is tied to ioctl because of the use
  *	  copy_to/from_user.
  *
- * New driver API (2001 -> onward) :
+ * New driver API (2002 -> onward) :
  * -------------------------------
  * The new driver API is just a bunch of standard functions (handlers),
  * each handling a specific Wireless Extension. The driver just export
@@ -206,7 +206,18 @@
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION	2
+#define IW_HANDLER_VERSION	3
+
+/*
+ * Changes :
+ *
+ * V2 to V3
+ * --------
+ *	- Move event definition in <linux/wireless.h>
+ *	- Add Wireless Event support :
+ *		o wireless_send_event() prototype
+ *		o iwe_stream_add_event/point() inline functions
+ */
 
 /**************************** CONSTANTS ****************************/
 
@@ -225,6 +236,7 @@
 #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 */
+#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
 
 /* Handling flags */
 /* Most are not implemented. I just use them as a reminder of some
@@ -233,7 +245,8 @@
 /* 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 */
+#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET : request is ROOT only */
+				/* SET : Omit payload from generated iwevent */
 /* Driver level flags */
 #define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
 
@@ -303,25 +316,6 @@
 	 * '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
@@ -369,6 +363,88 @@
 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 */
+/* Send a single event to user space */
+extern void wireless_send_event(struct net_device *	dev,
+				unsigned int		cmd,
+				union iwreq_data *	wrqu,
+				char *			extra);
+
+/* We may need a function to send a stream of events to user space.
+ * More on that later... */
+
+/************************* INLINE FUNTIONS *************************/
+/*
+ * Function that are so simple that it's more efficient inlining them
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an Wireless Event to a stream of events.
+ */
+static inline char *
+iwe_stream_add_event(char *	stream,		/* Stream of events */
+		     char *	ends,		/* End of stream */
+		     struct iw_event *iwe,	/* Payload */
+		     int	event_len)	/* Real size of payload */
+{
+	/* Check if it's possible */
+	if((stream + event_len) < ends) {
+		iwe->len = event_len;
+		memcpy(stream, (char *) iwe, event_len);
+		stream += event_len;
+	}
+	return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an short Wireless Event containing a pointer to a
+ * stream of events.
+ */
+static inline char *
+iwe_stream_add_point(char *	stream,		/* Stream of events */
+		     char *	ends,		/* End of stream */
+		     struct iw_event *iwe,	/* Payload */
+		     char *	extra)
+{
+	int	event_len = IW_EV_POINT_LEN + iwe->u.data.length;
+	/* Check if it's possible */
+	if((stream + event_len) < ends) {
+		iwe->len = event_len;
+		memcpy(stream, (char *) iwe, IW_EV_POINT_LEN);
+		memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
+		stream += event_len;
+	}
+	return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add a value to a Wireless Event in a stream of events.
+ * Be careful, this one is tricky to use properly :
+ * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
+ */
+static inline char *
+iwe_stream_add_value(char *	event,		/* Event in the stream */
+		     char *	value,		/* Value in event */
+		     char *	ends,		/* End of stream */
+		     struct iw_event *iwe,	/* Payload */
+		     int	event_len)	/* Real size of payload */
+{
+	/* Don't duplicate LCP */
+	event_len -= IW_EV_LCP_LEN;
+
+	/* Check if it's possible */
+	if((value + event_len) < ends) {
+		/* Add new value */
+		memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
+		value += event_len;
+		/* Patch LCP */
+		iwe->len = value - event;
+		memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
+	}
+	return value;
+}
+
+#endif	/* _IW_HANDLER_H */
diff -urN linux-2.4.20-pre1/include/net/tcp.h linux-2.4.20-pre2/include/net/tcp.h
--- linux-2.4.20-pre1/include/net/tcp.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/include/net/tcp.h	Mon Aug 12 16:34:17 2002
@@ -27,6 +27,7 @@
 #include <linux/config.h>
 #include <linux/tcp.h>
 #include <linux/slab.h>
+#include <linux/cache.h>
 #include <net/checksum.h>
 #include <net/sock.h>
 
@@ -117,8 +118,7 @@
 	 * Now align to a new cache line as all the following members
 	 * are often dirty.
 	 */
-	rwlock_t __tcp_lhash_lock
-		__attribute__((__aligned__(SMP_CACHE_BYTES)));
+	rwlock_t __tcp_lhash_lock ____cacheline_aligned;
 	atomic_t __tcp_lhash_users;
 	wait_queue_head_t __tcp_lhash_wait;
 	spinlock_t __tcp_portalloc_lock;
@@ -447,7 +447,6 @@
 extern int sysctl_tcp_retrans_collapse;
 extern int sysctl_tcp_stdurg;
 extern int sysctl_tcp_rfc1337;
-extern int sysctl_tcp_tw_recycle;
 extern int sysctl_tcp_abort_on_overflow;
 extern int sysctl_tcp_max_orphans;
 extern int sysctl_tcp_max_tw_buckets;
diff -urN linux-2.4.20-pre1/ipc/msg.c linux-2.4.20-pre2/ipc/msg.c
--- linux-2.4.20-pre1/ipc/msg.c	Fri Sep 14 14:17:00 2001
+++ linux-2.4.20-pre2/ipc/msg.c	Mon Aug 12 16:34:17 2002
@@ -597,7 +597,7 @@
 	return 0;
 }
 
-int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg)
+static int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg)
 {
 	struct list_head* tmp;
 
@@ -706,7 +706,7 @@
 	return err;
 }
 
-int inline convert_mode(long* msgtyp, int msgflg)
+static int inline convert_mode(long* msgtyp, int msgflg)
 {
 	/* 
 	 *  find message of correct type.
diff -urN linux-2.4.20-pre1/ipc/sem.c linux-2.4.20-pre2/ipc/sem.c
--- linux-2.4.20-pre1/ipc/sem.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/ipc/sem.c	Mon Aug 12 16:34:17 2002
@@ -440,7 +440,7 @@
 	}
 }
 
-int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	int err = -EINVAL;
 
@@ -512,7 +512,7 @@
 	return err;
 }
 
-int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	struct sem_array *sma;
 	struct sem* curr;
@@ -699,7 +699,7 @@
 	}
 }
 
-int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	struct sem_array *sma;
 	int err;
diff -urN linux-2.4.20-pre1/kernel/fork.c linux-2.4.20-pre2/kernel/fork.c
--- linux-2.4.20-pre1/kernel/fork.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/kernel/fork.c	Mon Aug 12 16:34:17 2002
@@ -707,7 +707,7 @@
 
 	/*
 	 * "share" dynamic priority between parent and child, thus the
-	 * total amount of dynamic priorities in the system doesnt change,
+	 * total amount of dynamic priorities in the system doesn't change,
 	 * more scheduling fairness. This is only important in the first
 	 * timeslice, on the long run the scheduling behaviour is unchanged.
 	 */
diff -urN linux-2.4.20-pre1/kernel/ksyms.c linux-2.4.20-pre2/kernel/ksyms.c
--- linux-2.4.20-pre1/kernel/ksyms.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/kernel/ksyms.c	Mon Aug 12 16:34:17 2002
@@ -104,6 +104,7 @@
 EXPORT_SYMBOL(kmem_cache_shrink);
 EXPORT_SYMBOL(kmem_cache_alloc);
 EXPORT_SYMBOL(kmem_cache_free);
+EXPORT_SYMBOL(kmem_cache_size);
 EXPORT_SYMBOL(kmalloc);
 EXPORT_SYMBOL(kfree);
 EXPORT_SYMBOL(vfree);
@@ -122,6 +123,8 @@
 EXPORT_SYMBOL(kunmap_high);
 EXPORT_SYMBOL(highmem_start_page);
 EXPORT_SYMBOL(create_bounce);
+EXPORT_SYMBOL(kmap_prot);
+EXPORT_SYMBOL(kmap_pte);
 #endif
 
 /* filesystem internal functions */
@@ -447,7 +450,8 @@
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 EXPORT_SYMBOL(schedule);
 EXPORT_SYMBOL(schedule_timeout);
-EXPORT_SYMBOL(sys_sched_yield);
+EXPORT_SYMBOL(yield);
+EXPORT_SYMBOL(__cond_resched);
 EXPORT_SYMBOL(jiffies);
 EXPORT_SYMBOL(xtime);
 EXPORT_SYMBOL(do_gettimeofday);
@@ -570,3 +574,6 @@
 
 EXPORT_SYMBOL(tasklist_lock);
 EXPORT_SYMBOL(pidhash);
+
+/* debug */
+EXPORT_SYMBOL(dump_stack);
diff -urN linux-2.4.20-pre1/kernel/pm.c linux-2.4.20-pre2/kernel/pm.c
--- linux-2.4.20-pre1/kernel/pm.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/kernel/pm.c	Mon Aug 12 16:34:17 2002
@@ -30,7 +30,7 @@
  *	Locking notes:
  *		pm_devs_lock can be a semaphore providing pm ops are not called
  *	from an interrupt handler (already a bad idea so no change here). Each
- *	change must be protected so that an unlink of an entry doesnt clash
+ *	change must be protected so that an unlink of an entry doesn't clash
  *	with a pm send - which is permitted to sleep in the current architecture
  *
  *	Module unloads clashing with pm events now work out safely, the module 
diff -urN linux-2.4.20-pre1/kernel/sched.c linux-2.4.20-pre2/kernel/sched.c
--- linux-2.4.20-pre1/kernel/sched.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/kernel/sched.c	Mon Aug 12 16:34:17 2002
@@ -1071,6 +1071,24 @@
 	return 0;
 }
 
+/**
+ * yield - yield the current processor to other threads.
+ *
+ * this is a shortcut for kernel-space yielding - it marks the
+ * thread runnable and calls sys_sched_yield().
+ */
+void yield(void)
+{
+	set_current_state(TASK_RUNNING);
+	sys_sched_yield();
+}
+
+void __cond_resched(void)
+{
+	set_current_state(TASK_RUNNING);
+	schedule();
+}
+
 asmlinkage long sys_sched_get_priority_max(int policy)
 {
 	int ret = -EINVAL;
diff -urN linux-2.4.20-pre1/lib/Config.in linux-2.4.20-pre2/lib/Config.in
--- linux-2.4.20-pre1/lib/Config.in	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/Config.in	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,38 @@
+#
+# Library configuration
+#
+mainmenu_option next_comment
+comment 'Library routines'
+
+#
+# Do we need the compression support?
+#
+if [ "$CONFIG_CRAMFS" = "y" -o \
+     "$CONFIG_PPP_DEFLATE" = "y" -o \
+     "$CONFIG_JFFS2_FS" = "y" -o \
+     "$CONFIG_ZISOFS_FS" = "y" ]; then
+   define_tristate CONFIG_ZLIB_INFLATE y
+else
+  if [ "$CONFIG_CRAMFS" = "m" -o \
+       "$CONFIG_PPP_DEFLATE" = "m" -o \
+       "$CONFIG_JFFS2_FS" = "m" -o \
+       "$CONFIG_ZISOFS_FS" = "m" ]; then
+     define_tristate CONFIG_ZLIB_INFLATE m
+  else
+     tristate 'zlib decompression support' CONFIG_ZLIB_INFLATE
+  fi
+fi
+
+if [ "$CONFIG_PPP_DEFLATE" = "y" -o \
+     "$CONFIG_JFFS2_FS" = "y" ]; then
+   define_tristate CONFIG_ZLIB_DEFLATE y
+else
+  if [ "$CONFIG_PPP_DEFLATE" = "m" -o \
+       "$CONFIG_JFFS2_FS" = "m" ]; then
+     define_tristate CONFIG_ZLIB_DEFLATE m
+  else
+     tristate 'zlib compression support' CONFIG_ZLIB_DEFLATE
+  fi
+fi
+
+endmenu
diff -urN linux-2.4.20-pre1/lib/Makefile linux-2.4.20-pre2/lib/Makefile
--- linux-2.4.20-pre1/lib/Makefile	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/lib/Makefile	Mon Aug 12 16:34:17 2002
@@ -10,7 +10,8 @@
 
 export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o rbtree.o
 
-obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
+obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \
+	 bust_spinlocks.o rbtree.o dump_stack.o
 
 obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
@@ -19,4 +20,10 @@
   obj-y += dec_and_lock.o
 endif
 
+subdir-$(CONFIG_ZLIB_INFLATE) += zlib_inflate
+subdir-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate
+
+# Include the subdirs, if necessary.
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
+
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/lib/dump_stack.c linux-2.4.20-pre2/lib/dump_stack.c
--- linux-2.4.20-pre1/lib/dump_stack.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/dump_stack.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,13 @@
+/*
+ * Provide a default dump_stack() function for architectures
+ * which don't implementtheir own.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+void dump_stack(void)
+{
+	printk(KERN_NOTICE
+		"This architecture does not implement dump_stack()\n");
+}
diff -urN linux-2.4.20-pre1/lib/zlib_deflate/Makefile linux-2.4.20-pre2/lib/zlib_deflate/Makefile
--- linux-2.4.20-pre1/lib/zlib_deflate/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_deflate/Makefile	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,18 @@
+#
+# This is a modified version of zlib, which does all memory
+# allocation ahead of time.
+#
+# This is the compression code, see zlib_inflate for the
+# decompression code.
+#
+
+O_TARGET    := zlib_deflate.o
+
+export-objs := deflate_syms.o
+
+obj-y := deflate.o deftree.o deflate_syms.o
+obj-m := $(O_TARGET)
+
+EXTRA_CFLAGS += -I $(TOPDIR)/lib/zlib_deflate
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/lib/zlib_deflate/deflate.c linux-2.4.20-pre2/lib/zlib_deflate/deflate.c
--- linux-2.4.20-pre1/lib/zlib_deflate/deflate.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_deflate/deflate.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,1250 @@
+/* +++ deflate.c */
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/zutil.h>
+#include "defutil.h"
+
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG_ZLIB
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    memset((charf *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int zlib_deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return zlib_deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS,
+			      DEF_MEM_LEVEL,
+			      Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int zlib_deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+		       version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int noheader = 0;
+    static char* my_version = ZLIB_VERSION;
+    deflate_workspace *mem;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+	return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+    mem = (deflate_workspace *) strm->workspace;
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) &(mem->deflate_memory);
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->noheader = noheader;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) mem->window_memory;
+    s->prev   = (Posf *)  mem->prev_memory;
+    s->head   = (Posf *)  mem->head_memory;
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) mem->overlay_memory;
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return zlib_deflateReset(strm);
+}
+
+/* ========================================================================= */
+int zlib_deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+	return Z_STREAM_ERROR;
+
+    s = (deflate_state *) strm->state;
+    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
+
+    strm->adler = zlib_adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+	length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+	dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+    }
+    memcpy((charf *)s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+	INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int zlib_deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+    
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL;
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    strm->adler = 1;
+    s->last_flush = Z_NO_FLUSH;
+
+    zlib_tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int zlib_deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    if (level == Z_DEFAULT_COMPRESSION) {
+	level = 6;
+    }
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+	return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+	/* Flush the last buffer: */
+	err = zlib_deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+	s->level = level;
+	s->max_lazy_match   = configuration_table[level].max_lazy;
+	s->good_match       = configuration_table[level].good_length;
+	s->nice_match       = configuration_table[level].nice_length;
+	s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}   
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    deflate_state *s = (deflate_state *) strm->state;
+    unsigned len = s->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    if (strm->next_out != Z_NULL) {
+	memcpy(strm->next_out, s->pending_out, len);
+	strm->next_out += len;
+    }
+    s->pending_out += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    s->pending -= len;
+    if (s->pending == 0) {
+        s->pending_out = s->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int zlib_deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+	flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) strm->state;
+
+    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
+	(s->status == FINISH_STATE && flush != Z_FINISH)) {
+        return Z_STREAM_ERROR;
+    }
+    if (strm->avail_out == 0) return Z_BUF_ERROR;
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the zlib header */
+    if (s->status == INIT_STATE) {
+
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags = (s->level-1) >> 1;
+
+        if (level_flags > 3) level_flags = 3;
+        header |= (level_flags << 6);
+	if (s->strstart != 0) header |= PRESET_DICT;
+        header += 31 - (header % 31);
+
+        s->status = BUSY_STATE;
+        putShortMSB(s, header);
+
+	/* Save the adler32 of the preset dictionary: */
+	if (s->strstart != 0) {
+	    putShortMSB(s, (uInt)(strm->adler >> 16));
+	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+	}
+	strm->adler = 1L;
+    }
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+	    /* Since avail_out is 0, deflate will be called again with
+	     * more output space, but possibly with both pending and
+	     * avail_in equal to zero. There won't be anything to do,
+	     * but this is not an error situation so make sure we
+	     * return OK instead of BUF_ERROR at next call of deflate:
+             */
+	    s->last_flush = -1;
+	    return Z_OK;
+	}
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+	       flush != Z_FINISH) {
+        return Z_BUF_ERROR;
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        return Z_BUF_ERROR;
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+	bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+	    if (strm->avail_out == 0) {
+	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+	    }
+	    return Z_OK;
+	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+	     * of deflate should use the same flush parameter to make sure
+	     * that the flush is complete. So we don't have to output an
+	     * empty block here, this will be done at next call. This also
+	     * ensures that for a very small output buffer, we emit at most
+	     * one empty block.
+	     */
+	}
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                zlib_tr_align(s);
+	    } else if (flush == Z_PACKET_FLUSH) {
+		/* Output just the 3-bit `stored' block type value,
+		   but not a zero length. */
+		zlib_tr_stored_type_only(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                zlib_tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+	    if (strm->avail_out == 0) {
+	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+	      return Z_OK;
+	    }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    putShortMSB(s, (uInt)(strm->adler >> 16));
+    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    s->noheader = -1; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int zlib_deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    status = s->status;
+    if (status != INIT_STATE && status != BUSY_STATE &&
+	status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ */
+int zlib_deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+    deflate_workspace *mem;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = (deflate_state *) source->state;
+
+    *dest = *source;
+
+    mem = (deflate_workspace *) dest->workspace;
+
+    ds = &(mem->deflate_memory);
+
+    dest->state = (struct internal_state FAR *) ds;
+    *ds = *ss;
+    ds->strm = dest;
+
+    ds->window = (Bytef *) mem->window_memory;
+    ds->prev   = (Posf *)  mem->prev_memory;
+    ds->head   = (Posf *)  mem->head_memory;
+    overlay = (ushf *) mem->overlay_memory;
+    ds->pending_buf = (uchf *) overlay;
+
+    memcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    memcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    memcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    memcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (!((deflate_state *)(strm->state))->noheader) {
+        strm->adler = zlib_adler32(strm->adler, strm->next_in, len);
+    }
+    memcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return best_len;
+    return s->lookahead;
+}
+
+#ifdef DEBUG_ZLIB
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (memcmp((charf *)s->window + match,
+                (charf *)s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+		start, match, length);
+        do {
+	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+	} while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+            more = wsize;
+
+        } else if (more == (unsigned)(-1)) {
+            /* Very unlikely, but possible on 16 bit machine if strstart == 0
+             * and lookahead == 1 (input done one byte at time)
+             */
+            more--;
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            memcpy((charf *)s->window, (charf *)s->window+wsize,
+                   (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   zlib_tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+		(ulg)((long)s->strstart - s->block_start), \
+		(eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+		   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+	Assert(s->block_start >= 0L, "block gone");
+
+	s->strstart += s->lookahead;
+	s->lookahead = 0;
+
+	/* Emit a stored block if pending_buf will be full: */
+ 	max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+	    /* strstart == 0 is possible when wraparound on 16-bit machine */
+	    s->lookahead = (uInt)(s->strstart - max_start);
+	    s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+	}
+	/* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+	}
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            bflush = zlib_tr_tally(s, s->strstart - s->match_start,
+                               s->match_length - MIN_MATCH);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in hash table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++; 
+            } else {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            bflush = zlib_tr_tally (s, 0, s->window[s->strstart]);
+            s->lookahead--;
+            s->strstart++; 
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+                 (s->match_length == MIN_MATCH &&
+                  s->strstart - s->match_start > TOO_FAR))) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            bflush = zlib_tr_tally(s, s->strstart -1 - s->prev_match,
+				   s->prev_length - MIN_MATCH);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            if (zlib_tr_tally (s, 0, s->window[s->strstart-1])) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        zlib_tr_tally (s, 0, s->window[s->strstart-1]);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+ZEXTERN int ZEXPORT zlib_deflate_workspacesize ()
+{
+    return sizeof(deflate_workspace);
+}
diff -urN linux-2.4.20-pre1/lib/zlib_deflate/deflate_syms.c linux-2.4.20-pre2/lib/zlib_deflate/deflate_syms.c
--- linux-2.4.20-pre1/lib/zlib_deflate/deflate_syms.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_deflate/deflate_syms.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,21 @@
+/*
+ * linux/lib/zlib_deflate/deflate_syms.c
+ *
+ * Exported symbols for the deflate functionality.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/zlib.h>
+
+EXPORT_SYMBOL(zlib_deflate_workspacesize);
+EXPORT_SYMBOL(zlib_deflate);
+EXPORT_SYMBOL(zlib_deflateInit_);
+EXPORT_SYMBOL(zlib_deflateInit2_);
+EXPORT_SYMBOL(zlib_deflateEnd);
+EXPORT_SYMBOL(zlib_deflateReset);
+EXPORT_SYMBOL(zlib_deflateCopy);
+EXPORT_SYMBOL(zlib_deflateParams);
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.20-pre1/lib/zlib_deflate/deftree.c linux-2.4.20-pre2/lib/zlib_deflate/deftree.c
--- linux-2.4.20-pre1/lib/zlib_deflate/deftree.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_deflate/deftree.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,1096 @@
+/* +++ trees.c */
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
+
+/* #include "deflate.h" */
+
+#include <linux/zutil.h>
+#include "defutil.h"
+
+#ifdef DEBUG_ZLIB
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {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};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {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};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see zlib_tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifndef DEBUG_ZLIB
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG_ZLIB */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG_ZLIB
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG_ZLIB */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG_ZLIB */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables. In a multi-threaded environment,
+ * this function may be called by two threads concurrently, but this is
+ * harmless since both invocations do exactly the same thing.
+ */
+local void tr_static_init()
+{
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+}
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void zlib_tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->compressed_len = 0L;
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG_ZLIB
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void zlib_tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* Send just the `stored block' type code without any length bytes or data.
+ */
+void zlib_tr_stored_type_only(s)
+    deflate_state *s;
+{
+    send_bits(s, (STORED_BLOCK << 1), 3);
+    bi_windup(s);
+    s->compressed_len = (s->compressed_len + 3) & ~7L;
+}
+
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void zlib_tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+        s->compressed_len += 10L;
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg zlib_tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+	 /* Check if the file is ascii or binary */
+	if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+	/* Construct the literal and distance trees */
+	build_tree(s, (tree_desc *)(&(s->l_desc)));
+	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+
+	build_tree(s, (tree_desc *)(&(s->d_desc)));
+	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+	/* At this point, opt_len and static_len are the total bit lengths of
+	 * the compressed block data, excluding the tree representations.
+	 */
+
+	/* Build the bit length tree for the above two trees, and get the index
+	 * in bl_order of the last bit length code to send.
+	 */
+	max_blindex = build_bl_tree(s);
+
+	/* Determine the best encoding. Compute first the block length in bytes*/
+	opt_lenb = (s->opt_len+3+7)>>3;
+	static_lenb = (s->static_len+3+7)>>3;
+
+	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+		s->last_lit));
+
+	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+    /* If compression failed and this is the first and last block,
+     * and if the .zip file can be seeked (to rewrite the local header),
+     * the whole file is transformed into a stored file:
+     */
+#ifdef STORED_FILE_OK
+#  ifdef FORCE_STORED_FILE
+    if (eof && s->compressed_len == 0L) { /* force stored file */
+#  else
+    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
+#  endif
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == (charf*)0) error ("block vanished");
+
+        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
+        s->compressed_len = stored_len << 3;
+        s->method = STORED;
+    } else
+#endif /* STORED_FILE_OK */
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        zlib_tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+        s->compressed_len += 3 + s->static_len;
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+        s->compressed_len += 3 + s->opt_len;
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+        s->compressed_len += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+
+    return s->compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int zlib_tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "zlib_tr_tally: bad match");
+
+        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0xfff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n = 0;
+    unsigned ascii_freq = 0;
+    unsigned bin_freq = 0;
+    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);   
+        put_short(s, (ush)~len);
+#ifdef DEBUG_ZLIB
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG_ZLIB
+    s->bits_sent += (ulg)len<<3;
+#endif
+    /* bundle up the put_byte(s, *buf++) calls */
+    memcpy(&s->pending_buf[s->pending], buf, len);
+    s->pending += len;
+}
+
diff -urN linux-2.4.20-pre1/lib/zlib_deflate/defutil.h linux-2.4.20-pre2/lib/zlib_deflate/defutil.h
--- linux-2.4.20-pre1/lib/zlib_deflate/defutil.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_deflate/defutil.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,335 @@
+
+
+
+#define Assert(err, str) 
+#define Trace(dummy) 
+#define Tracev(dummy) 
+#define Tracecv(err, dummy) 
+#define Tracevv(dummy) 
+
+
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct deflate_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    int   pending;       /* nb of bytes in the pending buffer */
+    int   noheader;      /* suppress zlib header and adler32 */
+    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    ulg compressed_len; /* total bit length of compressed file */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG_ZLIB
+    ulg bits_sent;      /* bit length of the compressed data */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+typedef struct deflate_workspace {
+    /* State memory for the deflator */
+    deflate_state deflate_memory;
+    Byte window_memory[2 * (1 << MAX_WBITS)];
+    Pos prev_memory[1 << MAX_WBITS];
+    Pos head_memory[1 << (MAX_MEM_LEVEL + 7)];
+    char overlay_memory[(1 << (MAX_MEM_LEVEL + 6)) * (sizeof(ush)+2)];
+} deflate_workspace;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void zlib_tr_init         OF((deflate_state *s));
+int  zlib_tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+ulg  zlib_tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+			      int eof));
+void zlib_tr_align        OF((deflate_state *s));
+void zlib_tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+			      int eof));
+void zlib_tr_stored_type_only OF((deflate_state *));
+
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+static inline unsigned bi_reverse(unsigned code, /* the value to invert */
+				  int len)       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+static inline void bi_flush(deflate_state *s)
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+static inline void bi_windup(deflate_state *s)
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG_ZLIB
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/Makefile linux-2.4.20-pre2/lib/zlib_inflate/Makefile
--- linux-2.4.20-pre1/lib/zlib_inflate/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/Makefile	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,26 @@
+#
+# This is a modified version of zlib, which does all memory
+# allocation ahead of time.
+#
+# This is only the decompression, see zlib_deflate for the
+# the compression
+#
+# Decompression needs to be serialized for each memory
+# allocation.
+#
+# (The upsides of the simplification is that you can't get in
+# any nasty situations wrt memory management, and that the
+# uncompression can be done without blocking on allocation).
+#
+
+O_TARGET    := zlib_inflate.o
+
+export-objs := inflate_syms.o
+
+obj-y := infblock.o infcodes.o inffast.o inflate.o \
+	 inftrees.o infutil.o inflate_syms.o
+obj-m := $(O_TARGET)
+
+EXTRA_CFLAGS += -I $(TOPDIR)/lib/zlib_inflate
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/infblock.c linux-2.4.20-pre2/lib/zlib_inflate/infblock.c
--- linux-2.4.20-pre1/lib/zlib_inflate/infblock.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/infblock.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,355 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state;
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const 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.
+ */
+
+
+void zlib_inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  if (c != Z_NULL)
+    *c = s->check;
+  if (s->mode == CODES)
+    zlib_inflate_codes_free(s->sub.decode.codes, z);
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+}
+
+inflate_blocks_statef *zlib_inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  s = &WS(z)->working_blocks_state;
+  s->hufts = WS(z)->working_hufts;
+  s->window = WS(z)->working_window;
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  zlib_inflate_blocks_reset(s, z, Z_NULL);
+  return s;
+}
+
+
+int zlib_inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp 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 */
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            zlib_inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+            s->sub.decode.codes = zlib_inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = B_BAD;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = B_BAD;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      memcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      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 = B_BAD;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      {
+      	s->sub.trees.blens = WS(z)->working_blens;
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      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 = zlib_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+				  &s->sub.trees.tb, s->hufts, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = B_BAD;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      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 & zlib_inflate_mask[t]);
+        t = h->bits;
+        c = h->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 & zlib_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 = B_BAD;
+            z->msg = (char*)"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;
+        }
+      }
+      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 = zlib_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+				       s->sub.trees.blens, &bl, &bd, &tl, &td,
+				       s->hufts, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = B_BAD;
+          r = t;
+          LEAVE
+        }
+        if ((c = zlib_inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        s->sub.decode.codes = c;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = zlib_inflate_codes(s, z, r)) != Z_STREAM_END)
+        return zlib_inflate_flush(s, z, r);
+      r = Z_OK;
+      zlib_inflate_codes_free(s->sub.decode.codes, z);
+      LOAD
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = B_DONE;
+    case B_DONE:
+      r = Z_STREAM_END;
+      LEAVE
+    case B_BAD:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+int zlib_inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  zlib_inflate_blocks_reset(s, z, Z_NULL);
+  return Z_OK;
+}
+
+
+void zlib_inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt  n;
+{
+  memcpy(s->window, d, n);
+  s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
+ * IN assertion: s != Z_NULL
+ */
+int zlib_inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+  return s->mode == LENS;
+}
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/infblock.h linux-2.4.20-pre2/lib/zlib_inflate/infblock.h
--- linux-2.4.20-pre1/lib/zlib_inflate/infblock.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/infblock.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,44 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1998 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.
+ */
+
+#ifndef _INFBLOCK_H
+#define _INFBLOCK_H
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * zlib_inflate_blocks_new OF((
+    z_streamp z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+extern int zlib_inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));                      /* initial return code */
+
+extern void zlib_inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern int zlib_inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_streamp));
+
+extern void zlib_inflate_set_dictionary OF((
+    inflate_blocks_statef *s,
+    const Bytef *d,  /* dictionary */
+    uInt  n));       /* dictionary length */
+
+extern int zlib_inflate_blocks_sync_point OF((
+    inflate_blocks_statef *s));
+
+#endif /* _INFBLOCK_H */
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/infcodes.c linux-2.4.20-pre2/lib/zlib_inflate/infcodes.c
--- linux-2.4.20-pre1/lib/zlib_inflate/infcodes.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/infcodes.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,204 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+inflate_codes_statef *zlib_inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+  inflate_codes_statef *c;
+
+  c = &WS(z)->working_state;
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+  }
+  return c;
+}
+
+
+int zlib_inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp 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 = zlib_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 & zlib_inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = 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 + t->base;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"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 & zlib_inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & zlib_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 + t->base;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"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 & zlib_inflate_mask[j];
+      DUMPBITS(j)
+      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 - (uInt)(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 */
+      if (k > 7)        /* return unused byte, if any */
+      {
+        k -= 8;
+        n++;
+        p--;            /* can always return one */
+      }
+      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
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void zlib_inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+}
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/infcodes.h linux-2.4.20-pre2/lib/zlib_inflate/infcodes.h
--- linux-2.4.20-pre1/lib/zlib_inflate/infcodes.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/infcodes.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,33 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1998 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.
+ */
+
+#ifndef _INFCODES_H
+#define _INFCODES_H
+
+#include "infblock.h"
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *zlib_inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_streamp ));
+
+extern int zlib_inflate_codes OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+extern void zlib_inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_streamp ));
+
+#endif /* _INFCODES_H */
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/inffast.c linux-2.4.20-pre2/lib/zlib_inflate/inffast.c
--- linux-2.4.20-pre1/lib/zlib_inflate/inffast.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/inffast.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,161 @@
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state;
+
+/* simplify the use of the inflate_huft type with some defines */
+#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 {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* 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. */
+
+int zlib_inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp 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 = zlib_inflate_mask[bl];
+  md = zlib_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)
+      *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 & zlib_inflate_mask[e]);
+        DUMPBITS(e)
+
+        /* 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 & zlib_inflate_mask[e]);
+            DUMPBITS(e)
+
+            /* 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 - (uInt)(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)
+          {
+            t += t->base;
+            e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop;
+          }
+          else
+          {
+            z->msg = (char*)"invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        t += t->base;
+        if ((e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = (char*)"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;
+}
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/inffast.h linux-2.4.20-pre2/lib/zlib_inflate/inffast.h
--- linux-2.4.20-pre1/lib/zlib_inflate/inffast.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/inffast.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,17 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1998 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.
+ */
+
+extern int zlib_inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_streamp ));
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/inffixed.h linux-2.4.20-pre2/lib/zlib_inflate/inffixed.h
--- linux-2.4.20-pre1/lib/zlib_inflate/inffixed.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/inffixed.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* 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 uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+  };
+local inflate_huft fixed_td[] = {
+    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+  };
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/inflate.c linux-2.4.20-pre2/lib/zlib_inflate/inflate.c
--- linux-2.4.20-pre1/lib/zlib_inflate/inflate.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/inflate.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,382 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/module.h>
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "infutil.h"
+
+int ZEXPORT zlib_inflate_workspacesize(void)
+{
+  return sizeof(struct inflate_workspace);
+}
+
+
+int ZEXPORT zlib_inflateReset(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->workspace == 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;
+  zlib_inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+  return Z_OK;
+}
+
+
+int ZEXPORT zlib_inflateEnd(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    zlib_inflate_blocks_free(z->state->blocks, z);
+  z->state = Z_NULL;
+  return Z_OK;
+}
+
+
+int ZEXPORT zlib_inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+      stream_size != sizeof(z_stream) || z->workspace == Z_NULL)
+      return Z_VERSION_ERROR;
+
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->msg = Z_NULL;
+  z->state = &WS(z)->internal_state;
+  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)
+  {
+    zlib_inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      zlib_inflate_blocks_new(z, z->state->nowrap ? Z_NULL : zlib_adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    zlib_inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+
+  /* reset state */
+  zlib_inflateReset(z);
+  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.
+ */
+static int zlib_inflate_packet_flush(inflate_blocks_statef *s)
+{
+    if (s->mode != LENS)
+	return Z_DATA_ERROR;
+    s->mode = TYPE;
+    return Z_OK;
+}
+
+
+int ZEXPORT zlib_inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+  return zlib_inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=trv;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT zlib_inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r, trv;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  trv = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"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 = I_BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = I_BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+        break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = I_BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = zlib_inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+	  r = zlib_inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = I_BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r == Z_OK)
+        r = trv;
+      if (r != Z_STREAM_END)
+        return r;
+      r = trv;
+      zlib_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = I_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 = I_BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = I_DONE;
+    case I_DONE:
+      return Z_STREAM_END;
+    case I_BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+ empty:
+  if (f != Z_PACKET_FLUSH)
+    return r;
+  z->state->mode = I_BAD;
+  z->msg = (char *)"need more for packet flush";
+  z->state->sub.marker = 0;       /* can try inflateSync */
+  return Z_DATA_ERROR;
+}
+
+
+int ZEXPORT zlib_inflateSync(z)
+z_streamp 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 != I_BAD)
+  {
+    z->state->mode = I_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)
+  {
+    static const Byte mark[4] = {0, 0, 0xff, 0xff};
+    if (*p == mark[m])
+      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;
+  zlib_inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ * but removes the length bytes of the resulting empty stored block. When
+ * decompressing, PPP checks that at the end of input packet, inflate is
+ * waiting for these length bytes.
+ */
+int ZEXPORT zlib_inflateSyncPoint(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+    return Z_STREAM_ERROR;
+  return zlib_inflate_blocks_sync_point(z->state->blocks);
+}
+
+/*
+ * 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.
+ */
+static int zlib_inflate_addhistory(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);
+	memcpy(q, p, t);
+	q += t;
+	p += t;
+	n -= t;
+	z->total_out += t;
+	s->read = q;    /* drag read pointer forward */
+/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
+	if (q == s->end) {
+	    s->read = q = s->window;
+	    m = WAVAIL;
+	}
+    }
+    UPDATE
+    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.
+ */
+
+int ZEXPORT zlib_inflateIncomp(z)
+z_stream *z;
+{
+    if (z->state->mode != BLOCKS)
+	return Z_DATA_ERROR;
+    return zlib_inflate_addhistory(z->state->blocks, z);
+}
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/inflate_syms.c linux-2.4.20-pre2/lib/zlib_inflate/inflate_syms.c
--- linux-2.4.20-pre1/lib/zlib_inflate/inflate_syms.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/inflate_syms.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,22 @@
+/*
+ * linux/lib/zlib_inflate/inflate_syms.c
+ *
+ * Exported symbols for the inflate functionality.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/zlib.h>
+
+EXPORT_SYMBOL(zlib_inflate_workspacesize);
+EXPORT_SYMBOL(zlib_inflate);
+EXPORT_SYMBOL(zlib_inflateInit_);
+EXPORT_SYMBOL(zlib_inflateInit2_);
+EXPORT_SYMBOL(zlib_inflateEnd);
+EXPORT_SYMBOL(zlib_inflateSync);
+EXPORT_SYMBOL(zlib_inflateReset);
+EXPORT_SYMBOL(zlib_inflateSyncPoint);
+EXPORT_SYMBOL(zlib_inflateIncomp); 
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/inftrees.c linux-2.4.20-pre2/lib/zlib_inflate/inftrees.c
--- linux-2.4.20-pre1/lib/zlib_inflate/inftrees.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/inftrees.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,391 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "inftrees.h"
+#include "infutil.h"
+
+static const char inflate_copyright[] =
+   " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+struct internal_state;
+
+/* simplify the use of the inflate_huft type with some defines */
+#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 */
+    const uIntf *,      /* list of base values for non-simple codes */
+    const uIntf *,      /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    inflate_huft *,     /* space for trees */
+    uInt *,             /* hufts used in space */
+    uIntf * ));         /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* 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};
+        /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* 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, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* 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 const uInt cpdext[30] = { /* 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 */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= 288) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+const uIntf *d;         /* list of base values for non-simple codes */
+const uIntf *e;         /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+inflate_huft *hp;       /* space for trees */
+uInt *hn;               /* hufts used in space */
+uIntf *v;               /* working area: values in order of bit length */
+/* 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 (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) */
+  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
+  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 */
+  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);
+  n = x[g];                     /* set n to length of v */
+
+
+  /* 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 = g - w;
+        z = z > (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 new table */
+        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
+          return Z_MEM_ERROR;   /* not enough memory */
+        u[h] = q = hp + *hn;
+        *hn += z;
+
+        /* 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 */
+          j = i >> (w - l);
+          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+        else
+          *t = q;               /* first table is returned result */
+      }
+
+      /* 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 */
+      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
+      while ((i & mask) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+        mask = (1 << w) - 1;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int zlib_inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+  
+  v = WS(z)->tree_work_area_1;
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+                 tb, bb, hp, &hn, v);
+  if (r == Z_DATA_ERROR)
+    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+int zlib_inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, 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 */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+
+  /* allocate work area */
+  v = WS(z)->tree_work_area_2;
+
+  /* build literal/length tree */
+  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+  if (r != Z_OK || *bl == 0)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+  if (r != Z_OK || (*bd == 0 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#include "inffixed.h"
+
+
+int zlib_inflate_trees_fixed(bl, bd, tl, td, z)
+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_streamp z;             /* for memory allocation */
+{
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/inftrees.h linux-2.4.20-pre2/lib/zlib_inflate/inftrees.h
--- linux-2.4.20-pre1/lib/zlib_inflate/inftrees.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/inftrees.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,63 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1998 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). */
+
+#ifndef _INFTREES_H
+#define _INFTREES_H
+
+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 pad;           /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
+  uInt base;            /* literal, length base, distance base,
+                           or table offset */
+};
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1004 huft structures (850 for length/literals
+   and 154 for distances, the latter actually the result of an
+   exhaustive search).  The actual maximum is not known, but the
+   value below is more than safe. */
+#define MANY 1440
+
+extern int zlib_inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int zlib_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 */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int zlib_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 */
+    z_streamp));                /* for memory allocation */
+
+#endif /* _INFTREES_H */
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/infutil.c linux-2.4.20-pre2/lib/zlib_inflate/infutil.c
--- linux-2.4.20-pre1/lib/zlib_inflate/infutil.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/infutil.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,87 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state;
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt zlib_inflate_mask[17] = {
+    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 */
+int zlib_inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt n;
+  Bytef *p;
+  Bytef *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)
+    z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  memcpy(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)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    memcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
diff -urN linux-2.4.20-pre1/lib/zlib_inflate/infutil.h linux-2.4.20-pre2/lib/zlib_inflate/infutil.h
--- linux-2.4.20-pre1/lib/zlib_inflate/infutil.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/lib/zlib_inflate/infutil.h	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,197 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1998 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.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+#include <linux/zconf.h>
+#include "inftrees.h"
+#include "infcodes.h"
+
+typedef 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 */
+      B_DONE,   /* finished last block, done */
+      B_BAD}    /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_block_mode  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 */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      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 */
+  inflate_huft *hufts;  /* single malloc for tree space */
+  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 zlib_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 (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=zlib_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}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt zlib_inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int zlib_inflate_flush OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+/* inflate private state */
+typedef enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      DICT4,    /* four dictionary check bytes to go */
+      DICT3,    /* three dictionary check bytes to go */
+      DICT2,    /* two dictionary check bytes to go */
+      DICT1,    /* one dictionary check byte to go */
+      DICT0,    /* waiting for inflateSetDictionary */
+      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 */
+      I_DONE,   /* finished check, done */
+      I_BAD}    /* got an error--stay here */
+inflate_mode;
+
+struct internal_state {
+
+  /* mode */
+  inflate_mode  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 */
+
+};
+
+/* inflate codes private state */
+typedef 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 */
+inflate_codes_mode;
+
+struct inflate_codes_state {
+
+  /* mode */
+  inflate_codes_mode 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 */
+
+};
+
+/* memory allocation for inflation */
+
+struct inflate_workspace {
+	inflate_codes_statef working_state;
+	struct inflate_blocks_state working_blocks_state;
+	struct internal_state internal_state;
+	unsigned int tree_work_area_1[19];
+	unsigned int tree_work_area_2[288];
+	unsigned working_blens[258 + 0x1f + 0x1f];
+	inflate_huft working_hufts[MANY];
+	unsigned char working_window[1 << MAX_WBITS];
+};
+
+#define WS(z) ((struct inflate_workspace *)(z->workspace))
+
+#endif
diff -urN linux-2.4.20-pre1/mm/bootmem.c linux-2.4.20-pre2/mm/bootmem.c
--- linux-2.4.20-pre1/mm/bootmem.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/mm/bootmem.c	Mon Aug 12 16:34:17 2002
@@ -26,6 +26,7 @@
  */
 unsigned long max_low_pfn;
 unsigned long min_low_pfn;
+unsigned long max_pfn;
 
 /* return the number of _pages_ that will be allocated for the boot bitmap */
 unsigned long __init bootmem_bootmap_pages (unsigned long pages)
@@ -324,15 +325,14 @@
 
 void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal)
 {
-	pg_data_t *pgdat = pgdat_list;
+	pg_data_t *pgdat;
 	void *ptr;
 
-	while (pgdat) {
+	for_each_pgdat(pgdat)
 		if ((ptr = __alloc_bootmem_core(pgdat->bdata, size,
 						align, goal)))
 			return(ptr);
-		pgdat = pgdat->node_next;
-	}
+
 	/*
 	 * Whoops, we cannot satisfy the allocation request.
 	 */
diff -urN linux-2.4.20-pre1/mm/filemap.c linux-2.4.20-pre2/mm/filemap.c
--- linux-2.4.20-pre1/mm/filemap.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/mm/filemap.c	Mon Aug 12 16:34:17 2002
@@ -154,11 +154,14 @@
 
 		if (mapping) {
 			spin_lock(&pagecache_lock);
-			list_del(&page->list);
-			list_add(&page->list, &mapping->dirty_pages);
+			mapping = page->mapping;
+			if (mapping) {	/* may have been truncated */
+				list_del(&page->list);
+				list_add(&page->list, &mapping->dirty_pages);
+			}
 			spin_unlock(&pagecache_lock);
 
-			if (mapping->host)
+			if (mapping && mapping->host)
 				mark_inode_dirty_pages(mapping->host);
 		}
 	}
diff -urN linux-2.4.20-pre1/mm/highmem.c linux-2.4.20-pre2/mm/highmem.c
--- linux-2.4.20-pre1/mm/highmem.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/mm/highmem.c	Mon Aug 12 16:34:17 2002
@@ -332,7 +332,7 @@
 	if (page)
 		return page;
 	/*
-	 * No luck. First, kick the VM so it doesnt idle around while
+	 * No luck. First, kick the VM so it doesn't idle around while
 	 * we are using up our emergency rations.
 	 */
 	wakeup_bdflush();
@@ -370,7 +370,7 @@
 	if (bh)
 		return bh;
 	/*
-	 * No luck. First, kick the VM so it doesnt idle around while
+	 * No luck. First, kick the VM so it doesn't idle around while
 	 * we are using up our emergency rations.
 	 */
 	wakeup_bdflush();
diff -urN linux-2.4.20-pre1/mm/page_alloc.c linux-2.4.20-pre2/mm/page_alloc.c
--- linux-2.4.20-pre1/mm/page_alloc.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/mm/page_alloc.c	Mon Aug 12 16:34:17 2002
@@ -29,7 +29,10 @@
 LIST_HEAD(active_list);
 pg_data_t *pgdat_list;
 
-/* Used to look up the address of the struct zone encoded in page->zone */
+/*
+ * Used by page_zone() to look up the address of the struct zone whose
+ * id is encoded in the upper bits of page->flags
+ */
 zone_t *zone_table[MAX_NR_ZONES*MAX_NR_NODES];
 EXPORT_SYMBOL(zone_table);
 
@@ -79,11 +82,15 @@
 	struct page *base;
 	zone_t *zone;
 
-	/* Yes, think what happens when other parts of the kernel take 
+	/*
+	 * Yes, think what happens when other parts of the kernel take 
 	 * a reference to a page in order to pin it for io. -ben
 	 */
-	if (PageLRU(page))
+	if (PageLRU(page)) {
+		if (unlikely(in_interrupt()))
+			BUG();
 		lru_cache_del(page);
+	}
 
 	if (page->buffers)
 		BUG();
@@ -456,16 +463,12 @@
  */
 unsigned int nr_free_pages (void)
 {
-	unsigned int sum;
+	unsigned int sum = 0;
 	zone_t *zone;
-	pg_data_t *pgdat = pgdat_list;
 
-	sum = 0;
-	while (pgdat) {
-		for (zone = pgdat->node_zones; zone < pgdat->node_zones + MAX_NR_ZONES; zone++)
-			sum += zone->free_pages;
-		pgdat = pgdat->node_next;
-	}
+	for_each_zone(zone)
+		sum += zone->free_pages;
+
 	return sum;
 }
 
@@ -474,10 +477,10 @@
  */
 unsigned int nr_free_buffer_pages (void)
 {
-	pg_data_t *pgdat = pgdat_list;
+	pg_data_t *pgdat;
 	unsigned int sum = 0;
 
-	do {
+	for_each_pgdat(pgdat) {
 		zonelist_t *zonelist = pgdat->node_zonelists + (GFP_USER & GFP_ZONEMASK);
 		zone_t **zonep = zonelist->zones;
 		zone_t *zone;
@@ -488,9 +491,7 @@
 			if (size > high)
 				sum += size - high;
 		}
-
-		pgdat = pgdat->node_next;
-	} while (pgdat);
+	}
 
 	return sum;
 }
@@ -498,17 +499,35 @@
 #if CONFIG_HIGHMEM
 unsigned int nr_free_highpages (void)
 {
-	pg_data_t *pgdat = pgdat_list;
+	pg_data_t *pgdat;
 	unsigned int pages = 0;
 
-	while (pgdat) {
+	for_each_pgdat(pgdat)
 		pages += pgdat->node_zones[ZONE_HIGHMEM].free_pages;
-		pgdat = pgdat->node_next;
-	}
+
 	return pages;
 }
 #endif
 
+int try_to_free_pages_nozone(unsigned int gfp_mask)
+{
+	pg_data_t *pgdat;
+	zonelist_t *zonelist;
+	unsigned long pf_free_pages;
+	int error = 0;
+
+	pf_free_pages = current->flags & PF_FREE_PAGES;
+	current->flags &= ~PF_FREE_PAGES;
+
+	for_each_pgdat(pgdat) {
+		zonelist = pgdat->node_zonelists + (gfp_mask & GFP_ZONEMASK);
+		error |= try_to_free_pages(zonelist->zones[0], gfp_mask, 0);
+	}
+
+	current->flags |= pf_free_pages;
+	return error;
+}
+
 #define K(x) ((x) << (PAGE_SHIFT-10))
 
 /*
diff -urN linux-2.4.20-pre1/mm/page_io.c linux-2.4.20-pre2/mm/page_io.c
--- linux-2.4.20-pre1/mm/page_io.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/mm/page_io.c	Mon Aug 12 16:34:17 2002
@@ -72,11 +72,6 @@
 
  	/* block_size == PAGE_SIZE/zones_used */
  	brw_page(rw, page, dev, zones, block_size);
-
- 	/* Note! For consistency we do all of the logic,
- 	 * decrementing the page count, and unlocking the page in the
- 	 * swap lock map - in the IO completion handler.
- 	 */
 	return 1;
 }
 
diff -urN linux-2.4.20-pre1/mm/slab.c linux-2.4.20-pre2/mm/slab.c
--- linux-2.4.20-pre1/mm/slab.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/mm/slab.c	Mon Aug 12 16:34:17 2002
@@ -123,7 +123,7 @@
  * Bufctl's are used for linking objs within a slab
  * linked offsets.
  *
- * This implementaion relies on "struct page" for locating the cache &
+ * This implementation relies on "struct page" for locating the cache &
  * slab an object belongs to.
  * This allows the bufctl structure to be small (one int), but limits
  * the number of objects a slab (not a cache) can contain when off-slab
@@ -970,8 +970,6 @@
 	if (!cachep || in_interrupt() || !is_chained_kmem_cache(cachep))
 		BUG();
 
-	drain_cpu_caches(cachep);
-  
 	spin_lock_irq(&cachep->spinlock);
 	ret = __kmem_cache_shrink_locked(cachep);
 	spin_unlock_irq(&cachep->spinlock);
@@ -1608,6 +1606,15 @@
 	local_irq_restore(flags);
 }
 
+unsigned int kmem_cache_size(kmem_cache_t *cachep)
+{
+#if DEBUG
+	if (cachep->flags & SLAB_RED_ZONE)
+		return (cachep->objsize - 2*BYTES_PER_WORD);
+#endif
+	return cachep->objsize;
+}
+
 kmem_cache_t * kmem_find_general_cachep (size_t size, int gfpflags)
 {
 	cache_sizes_t *csizep = cache_sizes;
diff -urN linux-2.4.20-pre1/mm/swap_state.c linux-2.4.20-pre2/mm/swap_state.c
--- linux-2.4.20-pre1/mm/swap_state.c	Wed Oct 31 15:31:03 2001
+++ linux-2.4.20-pre2/mm/swap_state.c	Mon Aug 12 16:34:17 2002
@@ -117,7 +117,8 @@
 	if (!PageLocked(page))
 		BUG();
 
-	block_flushpage(page, 0);
+	if (unlikely(!block_flushpage(page, 0)))
+		BUG();	/* an anonymous page cannot have page->buffers set */
 
 	entry.val = page->index;
 
diff -urN linux-2.4.20-pre1/mm/vmscan.c linux-2.4.20-pre2/mm/vmscan.c
--- linux-2.4.20-pre1/mm/vmscan.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/mm/vmscan.c	Mon Aug 12 16:34:17 2002
@@ -649,10 +649,9 @@
 
 	do {
 		need_more_balance = 0;
-		pgdat = pgdat_list;
-		do
+
+		for_each_pgdat(pgdat)
 			need_more_balance |= kswapd_balance_pgdat(pgdat);
-		while ((pgdat = pgdat->node_next));
 	} while (need_more_balance);
 }
 
@@ -675,12 +674,10 @@
 {
 	pg_data_t * pgdat;
 
-	pgdat = pgdat_list;
-	do {
-		if (kswapd_can_sleep_pgdat(pgdat))
-			continue;
-		return 0;
-	} while ((pgdat = pgdat->node_next));
+	for_each_pgdat(pgdat) {
+		if (!kswapd_can_sleep_pgdat(pgdat))
+			return 0;
+	}
 
 	return 1;
 }
diff -urN linux-2.4.20-pre1/net/8021q/vlan_dev.c linux-2.4.20-pre2/net/8021q/vlan_dev.c
--- linux-2.4.20-pre1/net/8021q/vlan_dev.c	Mon Aug 12 16:34:12 2002
+++ linux-2.4.20-pre2/net/8021q/vlan_dev.c	Mon Aug 12 16:34:17 2002
@@ -458,14 +458,14 @@
 			kfree_skb(sk_tmp);
 			if (skb == NULL) {
 				stats->tx_dropped++;
-				return -ENOMEM;
+				return 0;
 			}
 			VLAN_DEV_INFO(dev)->cnt_inc_headroom_on_tx++;
 		} else {
 			if (!(skb = skb_unshare(skb, GFP_ATOMIC))) {
 				printk(KERN_ERR "vlan: failed to unshare skbuff\n");
 				stats->tx_dropped++;
-				return -ENOMEM;
+				return 0;
 			}
 		}
 		veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
diff -urN linux-2.4.20-pre1/net/core/dev.c linux-2.4.20-pre2/net/core/dev.c
--- linux-2.4.20-pre1/net/core/dev.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/core/dev.c	Mon Aug 12 16:34:17 2002
@@ -798,6 +798,19 @@
 
 	clear_bit(__LINK_STATE_START, &dev->state);
 
+	/* Synchronize to scheduled poll. We cannot touch poll list,
+	 * it can be even on different cpu. So just clear netif_running(),
+	 * and wait when poll really will happen. Actually, the best place
+	 * for this is inside dev->stop() after device stopped its irq
+	 * engine, but this requires more changes in devices. */
+
+	smp_mb__after_clear_bit(); /* Commit netif_running(). */
+	while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
+		/* No hurry. */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+
 	/*
 	 *	Call the device specific close. This cannot fail.
 	 *	Only if device is UP
@@ -1072,6 +1085,7 @@
   =======================================================================*/
 
 int netdev_max_backlog = 300;
+int weight_p = 64;            /* old backlog weight */
 /* These numbers are selected based on intuition and some
  * experimentatiom, if you have more scientific way of doing this
  * please go ahead and fix things.
@@ -1237,13 +1251,11 @@
 enqueue:
 			dev_hold(skb->dev);
 			__skb_queue_tail(&queue->input_pkt_queue,skb);
-			/* Runs from irqs or BH's, no need to wake BH */
-			cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
 			local_irq_restore(flags);
 #ifndef OFFLINE_SAMPLE
 			get_sample_stats(this_cpu);
 #endif
-			return softnet_data[this_cpu].cng_level;
+			return queue->cng_level;
 		}
 
 		if (queue->throttle) {
@@ -1253,6 +1265,8 @@
 				netdev_wakeup();
 #endif
 		}
+
+		netif_rx_schedule(&queue->blog_dev);
 		goto enqueue;
 	}
 
@@ -1308,19 +1322,12 @@
 	return ret;
 }
 
-/* Reparent skb to master device. This function is called
- * only from net_rx_action under BR_NETPROTO_LOCK. It is misuse
- * of BR_NETPROTO_LOCK, but it is OK for now.
- */
 static __inline__ void skb_bond(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	
-	if (dev->master) {
-		dev_hold(dev->master);
+
+	if (dev->master)
 		skb->dev = dev->master;
-		dev_put(dev);
-	}
 }
 
 static void net_tx_action(struct softirq_action *h)
@@ -1408,129 +1415,147 @@
 
 
 #ifdef CONFIG_NET_DIVERT
-static inline void handle_diverter(struct sk_buff *skb)
+static inline int handle_diverter(struct sk_buff *skb)
 {
 	/* if diversion is supported on device, then divert */
 	if (skb->dev->divert && skb->dev->divert->divert)
 		divert_frame(skb);
+	return 0;
 }
 #endif   /* CONFIG_NET_DIVERT */
 
-
-static void net_rx_action(struct softirq_action *h)
+int netif_receive_skb(struct sk_buff *skb)
 {
-	int this_cpu = smp_processor_id();
-	struct softnet_data *queue = &softnet_data[this_cpu];
-	unsigned long start_time = jiffies;
-	int bugdet = netdev_max_backlog;
-
-	br_read_lock(BR_NETPROTO_LOCK);
-
-	for (;;) {
-		struct sk_buff *skb;
-		struct net_device *rx_dev;
-
-		local_irq_disable();
-		skb = __skb_dequeue(&queue->input_pkt_queue);
-		local_irq_enable();
+	struct packet_type *ptype, *pt_prev;
+	int ret = NET_RX_DROP;
+	unsigned short type = skb->protocol;
 
-		if (skb == NULL)
-			break;
+	if (skb->stamp.tv_sec == 0)
+		do_gettimeofday(&skb->stamp);
 
-		skb_bond(skb);
+	skb_bond(skb);
 
-		rx_dev = skb->dev;
+	netdev_rx_stat[smp_processor_id()].total++;
 
 #ifdef CONFIG_NET_FASTROUTE
-		if (skb->pkt_type == PACKET_FASTROUTE) {
-			netdev_rx_stat[this_cpu].fastroute_deferred_out++;
-			dev_queue_xmit(skb);
-			dev_put(rx_dev);
-			continue;
-		}
+	if (skb->pkt_type == PACKET_FASTROUTE) {
+		netdev_rx_stat[smp_processor_id()].fastroute_deferred_out++;
+		return dev_queue_xmit(skb);
+	}
 #endif
-		skb->h.raw = skb->nh.raw = skb->data;
-		{
-			struct packet_type *ptype, *pt_prev;
-			unsigned short type = skb->protocol;
 
-			pt_prev = NULL;
-			for (ptype = ptype_all; ptype; ptype = ptype->next) {
-				if (!ptype->dev || ptype->dev == skb->dev) {
-					if (pt_prev) {
-						if (!pt_prev->data) {
-							deliver_to_old_ones(pt_prev, skb, 0);
-						} else {
-							atomic_inc(&skb->users);
-							pt_prev->func(skb,
-								      skb->dev,
-								      pt_prev);
-						}
-					}
-					pt_prev = ptype;
+	skb->h.raw = skb->nh.raw = skb->data;
+
+	pt_prev = NULL;
+	for (ptype = ptype_all; ptype; ptype = ptype->next) {
+		if (!ptype->dev || ptype->dev == skb->dev) {
+			if (pt_prev) {
+				if (!pt_prev->data) {
+					ret = deliver_to_old_ones(pt_prev, skb, 0);
+				} else {
+					atomic_inc(&skb->users);
+					ret = pt_prev->func(skb, skb->dev, pt_prev);
 				}
 			}
+			pt_prev = ptype;
+		}
+	}
 
 #ifdef CONFIG_NET_DIVERT
-			if (skb->dev->divert && skb->dev->divert->divert)
-				handle_diverter(skb);
+	if (skb->dev->divert && skb->dev->divert->divert)
+		ret = handle_diverter(skb);
 #endif /* CONFIG_NET_DIVERT */
-
 			
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-			if (skb->dev->br_port != NULL &&
-			    br_handle_frame_hook != NULL) {
-				handle_bridge(skb, pt_prev);
-				dev_put(rx_dev);
-				continue;
-			}
+	if (skb->dev->br_port != NULL &&
+	    br_handle_frame_hook != NULL) {
+		return handle_bridge(skb, pt_prev);
+	}
 #endif
 
-			for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
-				if (ptype->type == type &&
-				    (!ptype->dev || ptype->dev == skb->dev)) {
-					if (pt_prev) {
-						if (!pt_prev->data)
-							deliver_to_old_ones(pt_prev, skb, 0);
-						else {
-							atomic_inc(&skb->users);
-							pt_prev->func(skb,
-								      skb->dev,
-								      pt_prev);
-						}
-					}
-					pt_prev = ptype;
+	for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
+		if (ptype->type == type &&
+		    (!ptype->dev || ptype->dev == skb->dev)) {
+			if (pt_prev) {
+				if (!pt_prev->data) {
+					ret = deliver_to_old_ones(pt_prev, skb, 0);
+				} else {
+					atomic_inc(&skb->users);
+					ret = pt_prev->func(skb, skb->dev, pt_prev);
 				}
 			}
+			pt_prev = ptype;
+		}
+	}
 
-			if (pt_prev) {
-				if (!pt_prev->data)
-					deliver_to_old_ones(pt_prev, skb, 1);
-				else
-					pt_prev->func(skb, skb->dev, pt_prev);
-			} else
-				kfree_skb(skb);
+	if (pt_prev) {
+		if (!pt_prev->data) {
+			ret = deliver_to_old_ones(pt_prev, skb, 1);
+		} else {
+			ret = pt_prev->func(skb, skb->dev, pt_prev);
 		}
+	} else {
+		kfree_skb(skb);
+		/* Jamal, now you will not able to escape explaining
+		 * me how you were going to use this. :-)
+		 */
+		ret = NET_RX_DROP;
+	}
 
-		dev_put(rx_dev);
+	return ret;
+}
 
-		if (bugdet-- < 0 || jiffies - start_time > 1)
-			goto softnet_break;
+static int process_backlog(struct net_device *blog_dev, int *budget)
+{
+	int work = 0;
+	int quota = min(blog_dev->quota, *budget);
+	int this_cpu = smp_processor_id();
+	struct softnet_data *queue = &softnet_data[this_cpu];
+	unsigned long start_time = jiffies;
+
+	for (;;) {
+		struct sk_buff *skb;
+		struct net_device *dev;
+
+		local_irq_disable();
+		skb = __skb_dequeue(&queue->input_pkt_queue);
+		if (skb == NULL)
+			goto job_done;
+		local_irq_enable();
+
+		dev = skb->dev;
+
+		netif_receive_skb(skb);
+
+		dev_put(dev);
+
+		work++;
+
+		if (work >= quota || jiffies - start_time > 1)
+			break;
 
 #ifdef CONFIG_NET_HW_FLOWCONTROL
-	if (queue->throttle && queue->input_pkt_queue.qlen < no_cong_thresh ) {
-		if (atomic_dec_and_test(&netdev_dropping)) {
-			queue->throttle = 0;
-			netdev_wakeup();
-			goto softnet_break;
+		if (queue->throttle && queue->input_pkt_queue.qlen < no_cong_thresh ) {
+			if (atomic_dec_and_test(&netdev_dropping)) {
+				queue->throttle = 0;
+				netdev_wakeup();
+				break;
+			}
 		}
-	}
 #endif
-
 	}
-	br_read_unlock(BR_NETPROTO_LOCK);
 
-	local_irq_disable();
+	blog_dev->quota -= work;
+	*budget -= work;
+	return -1;
+
+job_done:
+	blog_dev->quota -= work;
+	*budget -= work;
+
+	list_del(&blog_dev->poll_list);
+	clear_bit(__LINK_STATE_RX_SCHED, &blog_dev->state);
+
 	if (queue->throttle) {
 		queue->throttle = 0;
 #ifdef CONFIG_NET_HW_FLOWCONTROL
@@ -1539,21 +1564,53 @@
 #endif
 	}
 	local_irq_enable();
+	return 0;
+}
 
-	NET_PROFILE_LEAVE(softnet_process);
-	return;
+static void net_rx_action(struct softirq_action *h)
+{
+	int this_cpu = smp_processor_id();
+	struct softnet_data *queue = &softnet_data[this_cpu];
+	unsigned long start_time = jiffies;
+	int budget = netdev_max_backlog;
 
-softnet_break:
+	br_read_lock(BR_NETPROTO_LOCK);
+	local_irq_disable();
+
+	while (!list_empty(&queue->poll_list)) {
+		struct net_device *dev;
+
+		if (budget <= 0 || jiffies - start_time > 1)
+			goto softnet_break;
+
+		local_irq_enable();
+
+		dev = list_entry(queue->poll_list.next, struct net_device, poll_list);
+
+		if (dev->quota <= 0 || dev->poll(dev, &budget)) {
+			local_irq_disable();
+			list_del(&dev->poll_list);
+			list_add_tail(&dev->poll_list, &queue->poll_list);
+			if (dev->quota < 0)
+				dev->quota += dev->weight;
+			else
+				dev->quota = dev->weight;
+		} else {
+			dev_put(dev);
+			local_irq_disable();
+		}
+	}
+
+	local_irq_enable();
 	br_read_unlock(BR_NETPROTO_LOCK);
+	return;
 
-	local_irq_disable();
+softnet_break:
 	netdev_rx_stat[this_cpu].time_squeeze++;
-	/* This already runs in BH context, no need to wake up BH's */
-	cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
-	local_irq_enable();
+	__cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
 
-	NET_PROFILE_LEAVE(softnet_process);
-	return;
+	local_irq_enable();
+	br_read_unlock(BR_NETPROTO_LOCK);
 }
 
 static gifconf_func_t * gifconf_list [NPROTO];
@@ -2607,6 +2664,7 @@
 
 extern void net_device_init(void);
 extern void ip_auto_config(void);
+struct proc_dir_entry *proc_net_drivers;
 #ifdef CONFIG_NET_DIVERT
 extern void dv_init(void);
 #endif /* CONFIG_NET_DIVERT */
@@ -2624,6 +2682,7 @@
 	if (!dev_boot_phase)
 		return 0;
 
+
 #ifdef CONFIG_NET_DIVERT
 	dv_init();
 #endif /* CONFIG_NET_DIVERT */
@@ -2641,8 +2700,13 @@
 		queue->cng_level = 0;
 		queue->avg_blog = 10; /* arbitrary non-zero */
 		queue->completion_queue = NULL;
+		INIT_LIST_HEAD(&queue->poll_list);
+		set_bit(__LINK_STATE_START, &queue->blog_dev.state);
+		queue->blog_dev.weight = weight_p;
+		queue->blog_dev.poll = process_backlog;
+		atomic_set(&queue->blog_dev.refcnt, 1);
 	}
-	
+
 #ifdef CONFIG_NET_PROFILE
 	net_profile_init();
 	NET_PROFILE_REGISTER(dev_queue_xmit);
@@ -2725,6 +2789,7 @@
 #ifdef CONFIG_PROC_FS
 	proc_net_create("dev", 0, dev_get_info);
 	create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL);
+	proc_net_drivers = proc_mkdir("net/drivers", 0);
 #ifdef WIRELESS_EXT
 	/* Available in net/core/wireless.c */
 	proc_net_create("wireless", 0, dev_get_wireless_info);
@@ -2742,7 +2807,6 @@
 #ifdef CONFIG_NET_SCHED
 	pktsched_init();
 #endif
-
 	/*
 	 *	Initialise network devices
 	 */
diff -urN linux-2.4.20-pre1/net/core/sysctl_net_core.c linux-2.4.20-pre2/net/core/sysctl_net_core.c
--- linux-2.4.20-pre1/net/core/sysctl_net_core.c	Tue Oct 10 10:33:52 2000
+++ linux-2.4.20-pre2/net/core/sysctl_net_core.c	Mon Aug 12 16:34:17 2002
@@ -12,6 +12,7 @@
 #ifdef CONFIG_SYSCTL
 
 extern int netdev_max_backlog;
+extern int weight_p;
 extern int no_cong_thresh;
 extern int no_cong;
 extern int lo_cong;
@@ -47,6 +48,9 @@
 	{NET_CORE_RMEM_DEFAULT, "rmem_default",
 	 &sysctl_rmem_default, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
+	{NET_CORE_DEV_WEIGHT, "dev_weight",
+	 &weight_p, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
 	{NET_CORE_MAX_BACKLOG, "netdev_max_backlog",
 	 &netdev_max_backlog, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
diff -urN linux-2.4.20-pre1/net/core/wireless.c linux-2.4.20-pre2/net/core/wireless.c
--- linux-2.4.20-pre1/net/core/wireless.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/core/wireless.c	Mon Aug 12 16:34:17 2002
@@ -2,7 +2,7 @@
  * This file implement the Wireless Extensions APIs.
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
  *
  * (As all part of the Linux kernel, this file is GPL)
  */
@@ -25,6 +25,16 @@
  *	o Added iw_handler handling ;-)
  *	o Added standard ioctl description
  *	o Initial dumb commit strategy based on orinoco.c
+ *
+ * v3 - 19.12.01 - Jean II
+ *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
+ *	o Add event dispatcher function
+ *	o Add event description
+ *	o Propagate events as rtnetlink IFLA_WIRELESS option
+ *	o Generate event on selected SET requests
+ *
+ * v4 - 18.04.01 - Jean II
+ *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
  */
 
 /***************************** INCLUDES *****************************/
@@ -33,6 +43,7 @@
 #include <linux/config.h>		/* Not needed ??? */
 #include <linux/types.h>		/* off_t */
 #include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
+#include <linux/rtnetlink.h>		/* rtnetlink stuff */
 
 #include <linux/wireless.h>		/* Pretty obvious */
 #include <net/iw_handler.h>		/* New driver API */
@@ -44,14 +55,23 @@
 
 /* Debuging stuff */
 #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
+#undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
+
+/* Options */
+#define WE_EVENT_NETLINK	/* Propagate events using rtnetlink */
+#define WE_SET_EVENT		/* Generate an event on some set commands */
 
 /************************* GLOBAL VARIABLES *************************/
 /*
  * You should not use global variables, because or re-entrancy.
  * On our case, it's only const, so it's OK...
  */
+/*
+ * Meta-data about all the standard Wireless Extension request we
+ * know about.
+ */
 static const struct iw_ioctl_description	standard_ioctl[] = {
-	/* SIOCSIWCOMMIT (internal) */
+	/* SIOCSIWCOMMIT */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* SIOCGIWNAME */
 	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
@@ -99,18 +119,18 @@
 	{ 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},
+	/* SIOCSIWSCAN */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWSCAN */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
 	/* SIOCSIWESSID */
-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
 	/* SIOCGIWESSID */
-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP},
 	/* SIOCSIWNICKN */
-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
 	/* SIOCGIWNICKN */
-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
 	/* -- hole -- */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* -- hole -- */
@@ -136,7 +156,7 @@
 	/* 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},
+	{ IW_HEADER_TYPE_POINT, 0, 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 */
@@ -144,9 +164,38 @@
 	/* SIOCGIWPOWER */
 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
 };
+static const int standard_ioctl_num = (sizeof(standard_ioctl) /
+				       sizeof(struct iw_ioctl_description));
+
+/*
+ * Meta-data about all the additional standard Wireless Extension events
+ * we know about.
+ */
+static const struct iw_ioctl_description	standard_event[] = {
+	/* IWEVTXDROP */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* IWEVQUAL */
+	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
+};
+static const int standard_event_num = (sizeof(standard_event) /
+				       sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+
+/* Size (in bytes) of various events */
+static const int event_type_size[] = {
+	IW_EV_LCP_LEN,
+	0,
+	IW_EV_CHAR_LEN,
+	0,
+	IW_EV_UINT_LEN,
+	IW_EV_FREQ_LEN,
+	IW_EV_POINT_LEN,		/* Without variable payload */
+	IW_EV_PARAM_LEN,
+	IW_EV_ADDR_LEN,
+	IW_EV_QUAL_LEN,
+};
 
 /************************ COMMON SUBROUTINES ************************/
 /*
@@ -162,7 +211,8 @@
 static inline iw_handler get_handler(struct net_device *dev,
 				     unsigned int cmd)
 {
-	unsigned int	index;		/* MUST be unsigned */
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned int	index;		/* *MUST* be unsigned */
 
 	/* Check if we have some wireless handlers defined */
 	if(dev->wireless_handlers == NULL)
@@ -269,9 +319,9 @@
 			       stats->status,
 			       stats->qual.qual,
 			       stats->qual.updated & 1 ? '.' : ' ',
-			       stats->qual.level,
+			       ((__u8) stats->qual.level),
 			       stats->qual.updated & 2 ? '.' : ' ',
-			       stats->qual.noise,
+			       ((__u8) stats->qual.noise),
 			       stats->qual.updated & 4 ? '.' : ' ',
 			       stats->discard.nwid,
 			       stats->discard.code,
@@ -423,12 +473,14 @@
 	int					ret = -EINVAL;
 
 	/* Get the description of the IOCTL */
+	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+		return -EOPNOTSUPP;
 	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
 
 #ifdef WE_IOCTL_DEBUG
-	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
+	printk(KERN_DEBUG "%s (WE) : 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);
+	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
 #endif	/* WE_IOCTL_DEBUG */
 
 	/* Prepare the call */
@@ -437,8 +489,16 @@
 
 	/* 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);
+
+#ifdef WE_SET_EVENT
+		/* Generate an event to notify listeners of the change */
+		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT)))
+			wireless_send_event(dev, cmd, &(iwr->u), NULL);
+#endif	/* WE_SET_EVENT */
 	} else {
 		char *	extra;
 		int	err;
@@ -466,8 +526,8 @@
 		}
 
 #ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "Malloc %d bytes\n",
-		       descr->max_tokens * descr->token_size);
+		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
+		       dev->name, descr->max_tokens * descr->token_size);
 #endif	/* WE_IOCTL_DEBUG */
 
 		/* Always allocate for max space. Easier, and won't last
@@ -488,7 +548,8 @@
 				return -EFAULT;
 			}
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Got %d bytes\n",
+			printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
+			       dev->name,
 			       iwr->u.data.length * descr->token_size);
 #endif	/* WE_IOCTL_DEBUG */
 		}
@@ -504,11 +565,26 @@
 			if (err)
 				ret =  -EFAULT;				   
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Wrote %d bytes\n",
+			printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
+			       dev->name,
 			       iwr->u.data.length * descr->token_size);
 #endif	/* WE_IOCTL_DEBUG */
 		}
 
+#ifdef WE_SET_EVENT
+		/* Generate an event to notify listeners of the change */
+		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT))) {
+			if(descr->flags & IW_DESCR_FLAG_RESTRICT)
+				/* If the event is restricted, don't
+				 * export the payload */
+				wireless_send_event(dev, cmd, &(iwr->u), NULL);
+			else
+				wireless_send_event(dev, cmd, &(iwr->u),
+						    extra);
+		}
+#endif	/* WE_SET_EVENT */
+
 		/* Cleanup - I told you it wasn't that long ;-) */
 		kfree(extra);
 	}
@@ -558,11 +634,12 @@
 		}
 
 #ifdef WE_IOCTL_DEBUG
-	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
+	printk(KERN_DEBUG "%s (WE) : 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);
+		printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
+		       dev->name, descr->name,
+		       descr->set_args, descr->get_args);
 	}
 #endif	/* WE_IOCTL_DEBUG */
 
@@ -617,7 +694,8 @@
 		}
 
 #ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
+		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
+		       dev->name, extra_size);
 #endif	/* WE_IOCTL_DEBUG */
 
 		/* Always allocate for max space. Easier, and won't last
@@ -636,7 +714,8 @@
 				return -EFAULT;
 			}
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
+			printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
+			       dev->name, iwr->u.data.length);
 #endif	/* WE_IOCTL_DEBUG */
 		}
 
@@ -650,8 +729,8 @@
 			if (err)
 				ret =  -EFAULT;				   
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Wrote %d elem\n",
-			       iwr->u.data.length);
+			printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
+			       dev->name, iwr->u.data.length);
 #endif	/* WE_IOCTL_DEBUG */
 		}
 
@@ -731,3 +810,177 @@
 	/* Not reached */
 	return -EINVAL;
 }
+
+/************************* EVENT PROCESSING *************************/
+/*
+ * Process events generated by the wireless layer or the driver.
+ * Most often, the event will be propagated through rtnetlink
+ */
+
+#ifdef WE_EVENT_NETLINK
+/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
+ * It is declared in <linux/rtnetlink.h> */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Fill a rtnetlink message with our event data.
+ * Note that we propage only the specified event and don't dump the
+ * current wireless config. Dumping the wireless config is far too
+ * expensive (for each parameter, the driver need to query the hardware).
+ */
+static inline int rtnetlink_fill_iwinfo(struct sk_buff *	skb,
+					struct net_device *	dev,
+					int			type,
+					char *			event,
+					int			event_len)
+{
+	struct ifinfomsg *r;
+	struct nlmsghdr  *nlh;
+	unsigned char	 *b = skb->tail;
+
+	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
+	r = NLMSG_DATA(nlh);
+	r->ifi_family = AF_UNSPEC;
+	r->ifi_type = dev->type;
+	r->ifi_index = dev->ifindex;
+	r->ifi_flags = dev->flags;
+	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
+
+	/* Add the wireless events in the netlink packet */
+	RTA_PUT(skb, IFLA_WIRELESS,
+		event_len, event);
+
+	nlh->nlmsg_len = skb->tail - b;
+	return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Create and broadcast and send it on the standard rtnetlink socket
+ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
+ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
+ * within a RTM_NEWLINK event.
+ */
+static inline void rtmsg_iwinfo(struct net_device *	dev,
+				char *			event,
+				int			event_len)
+{
+	struct sk_buff *skb;
+	int size = NLMSG_GOODSIZE;
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
+				  event, event_len) < 0) {
+		kfree_skb(skb);
+		return;
+	}
+	NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
+	netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
+}
+#endif	/* WE_EVENT_NETLINK */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main event dispatcher. Called from other parts and drivers.
+ * Send the event on the apropriate channels.
+ * May be called from interrupt context.
+ */
+void wireless_send_event(struct net_device *	dev,
+			 unsigned int		cmd,
+			 union iwreq_data *	wrqu,
+			 char *			extra)
+{
+	const struct iw_ioctl_description *	descr = NULL;
+	int extra_len = 0;
+	struct iw_event  *event;		/* Mallocated whole event */
+	int event_len;				/* Its size */
+	int hdr_len;				/* Size of the event header */
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned	cmd_index;		/* *MUST* be unsigned */
+
+	/* Get the description of the IOCTL */
+	if(cmd <= SIOCIWLAST) {
+		cmd_index = cmd - SIOCIWFIRST;
+		if(cmd_index < standard_ioctl_num)
+			descr = &(standard_ioctl[cmd_index]);
+	} else {
+		cmd_index = cmd - IWEVFIRST;
+		if(cmd_index < standard_event_num)
+			descr = &(standard_event[cmd_index]);
+	}
+	/* Don't accept unknown events */
+	if(descr == NULL) {
+		/* Note : we don't return an error to the driver, because
+		 * the driver would not know what to do about it. It can't
+		 * return an error to the user, because the event is not
+		 * initiated by a user request.
+		 * The best the driver could do is to log an error message.
+		 * We will do it ourselves instead...
+		 */
+	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
+		       dev->name, cmd);
+		return;
+	}
+#ifdef WE_EVENT_DEBUG
+	printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
+	       dev->name, cmd);
+	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+#endif	/* WE_EVENT_DEBUG */
+
+	/* Check extra parameters and set extra_len */
+	if(descr->header_type == IW_HEADER_TYPE_POINT) {
+		/* Check if number of token fits within bounds */
+		if(wrqu->data.length > descr->max_tokens) {
+		  	printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		if(wrqu->data.length < descr->min_tokens) {
+		  	printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		/* Calculate extra_len - extra is NULL for restricted events */
+		if(extra != NULL)
+			extra_len = wrqu->data.length * descr->token_size;
+#ifdef WE_EVENT_DEBUG
+		printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
+#endif	/* WE_EVENT_DEBUG */
+	}
+
+	/* Total length of the event */
+	hdr_len = event_type_size[descr->header_type];
+	event_len = hdr_len + extra_len;
+
+#ifdef WE_EVENT_DEBUG
+	printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
+#endif	/* WE_EVENT_DEBUG */
+
+	/* Create temporary buffer to hold the event */
+	event = kmalloc(event_len, GFP_ATOMIC);
+	if(event == NULL)
+		return;
+
+	/* Fill event */
+	event->len = event_len;
+	event->cmd = cmd;
+	memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
+	if(extra != NULL)
+		memcpy(((char *) event) + hdr_len, extra, extra_len);
+
+#ifdef WE_EVENT_NETLINK
+	/* rtnetlink event channel */
+	rtmsg_iwinfo(dev, (char *) event, event_len);
+#endif	/* WE_EVENT_NETLINK */
+
+	/* Cleanup */
+	kfree(event);
+
+	return;		/* Always success, I guess ;-) */
+}
diff -urN linux-2.4.20-pre1/net/decnet/af_decnet.c linux-2.4.20-pre2/net/decnet/af_decnet.c
--- linux-2.4.20-pre1/net/decnet/af_decnet.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.20-pre2/net/decnet/af_decnet.c	Mon Aug 12 16:34:17 2002
@@ -2234,7 +2234,7 @@
 MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
 #endif
 
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.15-pre5s (C) 1995-2001 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.20-pre1s (C) 1995-2002 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
diff -urN linux-2.4.20-pre1/net/decnet/dn_route.c linux-2.4.20-pre2/net/decnet/dn_route.c
--- linux-2.4.20-pre1/net/decnet/dn_route.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.20-pre2/net/decnet/dn_route.c	Mon Aug 12 16:34:17 2002
@@ -35,6 +35,8 @@
  *                                 are numbered!
  *              Steve Whitehouse : Added return-to-sender functions. Added
  *                                 backlog congestion level return codes.
+ *		Steve Whitehouse : Fixed bug where routes were set up with
+ *                                 no ref count on net devices.
  *                                 
  */
 
@@ -801,6 +803,8 @@
 
 	rt->u.dst.neighbour = neigh;
 	rt->u.dst.dev = neigh ? neigh->dev : NULL;
+	if (rt->u.dst.dev)
+		dev_hold(rt->u.dst.dev);
 	rt->u.dst.lastuse = jiffies;
 	rt->u.dst.output = dn_output;
 	rt->u.dst.input  = dn_rt_bug;
@@ -978,6 +982,8 @@
 
 	rt->u.dst.neighbour = neigh;
 	rt->u.dst.dev = neigh ? neigh->dev : NULL;
+	if (rt->u.dst.dev)
+		dev_hold(rt->u.dst.dev);
 	rt->u.dst.lastuse = jiffies;
 	rt->u.dst.output = dnrt_output;
 	rt->u.dst.input = dnrt_input;
diff -urN linux-2.4.20-pre1/net/ipv4/ip_output.c linux-2.4.20-pre2/net/ipv4/ip_output.c
--- linux-2.4.20-pre1/net/ipv4/ip_output.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/ip_output.c	Mon Aug 12 16:34:17 2002
@@ -520,8 +520,18 @@
 		/*
 		 *	Get the memory we require with some space left for alignment.
 		 */
-
-		skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, flags&MSG_DONTWAIT, &err);
+		if (!(flags & MSG_DONTWAIT) || nfrags == 0) {
+			skb = sock_alloc_send_skb(sk, fraglen + hh_len + 15,
+						  (flags & MSG_DONTWAIT), &err);
+		} else {
+			/* On a non-blocking write, we check for send buffer
+			 * usage on the first fragment only.
+			 */
+			skb = sock_wmalloc(sk, fraglen + hh_len + 15, 1,
+					   sk->allocation);
+			if (!skb)
+				err = -ENOBUFS;
+		}
 		if (skb == NULL)
 			goto error;
 
diff -urN linux-2.4.20-pre1/net/ipv4/ipconfig.c linux-2.4.20-pre2/net/ipv4/ipconfig.c
--- linux-2.4.20-pre1/net/ipv4/ipconfig.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/ipconfig.c	Mon Aug 12 16:34:17 2002
@@ -468,7 +468,7 @@
 
 
 /*
- *  Send RARP request packet over a signle interface.
+ *  Send RARP request packet over a single interface.
  */
 static void __init ic_rarp_send_if(struct ic_device *d)
 {
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/Config.in linux-2.4.20-pre2/net/ipv4/netfilter/Config.in
--- linux-2.4.20-pre1/net/ipv4/netfilter/Config.in	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/Config.in	Mon Aug 12 16:34:17 2002
@@ -18,15 +18,24 @@
 # The simple matches.
   dep_tristate '  limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  MAC address match support' CONFIG_IP_NF_MATCH_MAC $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  Packet type match support' CONFIG_IP_NF_MATCH_PKTTYPE $CONFIG_IP_NF_IPTABLES
   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
+ 
+  dep_tristate '  DSCP match support' CONFIG_IP_NF_MATCH_DSCP $CONFIG_IP_NF_IPTABLES
+ 
   dep_tristate '  AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES
   dep_tristate '  LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES
   dep_tristate '  tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
   if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
+    dep_tristate '  Helper match support' CONFIG_IP_NF_MATCH_HELPER $CONFIG_IP_NF_IPTABLES
+  fi
+  if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
     dep_tristate '  Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
+    dep_tristate '  Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     dep_tristate '  Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
@@ -73,6 +82,10 @@
   dep_tristate '  Packet mangling' CONFIG_IP_NF_MANGLE $CONFIG_IP_NF_IPTABLES 
   if [ "$CONFIG_IP_NF_MANGLE" != "n" ]; then
     dep_tristate '    TOS target support' CONFIG_IP_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE
+    dep_tristate '    ECN target support' CONFIG_IP_NF_TARGET_ECN $CONFIG_IP_NF_MANGLE
+ 
+    dep_tristate '    DSCP target support' CONFIG_IP_NF_TARGET_DSCP $CONFIG_IP_NF_MANGLE
+ 
     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/Makefile linux-2.4.20-pre2/net/ipv4/netfilter/Makefile
--- linux-2.4.20-pre1/net/ipv4/netfilter/Makefile	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/Makefile	Mon Aug 12 16:34:17 2002
@@ -9,18 +9,18 @@
 
 O_TARGET := netfilter.o
 
-export-objs = ip_conntrack_standalone.o ip_conntrack_ftp.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
+export-objs = ip_conntrack_standalone.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
 
 # Multipart objects.
 list-multi		:= ip_conntrack.o iptable_nat.o ipfwadm.o ipchains.o
 
 # objects for the conntrack and NAT core (used by standalone and backw. compat)
 ip_nf_conntrack-objs	:= ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
-ip_nf_nat-objs		:= ip_nat_core.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
+ip_nf_nat-objs		:= ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
 
 # objects for the standalone - connection tracking / NAT
 ip_conntrack-objs	:= ip_conntrack_standalone.o $(ip_nf_conntrack-objs)
-iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o ip_nat_helper.o $(ip_nf_nat-objs)
+iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o $(ip_nf_nat-objs)
 
 # objects for backwards compatibility mode
 ip_nf_compat-objs	:= ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(ip_nf_conntrack-objs) $(ip_nf_nat-objs)
@@ -33,7 +33,14 @@
 
 # connection tracking helpers
 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
+ifdef CONFIG_IP_NF_NAT_FTP
+	export-objs += ip_conntrack_ftp.o
+endif
+
 obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+ifdef CONFIG_IP_NF_NAT_IRC
+	export-objs += ip_conntrack_irc.o
+endif
 
 # NAT helpers 
 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
@@ -48,18 +55,24 @@
 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
 
 # matches
+obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
+
+obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
 obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 
 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
 
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
+obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
 obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
 
@@ -67,6 +80,8 @@
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
 obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o
 obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
+obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
+obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_core.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_core.c	Mon Aug 12 16:34:17 2002
@@ -3,7 +3,15 @@
    extension. */
 
 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
-   Public Licence. */
+ * Public Licence. 
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ * 	- new API and handling of conntrack/nat helpers
+ * 	- now capable of multiple expectations for one master
+ * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
+ * 	- add usage/reference counts to ip_conntrack_expect
+ *	- export ip_conntrack[_expect]_{find_get,put} functions
+ * */
 
 #ifdef MODULE
 #define __NO_VERSION__
@@ -37,6 +45,8 @@
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
+#define IP_CONNTRACK_VERSION	"2.1"
+
 #if 0
 #define DEBUGP printk
 #else
@@ -44,9 +54,10 @@
 #endif
 
 DECLARE_RWLOCK(ip_conntrack_lock);
+DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
 
 void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
-LIST_HEAD(expect_list);
+LIST_HEAD(ip_conntrack_expect_list);
 LIST_HEAD(protocol_list);
 static LIST_HEAD(helpers);
 unsigned int ip_conntrack_htable_size = 0;
@@ -76,7 +87,7 @@
 	return p;
 }
 
-struct ip_conntrack_protocol *find_proto(u_int8_t protocol)
+struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
 {
 	struct ip_conntrack_protocol *p;
 
@@ -86,7 +97,8 @@
 	return p;
 }
 
-static inline void ip_conntrack_put(struct ip_conntrack *ct)
+inline void 
+ip_conntrack_put(struct ip_conntrack *ct)
 {
 	IP_NF_ASSERT(ct);
 	IP_NF_ASSERT(ct->infos[0].master);
@@ -150,9 +162,135 @@
 	return protocol->invert_tuple(inverse, orig);
 }
 
+
+/* ip_conntrack_expect helper functions */
+
+/* Compare tuple parts depending on mask. */
+static inline int expect_cmp(const struct ip_conntrack_expect *i,
+			     const struct ip_conntrack_tuple *tuple)
+{
+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
+	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
+}
+
+static void
+destroy_expect(struct ip_conntrack_expect *exp)
+{
+	DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(exp->use));
+	IP_NF_ASSERT(atomic_read(exp->use));
+	IP_NF_ASSERT(!timer_pending(&exp->timeout));
+
+	kfree(exp);
+}
+
+
+inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
+{
+	IP_NF_ASSERT(exp);
+
+	if (atomic_dec_and_test(&exp->use)) {
+		/* usage count dropped to zero */
+		destroy_expect(exp);
+	}
+}
+
+static inline struct ip_conntrack_expect *
+__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
+{
+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
+	return LIST_FIND(&ip_conntrack_expect_list, expect_cmp, 
+			 struct ip_conntrack_expect *, tuple);
+}
+
+/* Find a expectation corresponding to a tuple. */
+struct ip_conntrack_expect *
+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
+{
+	struct ip_conntrack_expect *exp;
+
+	READ_LOCK(&ip_conntrack_lock);
+	READ_LOCK(&ip_conntrack_expect_tuple_lock);
+	exp = __ip_ct_expect_find(tuple);
+	if (exp)
+		atomic_inc(&exp->use);
+	READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+	READ_UNLOCK(&ip_conntrack_lock);
+
+	return exp;
+}
+
+/* remove one specific expectation from all lists and drop refcount,
+ * does _NOT_ delete the timer. */
+static void __unexpect_related(struct ip_conntrack_expect *expect)
+{
+	DEBUGP("unexpect_related(%p)\n", expect);
+	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
+
+	/* we're not allowed to unexpect a confirmed expectation! */
+	IP_NF_ASSERT(!expect->sibling);
+
+	/* delete from global and local lists */
+	list_del(&expect->list);
+	list_del(&expect->expected_list);
+
+	/* decrement expect-count of master conntrack */
+	if (expect->expectant)
+		expect->expectant->expecting--;
+
+	ip_conntrack_expect_put(expect);
+}
+
+/* remove one specific expecatation from all lists, drop refcount
+ * and expire timer. 
+ * This function can _NOT_ be called for confirmed expects! */
+static void unexpect_related(struct ip_conntrack_expect *expect)
+{
+	IP_NF_ASSERT(expect->expectant);
+	IP_NF_ASSERT(expect->expectant->helper);
+	/* if we are supposed to have a timer, but we can't delete
+	 * it: race condition.  __unexpect_related will
+	 * be calledd by timeout function */
+	if (expect->expectant->helper->timeout
+	    && !del_timer(&expect->timeout))
+		return;
+
+	__unexpect_related(expect);
+}
+
+/* delete all unconfirmed expectations for this conntrack */
+static void remove_expectations(struct ip_conntrack *ct)
+{
+	struct list_head *exp_entry, *next;
+	struct ip_conntrack_expect *exp;
+
+	DEBUGP("remove_expectations(%p)\n", ct);
+
+	for (exp_entry = ct->sibling_list.next;
+	     exp_entry != &ct->sibling_list; exp_entry = next) {
+		next = exp_entry->next;
+		exp = list_entry(exp_entry, struct ip_conntrack_expect,
+				 expected_list);
+
+		/* we skip established expectations, as we want to delete
+		 * the un-established ones only */
+		if (exp->sibling) {
+			DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
+			continue;
+		}
+
+		IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
+		IP_NF_ASSERT(exp->expectant == ct);
+
+		/* delete expectation from global and private lists */
+		unexpect_related(exp);
+	}
+}
+
 static void
 clean_from_lists(struct ip_conntrack *ct)
 {
+	DEBUGP("clean_from_lists(%p)\n", ct);
 	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
 	/* Remove from both hash lists: must not NULL out next ptrs,
            otherwise we'll look unconfirmed.  Fortunately, LIST_DELETE
@@ -163,12 +301,9 @@
 	LIST_DELETE(&ip_conntrack_hash
 		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
 		    &ct->tuplehash[IP_CT_DIR_REPLY]);
-	/* If our expected is in the list, take it out. */
-	if (ct->expected.expectant) {
-		IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));
-		IP_NF_ASSERT(ct->expected.expectant == ct);
-		LIST_DELETE(&expect_list, &ct->expected);
-	}
+
+	/* Destroy all un-established, pending expectations */
+	remove_expectations(ct);
 }
 
 static void
@@ -177,21 +312,34 @@
 	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
 	struct ip_conntrack_protocol *proto;
 
+	DEBUGP("destroy_conntrack(%p)\n", ct);
 	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
 	IP_NF_ASSERT(!timer_pending(&ct->timeout));
 
-	if (ct->master.master)
-		nf_conntrack_put(&ct->master);
+	if (ct->master && master_ct(ct))
+		ip_conntrack_put(master_ct(ct));
 
 	/* 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);
+	proto = ip_ct_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);
+
+	WRITE_LOCK(&ip_conntrack_lock);
+	/* Delete our master expectation */
+	if (ct->master) {
+		/* can't call __unexpect_related here,
+		 * since it would screw up expect_list */
+		list_del(&ct->master->expected_list);
+		kfree(ct->master);
+	}
+	WRITE_UNLOCK(&ip_conntrack_lock);
+
+	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
 	kmem_cache_free(ip_conntrack_cachep, ct);
 	atomic_dec(&ip_conntrack_count);
 }
@@ -389,7 +537,7 @@
 		return NULL;
 	}
 
-	innerproto = find_proto(inner->protocol);
+	innerproto = ip_ct_find_proto(inner->protocol);
 	/* Are they talking about one of our connections? */
 	if (inner->ihl * 4 + 8 > datalen
 	    || !get_tuple(inner, datalen, &origtuple, innerproto)) {
@@ -469,11 +617,11 @@
 	return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
 }
 
-/* Compare parts depending on mask. */
-static inline int expect_cmp(const struct ip_conntrack_expect *i,
-			     const struct ip_conntrack_tuple *tuple)
+struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
 {
-	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
+	return LIST_FIND(&helpers, helper_cmp,
+			 struct ip_conntrack_helper *,
+			 tuple);
 }
 
 /* Allocate a new conntrack: we return -ENOMEM if classification
@@ -521,7 +669,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
-	memset(conntrack, 0, sizeof(struct ip_conntrack));
+	memset(conntrack, 0, sizeof(*conntrack));
 	atomic_set(&conntrack->ct_general.use, 1);
 	conntrack->ct_general.destroy = destroy_conntrack;
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
@@ -540,31 +688,44 @@
 	conntrack->timeout.data = (unsigned long)conntrack;
 	conntrack->timeout.function = death_by_timeout;
 
+	INIT_LIST_HEAD(&conntrack->sibling_list);
+
 	/* Mark clearly that it's not in the hash table. */
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list.next = NULL;
 
-	/* Write lock required for deletion of expected.  Without
-           this, a read-lock would do. */
 	WRITE_LOCK(&ip_conntrack_lock);
-	conntrack->helper = LIST_FIND(&helpers, helper_cmp,
-				      struct ip_conntrack_helper *,
-				      &repl_tuple);
 	/* Need finding and deleting of expected ONLY if we win race */
-	expected = LIST_FIND(&expect_list, expect_cmp,
+	READ_LOCK(&ip_conntrack_expect_tuple_lock);
+	expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
 			     struct ip_conntrack_expect *, tuple);
+	READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+
+	/* Look up the conntrack helper for master connections only */
+	if (!expected)
+		conntrack->helper = ip_ct_find_helper(&repl_tuple);
+
+	/* If the expectation is dying, then this is a looser. */
+	if (expected
+	    && expected->expectant->helper->timeout
+	    && ! del_timer(&expected->timeout))
+		expected = NULL;
+
 	/* If master is not in hash table yet (ie. packet hasn't left
 	   this machine yet), how can other end know about expected?
 	   Hence these are not the droids you are looking for (if
 	   master ct never got confirmed, we'd hold a reference to it
 	   and weird things would happen to future packets). */
 	if (expected && is_confirmed(expected->expectant)) {
+		DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
+			conntrack, expected);
 		/* Welcome, Mr. Bond.  We've been expecting you... */
+		IP_NF_ASSERT(master_ct(conntrack));
 		conntrack->status = IPS_EXPECTED;
-		conntrack->master.master = &expected->expectant->ct_general;
-		IP_NF_ASSERT(conntrack->master.master);
-		LIST_DELETE(&expect_list, expected);
-		expected->expectant = NULL;
-		nf_conntrack_get(&conntrack->master);
+		conntrack->master = expected;
+		expected->sibling = conntrack;
+		LIST_DELETE(&ip_conntrack_expect_list, expected);
+		expected->expectant->expecting--;
+		nf_conntrack_get(&master_ct(conntrack)->infos[0]);
 	}
 	atomic_inc(&ip_conntrack_count);
 	WRITE_UNLOCK(&ip_conntrack_lock);
@@ -669,7 +830,7 @@
 			return NF_STOLEN;
 	}
 
-	proto = find_proto((*pskb)->nh.iph->protocol);
+	proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
 
 	/* It may be an icmp error... */
 	if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP 
@@ -713,66 +874,227 @@
 int invert_tuplepr(struct ip_conntrack_tuple *inverse,
 		   const struct ip_conntrack_tuple *orig)
 {
-	return invert_tuple(inverse, orig, find_proto(orig->dst.protonum));
+	return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
 }
 
-static void unexpect_related(struct ip_conntrack *related_to)
-{
-	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
-	list_del(&related_to->expected.list);
-	related_to->expected.expectant = NULL;
+static inline int resent_expect(const struct ip_conntrack_expect *i,
+			        const struct ip_conntrack_tuple *tuple,
+			        const struct ip_conntrack_tuple *mask)
+{
+	DEBUGP("resent_expect\n");
+	DEBUGP("   tuple:   "); DUMP_TUPLE(&i->tuple);
+	DEBUGP("ct_tuple:   "); DUMP_TUPLE(&i->ct_tuple);
+	DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
+	return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
+	         || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
+		&& ip_ct_tuple_equal(&i->mask, mask));
 }
 
 /* Would two expected things clash? */
 static inline int expect_clash(const struct ip_conntrack_expect *i,
-			       const struct ip_conntrack_expect *new)
+			       const struct ip_conntrack_tuple *tuple,
+			       const struct ip_conntrack_tuple *mask)
 {
 	/* Part covered by intersection of masks must be unequal,
            otherwise they clash */
 	struct ip_conntrack_tuple intersect_mask
-		= { { i->mask.src.ip & new->mask.src.ip,
-		      { i->mask.src.u.all & new->mask.src.u.all } },
-		    { i->mask.dst.ip & new->mask.dst.ip,
-		      { i->mask.dst.u.all & new->mask.dst.u.all },
-		      i->mask.dst.protonum & new->mask.dst.protonum } };
+		= { { i->mask.src.ip & mask->src.ip,
+		      { i->mask.src.u.all & mask->src.u.all } },
+		    { i->mask.dst.ip & mask->dst.ip,
+		      { i->mask.dst.u.all & mask->dst.u.all },
+		      i->mask.dst.protonum & mask->dst.protonum } };
+
+	return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
+}
 
-	return ip_ct_tuple_mask_cmp(&i->tuple, &new->tuple, &intersect_mask);
+inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
+{
+	WRITE_LOCK(&ip_conntrack_lock);
+	unexpect_related(expect);
+	WRITE_UNLOCK(&ip_conntrack_lock);
+}
+	
+static void expectation_timed_out(unsigned long ul_expect)
+{
+	struct ip_conntrack_expect *expect = (void *) ul_expect;
+
+	DEBUGP("expectation %p timed out\n", expect);	
+	WRITE_LOCK(&ip_conntrack_lock);
+	__unexpect_related(expect);
+	WRITE_UNLOCK(&ip_conntrack_lock);
 }
 
 /* Add a related connection. */
 int ip_conntrack_expect_related(struct ip_conntrack *related_to,
-				const struct ip_conntrack_tuple *tuple,
-				const struct ip_conntrack_tuple *mask,
-				int (*expectfn)(struct ip_conntrack *))
+				struct ip_conntrack_expect *expect)
 {
+	struct ip_conntrack_expect *old, *new;
+	int ret = 0;
+
 	WRITE_LOCK(&ip_conntrack_lock);
-	if (related_to->expected.expectant)
-		unexpect_related(related_to);
+	/* Because of the write lock, no reader can walk the lists,
+	 * so there is no need to use the tuple lock too */
+
+	DEBUGP("ip_conntrack_expect_related %p\n", related_to);
+	DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
+	DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
+
+	old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
+		        struct ip_conntrack_expect *, &expect->tuple, 
+			&expect->mask);
+	if (old) {
+		/* Helper private data may contain offsets but no pointers
+		   pointing into the payload - otherwise we should have to copy 
+		   the data filled out by the helper over the old one */
+		DEBUGP("expect_related: resent packet\n");
+		if (related_to->helper->timeout) {
+			if (!del_timer(&old->timeout)) {
+				/* expectation is dying. Fall through */
+				old = NULL;
+			} else {
+				old->timeout.expires = jiffies + 
+					related_to->helper->timeout * HZ;
+				add_timer(&old->timeout);
+			}
+		}
 
-	related_to->expected.tuple = *tuple;
-	related_to->expected.mask = *mask;
-	related_to->expected.expectfn = expectfn;
+		if (old) {
+			WRITE_UNLOCK(&ip_conntrack_lock);
+			return -EEXIST;
+		}
+	} else if (related_to->helper->max_expected && 
+		   related_to->expecting >= related_to->helper->max_expected) {
+		struct list_head *cur_item;
+		/* old == NULL */
+	    	if (net_ratelimit())
+		    	printk(KERN_WARNING 
+		    	       "ip_conntrack: max number of expected "
+			       "connections %i of %s reached for "
+			       "%u.%u.%u.%u->%u.%u.%u.%u%s\n",
+		    	       related_to->helper->max_expected, 
+		    	       related_to->helper->name,
+		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip),
+		    	       related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ?
+		    	       ", reusing" : "");
+		if (!(related_to->helper->flags & 
+		      IP_CT_HELPER_F_REUSE_EXPECT)) {
+			WRITE_UNLOCK(&ip_conntrack_lock);
+			return -EPERM;
+		}
+
+		/* choose the the oldest expectation to evict */
+		list_for_each(cur_item, &related_to->sibling_list) { 
+			struct ip_conntrack_expect *cur;
+
+			cur = list_entry(cur_item, 
+					 struct ip_conntrack_expect,
+					 expected_list);
+			if (cur->sibling == NULL) {
+				old = cur;
+				break;
+			}
+		}
 
-	if (LIST_FIND(&expect_list, expect_clash,
-		      struct ip_conntrack_expect *, &related_to->expected)) {
+		/* (!old) cannot happen, since related_to->expecting is the
+		 * number of unconfirmed expects */
+		IP_NF_ASSERT(old);
+
+		/* newnat14 does not reuse the real allocated memory
+		 * structures but rather unexpects the old and
+		 * allocates a new.  unexpect_related will decrement
+		 * related_to->expecting. 
+		 */
+		unexpect_related(old);
+		ret = -EPERM;
+	} else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
+			     struct ip_conntrack_expect *, &expect->tuple, 
+			     &expect->mask)) {
 		WRITE_UNLOCK(&ip_conntrack_lock);
+		DEBUGP("expect_related: busy!\n");
 		return -EBUSY;
 	}
+	
+	new = (struct ip_conntrack_expect *) 
+	      kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
+	if (!new) {
+		WRITE_UNLOCK(&ip_conntrack_lock);
+		DEBUGP("expect_relaed: OOM allocating expect\n");
+		return -ENOMEM;
+	}
+	
+	/* Zero out the new structure, then fill out it with the data */
+	DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
+	memset(new, 0, sizeof(*expect));
+	INIT_LIST_HEAD(&new->list);
+	INIT_LIST_HEAD(&new->expected_list);
+	memcpy(new, expect, sizeof(*expect));
+	new->expectant = related_to;
+	new->sibling = NULL;
+	/* increase usage count. This sucks. The memset above overwrites
+	 * old usage count [if still present] and we increase to one.  Only
+	 * works because everything is done under ip_conntrack_lock() */
+	atomic_inc(&new->use);
+	
+	/* add to expected list for this connection */	
+	list_add(&new->expected_list, &related_to->sibling_list);
+	/* add to global list of expectations */
+	list_prepend(&ip_conntrack_expect_list, &new->list);
+	/* add and start timer if required */
+	if (related_to->helper->timeout) {
+		init_timer(&new->timeout);
+		new->timeout.data = (unsigned long)new;
+		new->timeout.function = expectation_timed_out;
+		new->timeout.expires = jiffies + 
+					related_to->helper->timeout * HZ;
+		add_timer(&new->timeout);
+	}
+	related_to->expecting++;
 
-	list_prepend(&expect_list, &related_to->expected);
-	related_to->expected.expectant = related_to;
 	WRITE_UNLOCK(&ip_conntrack_lock);
 
-	return 0;
+	return ret;
 }
 
-void ip_conntrack_unexpect_related(struct ip_conntrack *related_to)
+/* Change tuple in an existing expectation */
+int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
+			       struct ip_conntrack_tuple *newtuple)
 {
-	WRITE_LOCK(&ip_conntrack_lock);
-	unexpect_related(related_to);
-	WRITE_UNLOCK(&ip_conntrack_lock);
-}
+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+
+	DEBUGP("change_expect:\n");
+	DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
+	DEBUGP("exp mask:  "); DUMP_TUPLE(&expect->mask);
+	DEBUGP("newtuple:  "); DUMP_TUPLE(newtuple);
+	if (expect->ct_tuple.dst.protonum == 0) {
+		/* Never seen before */
+		DEBUGP("change expect: never seen before\n");
+		if (!ip_ct_tuple_equal(&expect->tuple, newtuple) 
+		    && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
+			         struct ip_conntrack_expect *, newtuple, &expect->mask)) {
+			/* Force NAT to find an unused tuple */
+			return -1;
+		} else {
+			WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
+			memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
+			memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
+			WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
+			return 0;
+		}
+	} else {
+		/* Resent packet */
+		DEBUGP("change expect: resent packet\n");
+		if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
+			return 0;
+		} else {
+			/* Force NAT to choose again the same port */
+			return -1;
+		}
+	}
 	
+	return -1;
+}
+
 /* Alter reply tuple (maybe alter helper).  If it's already taken,
    return 0 and don't do alteration. */
 int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
@@ -790,10 +1112,12 @@
 	DUMP_TUPLE(newreply);
 
 	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-	conntrack->helper = LIST_FIND(&helpers, helper_cmp,
-				      struct ip_conntrack_helper *,
-				      newreply);
+	if (!conntrack->master)
+		conntrack->helper = LIST_FIND(&helpers, helper_cmp,
+					      struct ip_conntrack_helper *,
+					      newreply);
 	WRITE_UNLOCK(&ip_conntrack_lock);
+
 	return 1;
 }
 
@@ -812,14 +1136,10 @@
 			 const struct ip_conntrack_helper *me)
 {
 	if (i->ctrack->helper == me) {
-		i->ctrack->helper = NULL;
 		/* Get rid of any expected. */
-		if (i->ctrack->expected.expectant) {
-			IP_NF_ASSERT(i->ctrack->expected.expectant
-				     == i->ctrack);
-			LIST_DELETE(&expect_list, &i->ctrack->expected);
-			i->ctrack->expected.expectant = NULL;
-		}
+		remove_expectations(i->ctrack);
+		/* And *then* set helper to NULL */
+		i->ctrack->helper = NULL;
 	}
 	return 0;
 }
@@ -1100,18 +1420,22 @@
 	}
 	ip_conntrack_max = 8 * ip_conntrack_htable_size;
 
-	printk("ip_conntrack (%u buckets, %d max)\n",
-	       ip_conntrack_htable_size, ip_conntrack_max);
+	printk("ip_conntrack version %s (%u buckets, %d max)"
+	       " - %d bytes per conntrack\n", IP_CONNTRACK_VERSION,
+	       ip_conntrack_htable_size, ip_conntrack_max,
+	       sizeof(struct ip_conntrack));
 
 	ret = nf_register_sockopt(&so_getorigdst);
-	if (ret != 0)
+	if (ret != 0) {
+		printk(KERN_ERR "Unable to register netfilter socket option\n");
 		return ret;
+	}
 
 	ip_conntrack_hash = vmalloc(sizeof(struct list_head)
 				    * ip_conntrack_htable_size);
 	if (!ip_conntrack_hash) {
-		nf_unregister_sockopt(&so_getorigdst);
-		return -ENOMEM;
+		printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
+		goto err_unreg_sockopt;
 	}
 
 	ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
@@ -1119,11 +1443,8 @@
 	                                        SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if (!ip_conntrack_cachep) {
 		printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
-		vfree(ip_conntrack_hash);
-		nf_unregister_sockopt(&so_getorigdst);
-		return -ENOMEM;
+		goto err_free_hash;
 	}
-	
 	/* Don't NEED lock here, but good form anyway. */
 	WRITE_LOCK(&ip_conntrack_lock);
 	/* Sew in builtin protocols. */
@@ -1142,14 +1463,20 @@
 	ip_conntrack_sysctl_header
 		= register_sysctl_table(ip_conntrack_root_table, 0);
 	if (ip_conntrack_sysctl_header == NULL) {
-		kmem_cache_destroy(ip_conntrack_cachep);
-		vfree(ip_conntrack_hash);
-		nf_unregister_sockopt(&so_getorigdst);
-		return -ENOMEM;
+		goto err_free_ct_cachep;
 	}
 #endif /*CONFIG_SYSCTL*/
 
 	/* For use by ipt_REJECT */
 	ip_ct_attach = ip_conntrack_attach;
 	return ret;
+
+err_free_ct_cachep:
+	kmem_cache_destroy(ip_conntrack_cachep);
+err_free_hash:
+	vfree(ip_conntrack_hash);
+err_unreg_sockopt:
+	nf_unregister_sockopt(&so_getorigdst);
+
+	return -ENOMEM;
 }
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_ftp.c	Tue Oct 30 15:08:12 2001
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_ftp.c	Mon Aug 12 16:34:17 2002
@@ -1,4 +1,5 @@
 /* FTP extension for IP connection tracking. */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
@@ -15,7 +16,7 @@
 
 #define MAX_PORTS 8
 static int ports[MAX_PORTS];
-static int ports_c;
+static int ports_c = 0;
 #ifdef MODULE_PARM
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
 #endif
@@ -242,8 +243,10 @@
 	u_int32_t array[6] = { 0 };
 	int dir = CTINFO2DIR(ctinfo);
 	unsigned int matchlen, matchoff;
-	struct ip_conntrack_tuple t, mask;
-	struct ip_ct_ftp *info = &ct->help.ct_ftp_info;
+	struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
+	struct ip_conntrack_expect expect, *exp = &expect;
+	struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info;
+
 	unsigned int i;
 	int found = 0;
 
@@ -271,8 +274,8 @@
 	}
 
 	LOCK_BH(&ip_ftp_lock);
-	old_seq_aft_nl_set = info->seq_aft_nl_set[dir];
-	old_seq_aft_nl = info->seq_aft_nl[dir];
+	old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir];
+	old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir];
 
 	DEBUGP("conntrack_ftp: datalen %u\n", datalen);
 	if ((datalen > 0) && (data[datalen-1] == '\n')) {
@@ -281,8 +284,9 @@
 		    || after(ntohl(tcph->seq) + datalen, old_seq_aft_nl)) {
 			DEBUGP("conntrack_ftp: updating nl to %u\n",
 			       ntohl(tcph->seq) + datalen);
-			info->seq_aft_nl[dir] = ntohl(tcph->seq) + datalen;
-			info->seq_aft_nl_set[dir] = 1;
+			ct_ftp_info->seq_aft_nl[dir] = 
+						ntohl(tcph->seq) + datalen;
+			ct_ftp_info->seq_aft_nl_set[dir] = 1;
 		}
 	}
 	UNLOCK_BH(&ip_ftp_lock);
@@ -330,16 +334,17 @@
 	DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
 	       (int)matchlen, data + matchoff,
 	       matchlen, ntohl(tcph->seq) + matchoff);
+	       
+	memset(&expect, 0, sizeof(expect));
 
 	/* Update the ftp info */
 	LOCK_BH(&ip_ftp_lock);
 	if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
 	    == ct->tuplehash[dir].tuple.src.ip) {
-		info->is_ftp = 21;
-		info->seq = ntohl(tcph->seq) + matchoff;
-		info->len = matchlen;
-		info->ftptype = search[i].ftptype;
-		info->port = array[4] << 8 | array[5];
+		exp->seq = ntohl(tcph->seq) + matchoff;
+		exp_ftp_info->len = matchlen;
+		exp_ftp_info->ftptype = search[i].ftptype;
+		exp_ftp_info->port = array[4] << 8 | array[5];
 	} else {
 		/* Enrico Scholz's passive FTP to partially RNAT'd ftp
 		   server: it really wants us to connect to a
@@ -356,18 +361,21 @@
 		if (!loose) goto out;
 	}
 
-	t = ((struct ip_conntrack_tuple)
+	exp->tuple = ((struct ip_conntrack_tuple)
 		{ { ct->tuplehash[!dir].tuple.src.ip,
 		    { 0 } },
 		  { htonl((array[0] << 24) | (array[1] << 16)
 			  | (array[2] << 8) | array[3]),
 		    { htons(array[4] << 8 | array[5]) },
 		    IPPROTO_TCP }});
-	mask = ((struct ip_conntrack_tuple)
+	exp->mask = ((struct ip_conntrack_tuple)
 		{ { 0xFFFFFFFF, { 0 } },
 		  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+
+	exp->expectfn = NULL;
+
 	/* Ignore failure; should only happen with NAT */
-	ip_conntrack_expect_related(ct, &t, &mask, NULL);
+	ip_conntrack_expect_related(ct, &expect);
  out:
 	UNLOCK_BH(&ip_ftp_lock);
 
@@ -375,12 +383,13 @@
 }
 
 static struct ip_conntrack_helper ftp[MAX_PORTS];
+static char ftp_names[MAX_PORTS][10];
 
 /* Not __exit: called from init() */
 static void fini(void)
 {
 	int i;
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; i++) {
 		DEBUGP("ip_ct_ftp: unregistering helper for port %d\n",
 				ports[i]);
 		ip_conntrack_helper_unregister(&ftp[i]);
@@ -390,9 +399,10 @@
 static int __init init(void)
 {
 	int i, ret;
+	char *tmpname;
 
 	if (ports[0] == 0)
-		ports[0] = 21;
+		ports[0] = FTP_PORT;
 
 	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
 		memset(&ftp[i], 0, sizeof(struct ip_conntrack_helper));
@@ -400,7 +410,19 @@
 		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
 		ftp[i].mask.src.u.tcp.port = 0xFFFF;
 		ftp[i].mask.dst.protonum = 0xFFFF;
+		ftp[i].max_expected = 1;
+		ftp[i].timeout = 0;
+		ftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
+		ftp[i].me = ip_conntrack_ftp;
 		ftp[i].help = help;
+
+		tmpname = &ftp_names[i][0];
+		if (ports[i] == FTP_PORT)
+			sprintf(tmpname, "ftp");
+		else
+			sprintf(tmpname, "ftp-%d", ports[i]);
+		ftp[i].name = tmpname;
+
 		DEBUGP("ip_ct_ftp: registering helper for port %d\n", 
 				ports[i]);
 		ret = ip_conntrack_helper_register(&ftp[i]);
@@ -414,10 +436,10 @@
 	return 0;
 }
 
-
+#ifdef CONFIG_IP_NF_NAT_NEEDED
 EXPORT_SYMBOL(ip_ftp_lock);
-EXPORT_SYMBOL(ip_conntrack_ftp);
-MODULE_LICENSE("GPL");
+#endif
 
+MODULE_LICENSE("GPL");
 module_init(init);
 module_exit(fini);
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_irc.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_irc.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_irc.c	Mon Aug 12 16:34:17 2002
@@ -11,12 +11,18 @@
  **
  *	Module load syntax:
  * 	insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
+ *			    max_dcc_channels=n dcc_timeout=secs
  *	
  * 	please give the ports of all IRC servers You wish to connect to.
- *	If You don't specify ports, the default will be port 6667
+ *	If You don't specify ports, the default will be port 6667.
+ *	With max_dcc_channels you can define the maximum number of not
+ *	yet answered DCC channels per IRC session (default 8).
+ *	With dcc_timeout you can specify how long the system waits for 
+ *	an expected DCC channel (default 300 seconds).
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
@@ -29,7 +35,9 @@
 
 #define MAX_PORTS 8
 static int ports[MAX_PORTS];
-static int ports_n_c = 0;
+static int ports_c = 0;
+static int max_dcc_channels = 8;
+static unsigned int dcc_timeout = 300;
 
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("IRC (DCC) connection tracking module");
@@ -37,6 +45,10 @@
 #ifdef MODULE_PARM
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
 MODULE_PARM_DESC(ports, "port numbers of IRC servers");
+MODULE_PARM(max_dcc_channels, "i");
+MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
+MODULE_PARM(dcc_timeout, "i");
+MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
 #endif
 
 #define NUM_DCCPROTO 	5
@@ -103,23 +115,15 @@
 	u_int32_t tcplen = len - iph->ihl * 4;
 	u_int32_t datalen = tcplen - tcph->doff * 4;
 	int dir = CTINFO2DIR(ctinfo);
-	struct ip_conntrack_tuple t, mask;
+	struct ip_conntrack_expect expect, *exp = &expect;
+	struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;
 
 	u_int32_t dcc_ip;
 	u_int16_t dcc_port;
 	int i;
 	char *addr_beg_p, *addr_end_p;
 
-	struct ip_ct_irc *info = &ct->help.ct_irc_info;
-
-	mask = ((struct ip_conntrack_tuple)
-		{ { 0, { 0 } },
-		  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
-
 	DEBUGP("entered\n");
-	/* Can't track connections formed before we registered */
-	if (!info)
-		return NF_ACCEPT;
 
 	/* If packet is coming from IRC server */
 	if (dir == IP_CT_DIR_REPLY)
@@ -189,33 +193,37 @@
 
 				continue;
 			}
+			
+			memset(&expect, 0, sizeof(expect));
 
 			LOCK_BH(&ip_irc_lock);
 
 			/* save position of address in dcc string,
 			 * neccessary for NAT */
-			info->is_irc = IP_CONNTR_IRC;
 			DEBUGP("tcph->seq = %u\n", tcph->seq);
-			info->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
-			info->len = (addr_end_p - addr_beg_p);
-			info->port = dcc_port;
+			exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
+			exp_irc_info->len = (addr_end_p - addr_beg_p);
+			exp_irc_info->port = dcc_port;
 			DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
-				info->seq, (addr_end_p - _data), info->len);
+				exp->seq, (addr_end_p - _data), exp_irc_info->len);
 
-			memset(&t, 0, sizeof(t));
-			t.src.ip = 0;
-			t.src.u.tcp.port = 0;
-			t.dst.ip = htonl(dcc_ip);
-			t.dst.u.tcp.port = htons(info->port);
-			t.dst.protonum = IPPROTO_TCP;
+			exp->tuple = ((struct ip_conntrack_tuple)
+				{ { 0, { 0 } },
+				  { htonl(dcc_ip), { htons(dcc_port) },
+				    IPPROTO_TCP }});
+			exp->mask = ((struct ip_conntrack_tuple)
+				{ { 0, { 0 } },
+				  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+
+			exp->expectfn = NULL;
 
 			DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
-				NIPQUAD(t.src.ip),
-				ntohs(t.src.u.tcp.port),
-				NIPQUAD(t.dst.ip),
-				ntohs(t.dst.u.tcp.port));
+				NIPQUAD(exp->tuple.src.ip),
+				ntohs(exp->tuple.src.u.tcp.port),
+				NIPQUAD(exp->tuple.dst.ip),
+				ntohs(exp->tuple.dst.u.tcp.port));
 
-			ip_conntrack_expect_related(ct, &t, &mask, NULL);
+			ip_conntrack_expect_related(ct, &expect);
 			UNLOCK_BH(&ip_irc_lock);
 
 			return NF_ACCEPT;
@@ -226,29 +234,53 @@
 }
 
 static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
+static char irc_names[MAX_PORTS][10];
 
 static void fini(void);
 
 static int __init init(void)
 {
 	int i, ret;
+	struct ip_conntrack_helper *hlpr;
+	char *tmpname;
 
+	if (max_dcc_channels < 1) {
+		printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n");
+		return -EBUSY;
+	}
+	if (dcc_timeout < 0) {
+		printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n");
+		return -EBUSY;
+	}
+	
 	/* If no port given, default to standard irc port */
 	if (ports[0] == 0)
-		ports[0] = 6667;
+		ports[0] = IRC_PORT;
 
 	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
-		memset(&irc_helpers[i], 0,
+		hlpr = &irc_helpers[i];
+		memset(hlpr, 0,
 		       sizeof(struct ip_conntrack_helper));
-		irc_helpers[i].tuple.src.u.tcp.port = htons(ports[i]);
-		irc_helpers[i].tuple.dst.protonum = IPPROTO_TCP;
-		irc_helpers[i].mask.src.u.tcp.port = 0xFFFF;
-		irc_helpers[i].mask.dst.protonum = 0xFFFF;
-		irc_helpers[i].help = help;
+		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+		hlpr->tuple.dst.protonum = IPPROTO_TCP;
+		hlpr->mask.src.u.tcp.port = 0xFFFF;
+		hlpr->mask.dst.protonum = 0xFFFF;
+		hlpr->max_expected = max_dcc_channels;
+		hlpr->timeout = dcc_timeout;
+		hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
+		hlpr->me = ip_conntrack_irc;
+		hlpr->help = help;
+
+		tmpname = &irc_names[i][0];
+		if (ports[i] == IRC_PORT)
+			sprintf(tmpname, "irc");
+		else
+			sprintf(tmpname, "irc-%d", i);
+		hlpr->name = tmpname;
 
 		DEBUGP("port #%d: %d\n", i, ports[i]);
 
-		ret = ip_conntrack_helper_register(&irc_helpers[i]);
+		ret = ip_conntrack_helper_register(hlpr);
 
 		if (ret) {
 			printk("ip_conntrack_irc: ERROR registering port %d\n",
@@ -256,7 +288,7 @@
 			fini();
 			return -EBUSY;
 		}
-		ports_n_c++;
+		ports_c++;
 	}
 	return 0;
 }
@@ -266,12 +298,16 @@
 static void fini(void)
 {
 	int i;
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; i++) {
 		DEBUGP("unregistering port %d\n",
 		       ports[i]);
 		ip_conntrack_helper_unregister(&irc_helpers[i]);
 	}
 }
 
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+EXPORT_SYMBOL(ip_irc_lock);
+#endif
+
 module_init(init);
 module_exit(fini);
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_proto_generic.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Mon Aug 12 16:34:17 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, NULL };
+    generic_print_conntrack, established, new, NULL, NULL, NULL };
 
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Mon Aug 12 16:34:17 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, NULL };
+    icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL, NULL };
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Mon Aug 12 16:34:17 2002
@@ -7,6 +7,9 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+
+#include <net/tcp.h>
+
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 #include <linux/netfilter_ipv4/lockhelp.h>
@@ -227,7 +230,19 @@
 	return 1;
 }
 
+static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
+			       struct sk_buff **pskb)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+	unsigned int datalen;
+
+	datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
+
+	return between(exp->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
+}
+
 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, NULL };
+    tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Mon Aug 12 16:34:17 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, NULL };
+    udp_packet, udp_new, NULL, NULL, NULL };
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_conntrack_standalone.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_conntrack_standalone.c	Mon Aug 12 16:34:17 2002
@@ -62,8 +62,14 @@
 {
 	unsigned int len;
 
-	len = sprintf(buffer, "EXPECTING: proto=%u ",
-		      expect->tuple.dst.protonum);
+	if (expect->expectant->helper->timeout)
+		len = sprintf(buffer, "EXPECTING: %lu ",
+			      timer_pending(&expect->timeout)
+			      ? (expect->timeout.expires - jiffies)/HZ : 0);
+	else
+		len = sprintf(buffer, "EXPECTING: - ");
+	len += sprintf(buffer + len, "use=%u proto=%u ",
+		      atomic_read(&expect->use), expect->tuple.dst.protonum);
 	len += print_tuple(buffer + len, &expect->tuple,
 			   __find_proto(expect->tuple.dst.protonum));
 	len += sprintf(buffer + len, "\n");
@@ -147,7 +153,8 @@
 	}
 
 	/* Now iterate through expecteds. */
-	for (e = expect_list.next; e != &expect_list; e = e->next) {
+	for (e = ip_conntrack_expect_list.next; 
+	     e != &ip_conntrack_expect_list; e = e->next) {
 		unsigned int last_len;
 		struct ip_conntrack_expect *expect
 			= (struct ip_conntrack_expect *)e;
@@ -314,7 +321,7 @@
 {
 	WRITE_LOCK(&ip_conntrack_lock);
 
-	/* find_proto() returns proto_generic in case there is no protocol 
+	/* ip_ct_find_proto() returns proto_generic in case there is no protocol 
 	 * helper. So this should be enough - HW */
 	LIST_DELETE(&protocol_list, proto);
 	WRITE_UNLOCK(&ip_conntrack_lock);
@@ -353,8 +360,18 @@
 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
 EXPORT_SYMBOL(ip_ct_selective_cleanup);
 EXPORT_SYMBOL(ip_ct_refresh);
+EXPORT_SYMBOL(ip_ct_find_proto);
+EXPORT_SYMBOL(ip_ct_find_helper);
 EXPORT_SYMBOL(ip_conntrack_expect_related);
+EXPORT_SYMBOL(ip_conntrack_change_expect);
 EXPORT_SYMBOL(ip_conntrack_unexpect_related);
+EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
+EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
 EXPORT_SYMBOL(ip_ct_gather_frags);
 EXPORT_SYMBOL(ip_conntrack_htable_size);
+EXPORT_SYMBOL(ip_conntrack_expect_list);
+EXPORT_SYMBOL(ip_conntrack_lock);
+EXPORT_SYMBOL(ip_conntrack_hash);
+EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
+EXPORT_SYMBOL_GPL(ip_conntrack_put);
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_fw_compat_masq.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_fw_compat_masq.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_fw_compat_masq.c	Mon Aug 12 16:34:17 2002
@@ -130,7 +130,7 @@
 	struct ip_conntrack *ct;
 	int ret;
 
-	protocol = find_proto(iph->protocol);
+	protocol = ip_ct_find_proto(iph->protocol);
 
 	/* We don't feed packets to conntrack system unless we know
            they're part of an connection already established by an
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_core.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_core.c	Mon Aug 12 16:34:13 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_core.c	Mon Aug 12 16:34:17 2002
@@ -21,10 +21,14 @@
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
 
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 #include <linux/netfilter_ipv4/ip_nat_core.h>
 #include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
 #if 0
@@ -34,6 +38,7 @@
 #endif
 
 DECLARE_RWLOCK(ip_nat_lock);
+DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
 
 /* Calculated at init based on memory size */
 static unsigned int ip_nat_htable_size;
@@ -630,8 +635,9 @@
 	}
 
 	/* If there's a helper, assign it; based on new tuple. */
-	info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
-				 &reply);
+	if (!conntrack->master)
+		info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
+					 &reply);
 
 	/* It's done. */
 	info->initialized |= (1 << HOOK2MANIP(hooknum));
@@ -726,6 +732,20 @@
 #endif
 }
 
+static inline int exp_for_packet(struct ip_conntrack_expect *exp,
+			         struct sk_buff **pskb)
+{
+	struct ip_conntrack_protocol *proto;
+	int ret = 1;
+
+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+	proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
+	if (proto->exp_matches_pkt)
+		ret = proto->exp_matches_pkt(exp, pskb);
+
+	return ret;
+}
+
 /* Do packet manipulations according to binding. */
 unsigned int
 do_bindings(struct ip_conntrack *ct,
@@ -737,6 +757,7 @@
 	unsigned int i;
 	struct ip_nat_helper *helper;
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
 
 	/* Need nat lock to protect against modification, but neither
 	   conntrack (referenced) and helper (deleted with
@@ -775,11 +796,66 @@
 	READ_UNLOCK(&ip_nat_lock);
 
 	if (helper) {
+		struct ip_conntrack_expect *exp = NULL;
+		struct list_head *cur_item;
+		int ret = NF_ACCEPT;
+
+		DEBUGP("do_bindings: helper existing for (%p)\n", ct);
+
 		/* Always defragged for helpers */
 		IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
 			       & __constant_htons(IP_MF|IP_OFFSET)));
-		return helper->help(ct, info, ctinfo, hooknum, pskb);
-	} else return NF_ACCEPT;
+
+		/* Have to grab read lock before sibling_list traversal */
+		READ_LOCK(&ip_conntrack_lock);
+		list_for_each(cur_item, &ct->sibling_list) { 
+			exp = list_entry(cur_item, struct ip_conntrack_expect, 
+					 expected_list);
+					 
+			/* if this expectation is already established, skip */
+			if (exp->sibling)
+				continue;
+
+			if (exp_for_packet(exp, pskb)) {
+				/* FIXME: May be true multiple times in the case of UDP!! */
+				DEBUGP("calling nat helper (exp=%p) for packet\n",
+					exp);
+				ret = helper->help(ct, exp, info, ctinfo, 
+						   hooknum, pskb);
+				if (ret != NF_ACCEPT) {
+					READ_UNLOCK(&ip_conntrack_lock);
+					return ret;
+				}
+			}
+		}
+		/* Helper might want to manip the packet even when there is no expectation */
+		if (!exp && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
+			DEBUGP("calling nat helper for packet without expectation\n");
+			ret = helper->help(ct, NULL, info, ctinfo, 
+					   hooknum, pskb);
+			if (ret != NF_ACCEPT) {
+				READ_UNLOCK(&ip_conntrack_lock);
+				return ret;
+			}
+		}
+		READ_UNLOCK(&ip_conntrack_lock);
+		
+		/* Adjust sequence number only once per packet 
+		 * (helper is called at all hooks) */
+		if (is_tcp && (hooknum == NF_IP_POST_ROUTING
+			       || hooknum == NF_IP_LOCAL_IN)) {
+			DEBUGP("ip_nat_core: adjusting sequence number\n");
+			/* future: put this in a l4-proto specific function,
+			 * and call this function here. */
+			ip_nat_seq_adjust(*pskb, ct, ctinfo);
+		}
+
+		return ret;
+
+	} else 
+		return NF_ACCEPT;
+
+	/* not reached */
 }
 
 unsigned int
@@ -922,4 +998,5 @@
 {
 	ip_ct_selective_cleanup(&clean_nat, NULL);
 	ip_conntrack_destroyed = NULL;
+	vfree(bysource);
 }
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_ftp.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_ftp.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_ftp.c	Tue Oct 30 15:08:12 2001
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_ftp.c	Mon Aug 12 16:34:17 2002
@@ -28,38 +28,30 @@
 
 /* FIXME: Time out? --RR */
 
-static int
+static unsigned int
 ftp_nat_expected(struct sk_buff **pskb,
 		 unsigned int hooknum,
 		 struct ip_conntrack *ct,
-		 struct ip_nat_info *info,
-		 struct ip_conntrack *master,
-		 struct ip_nat_info *masterinfo,
-		 unsigned int *verdict)
+		 struct ip_nat_info *info)
 {
 	struct ip_nat_multi_range mr;
 	u_int32_t newdstip, newsrcip, newip;
-	struct ip_ct_ftp *ftpinfo;
+	struct ip_ct_ftp_expect *exp_ftp_info;
 
+	struct ip_conntrack *master = master_ct(ct);
+	
 	IP_NF_ASSERT(info);
 	IP_NF_ASSERT(master);
-	IP_NF_ASSERT(masterinfo);
 
 	IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
 
 	DEBUGP("nat_expected: We have a connection!\n");
-	/* Master must be an ftp connection */
-	ftpinfo = &master->help.ct_ftp_info;
+	exp_ftp_info = &ct->master->help.exp_ftp_info;
 
 	LOCK_BH(&ip_ftp_lock);
-	if (ftpinfo->is_ftp != 21) {
-		UNLOCK_BH(&ip_ftp_lock);
-		DEBUGP("nat_expected: master not ftp\n");
-		return 0;
-	}
 
-	if (ftpinfo->ftptype == IP_CT_FTP_PORT
-	    || ftpinfo->ftptype == IP_CT_FTP_EPRT) {
+	if (exp_ftp_info->ftptype == IP_CT_FTP_PORT
+	    || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) {
 		/* PORT command: make connection go to the client. */
 		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
@@ -92,11 +84,9 @@
 		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
 		mr.range[0].min = mr.range[0].max
 			= ((union ip_conntrack_manip_proto)
-				{ htons(ftpinfo->port) });
+				{ htons(exp_ftp_info->port) });
 	}
-	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
-
-	return 1;
+	return ip_nat_setup_info(ct, &mr, hooknum);
 }
 
 static int
@@ -176,27 +166,22 @@
     [IP_CT_FTP_EPSV] mangle_epsv_packet
 };
 
-static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
+static int ftp_data_fixup(const struct ip_ct_ftp_expect *ct_ftp_info,
 			  struct ip_conntrack *ct,
-			  unsigned int datalen,
 			  struct sk_buff **pskb,
-			  enum ip_conntrack_info ctinfo)
+			  enum ip_conntrack_info ctinfo,
+			  struct ip_conntrack_expect *expect)
 {
 	u_int32_t newip;
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
 	u_int16_t port;
-	struct ip_conntrack_tuple tuple;
-	/* Don't care about source port */
-	const struct ip_conntrack_tuple mask
-		= { { 0xFFFFFFFF, { 0 } },
-		    { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF } };
+	struct ip_conntrack_tuple newtuple;
 
-	memset(&tuple, 0, sizeof(tuple));
 	MUST_BE_LOCKED(&ip_ftp_lock);
-	DEBUGP("FTP_NAT: seq %u + %u in %u + %u\n",
-	       ct_ftp_info->seq, ct_ftp_info->len,
-	       ntohl(tcph->seq), datalen);
+	DEBUGP("FTP_NAT: seq %u + %u in %u\n",
+	       expect->seq, ct_ftp_info->len,
+	       ntohl(tcph->seq));
 
 	/* Change address inside packet to match way we're mapping
 	   this connection. */
@@ -206,29 +191,34 @@
 		   is */
 		newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
 		/* Expect something from client->server */
-		tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
-		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+		newtuple.src.ip = 
+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+		newtuple.dst.ip = 
+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
 	} else {
 		/* PORT command: must be where server thinks client is */
 		newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 		/* Expect something from server->client */
-		tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
-		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+		newtuple.src.ip = 
+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+		newtuple.dst.ip = 
+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 	}
-	tuple.dst.protonum = IPPROTO_TCP;
+	newtuple.dst.protonum = IPPROTO_TCP;
+	newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
 
 	/* Try to get same port: if not, try to change it. */
 	for (port = ct_ftp_info->port; port != 0; port++) {
-		tuple.dst.u.tcp.port = htons(port);
+		newtuple.dst.u.tcp.port = htons(port);
 
-		if (ip_conntrack_expect_related(ct, &tuple, &mask, NULL) == 0)
+		if (ip_conntrack_change_expect(expect, &newtuple) == 0)
 			break;
 	}
 	if (port == 0)
 		return 0;
 
 	if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,
-					  ct_ftp_info->seq - ntohl(tcph->seq),
+					  expect->seq - ntohl(tcph->seq),
 					  ct_ftp_info->len, ct, ctinfo))
 		return 0;
 
@@ -236,6 +226,7 @@
 }
 
 static unsigned int help(struct ip_conntrack *ct,
+			 struct ip_conntrack_expect *exp,
 			 struct ip_nat_info *info,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned int hooknum,
@@ -245,13 +236,12 @@
 	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
 	unsigned int datalen;
 	int dir;
-	int score;
-	struct ip_ct_ftp *ct_ftp_info
-		= &ct->help.ct_ftp_info;
-
-	/* Delete SACK_OK on initial TCP SYNs. */
-	if (tcph->syn && !tcph->ack)
-		ip_nat_delete_sack(*pskb, tcph);
+	struct ip_ct_ftp_expect *ct_ftp_info;
+
+	if (!exp)
+		DEBUGP("ip_nat_ftp: no exp!!");
+
+	ct_ftp_info = &exp->help.exp_ftp_info;
 
 	/* Only mangle things once: original direction in POST_ROUTING
 	   and reply direction on PRE_ROUTING. */
@@ -267,103 +257,87 @@
 	}
 
 	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
-	score = 0;
 	LOCK_BH(&ip_ftp_lock);
-	if (ct_ftp_info->len) {
-		/* If it's in the right range... */
-		score += between(ct_ftp_info->seq, ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		score += between(ct_ftp_info->seq + ct_ftp_info->len,
-				 ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		if (score == 1) {
-			/* Half a match?  This means a partial retransmisison.
-			   It's a cracker being funky. */
-			if (net_ratelimit()) {
-				printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
-				       ct_ftp_info->seq, ct_ftp_info->len,
-				       ntohl(tcph->seq),
-				       ntohl(tcph->seq) + datalen);
-			}
+	/* If it's in the right range... */
+	if (between(exp->seq + ct_ftp_info->len,
+		    ntohl(tcph->seq),
+		    ntohl(tcph->seq) + datalen)) {
+		if (!ftp_data_fixup(ct_ftp_info, ct, pskb, ctinfo, exp)) {
 			UNLOCK_BH(&ip_ftp_lock);
 			return NF_DROP;
-		} else if (score == 2) {
-			if (!ftp_data_fixup(ct_ftp_info, ct, datalen,
-					    pskb, ctinfo)) {
-				UNLOCK_BH(&ip_ftp_lock);
-				return NF_DROP;
-			}
-			/* skb may have been reallocated */
-			iph = (*pskb)->nh.iph;
-			tcph = (void *)iph + iph->ihl*4;
 		}
+	} else {
+		/* Half a match?  This means a partial retransmisison.
+		   It's a cracker being funky. */
+		if (net_ratelimit()) {
+			printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
+			       exp->seq, ct_ftp_info->len,
+			       ntohl(tcph->seq),
+			       ntohl(tcph->seq) + datalen);
+		}
+		UNLOCK_BH(&ip_ftp_lock);
+		return NF_DROP;
 	}
-
 	UNLOCK_BH(&ip_ftp_lock);
 
-	ip_nat_seq_adjust(*pskb, ct, ctinfo);
-
 	return NF_ACCEPT;
 }
 
 static struct ip_nat_helper ftp[MAX_PORTS];
-static char ftp_names[MAX_PORTS][6];
-
-static struct ip_nat_expect ftp_expect
-= { { NULL, NULL }, ftp_nat_expected };
+static char ftp_names[MAX_PORTS][10];
 
 /* Not __exit: called from init() */
 static void fini(void)
 {
 	int i;
 
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; i++) {
 		DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]);
 		ip_nat_helper_unregister(&ftp[i]);
 	}
-
-	ip_nat_expect_unregister(&ftp_expect);
 }
 
 static int __init init(void)
 {
-	int i, ret;
+	int i, ret = 0;
 	char *tmpname;
 
-	ret = ip_nat_expect_register(&ftp_expect);
-	if (ret == 0) {
-		if (ports[0] == 0)
-			ports[0] = 21;
-
-		for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
-
-			memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
-
-			ftp[i].tuple.dst.protonum = IPPROTO_TCP;
-			ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
-			ftp[i].mask.dst.protonum = 0xFFFF;
-			ftp[i].mask.src.u.tcp.port = 0xFFFF;
-			ftp[i].help = help;
-
-			tmpname = &ftp_names[i][0];
-			sprintf(tmpname, "ftp%2.2d", i);
-			ftp[i].name = tmpname;
-
-			DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
-					ports[i]);
-			ret = ip_nat_helper_register(&ftp[i]);
-
-			if (ret) {
-				printk("ip_nat_ftp: error registering helper for port %d\n", ports[i]);
-				fini();
-				return ret;
-			}
-			ports_c++;
-		}
+	if (ports[0] == 0)
+		ports[0] = FTP_PORT;
 
-	} else {
-		ip_nat_expect_unregister(&ftp_expect);
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+
+		memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
+
+		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
+		ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
+		ftp[i].mask.dst.protonum = 0xFFFF;
+		ftp[i].mask.src.u.tcp.port = 0xFFFF;
+		ftp[i].help = help;
+		ftp[i].me = THIS_MODULE;
+		ftp[i].flags = 0;
+		ftp[i].expect = ftp_nat_expected;
+
+		tmpname = &ftp_names[i][0];
+		if (ports[i] == FTP_PORT)
+			sprintf(tmpname, "ftp");
+		else
+			sprintf(tmpname, "ftp-%d", i);
+		ftp[i].name = tmpname;
+
+		DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
+				ports[i]);
+		ret = ip_nat_helper_register(&ftp[i]);
+
+		if (ret) {
+			printk("ip_nat_ftp: error registering "
+			       "helper for port %d\n", ports[i]);
+			fini();
+			return ret;
+		}
+		ports_c++;
 	}
+
 	return ret;
 }
 
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_helper.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_helper.c	Mon Aug 12 16:34:17 2002
@@ -1,11 +1,18 @@
 /* ip_nat_mangle.c - generic support functions for NAT helpers 
  *
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
  *
  * distributed under the terms of GNU GPL
+ *
+ * 	14 Jan 2002 Harald Welte <laforge@gnumonks.org>:
+ *		- add support for SACK adjustment 
+ *	14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
+ *		- merge SACK support into newnat API
  */
 #include <linux/version.h>
+#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/kmod.h>
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/skbuff.h>
@@ -19,6 +26,8 @@
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
 
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 #include <linux/netfilter_ipv4/ip_nat_core.h>
@@ -32,7 +41,7 @@
 #define DEBUGP(format, args...)
 #define DUMP_OFFSET(x)
 #endif
-	
+
 DECLARE_LOCK(ip_nat_seqofs_lock);
 			 
 static inline int 
@@ -199,6 +208,103 @@
 	return 1;
 }
 
+/* Adjust one found SACK option including checksum correction */
+static void
+sack_adjust(struct tcphdr *tcph, 
+	    unsigned char *ptr, 
+	    struct ip_nat_seq *natseq)
+{
+	struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
+	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
+	int i;
+
+	for (i = 0; i < num_sacks; i++, sp++) {
+		u_int32_t new_start_seq, new_end_seq;
+
+		if (after(ntohl(sp->start_seq) - natseq->offset_before,
+			  natseq->correction_pos))
+			new_start_seq = ntohl(sp->start_seq) 
+					- natseq->offset_after;
+		else
+			new_start_seq = ntohl(sp->start_seq) 
+					- natseq->offset_before;
+		new_start_seq = htonl(new_start_seq);
+
+		if (after(ntohl(sp->end_seq) - natseq->offset_before,
+			  natseq->correction_pos))
+			new_end_seq = ntohl(sp->end_seq)
+				      - natseq->offset_after;
+		else
+			new_end_seq = ntohl(sp->end_seq)
+				      - natseq->offset_before;
+		new_end_seq = htonl(new_end_seq);
+
+		DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
+			ntohl(sp->start_seq), new_start_seq,
+			ntohl(sp->end_seq), new_end_seq);
+
+		tcph->check = 
+			ip_nat_cheat_check(~sp->start_seq, new_start_seq,
+					   ip_nat_cheat_check(~sp->end_seq, 
+						   	      new_end_seq,
+							      tcph->check));
+
+		sp->start_seq = new_start_seq;
+		sp->end_seq = new_end_seq;
+	}
+}
+			
+
+/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */
+static inline int
+ip_nat_sack_adjust(struct sk_buff *skb,
+			struct ip_conntrack *ct,
+			enum ip_conntrack_info ctinfo)
+{
+	struct iphdr *iph;
+	struct tcphdr *tcph;
+	unsigned char *ptr;
+	int length, dir, sack_adjusted = 0;
+
+	iph = skb->nh.iph;
+	tcph = (void *)iph + iph->ihl*4;
+	length = (tcph->doff*4)-sizeof(struct tcphdr);
+	ptr = (unsigned char *)(tcph+1);
+
+	dir = CTINFO2DIR(ctinfo);
+
+	while (length > 0) {
+		int opcode = *ptr++;
+		int opsize;
+
+		switch (opcode) {
+		case TCPOPT_EOL:
+			return !sack_adjusted;
+		case TCPOPT_NOP:
+			length--;
+			continue;
+		default:
+			opsize = *ptr++;
+			if (opsize > length) /* no partial opts */
+				return !sack_adjusted;
+			if (opcode == TCPOPT_SACK) {
+				/* found SACK */
+				if((opsize >= (TCPOLEN_SACK_BASE
+					       +TCPOLEN_SACK_PERBLOCK)) &&
+				   !((opsize - TCPOLEN_SACK_BASE)
+				     % TCPOLEN_SACK_PERBLOCK))
+					sack_adjust(tcph, ptr-2,
+						    &ct->nat.info.seq[!dir]);
+				
+				sack_adjusted = 1;
+			}
+			ptr += opsize-2;
+			length -= opsize;
+		}
+	}
+	return !sack_adjusted;
+}
+
 /* TCP sequence number adjustment */
 int 
 ip_nat_seq_adjust(struct sk_buff *skb, 
@@ -243,51 +349,9 @@
 	tcph->seq = newseq;
 	tcph->ack_seq = newack;
 
-	return 0;
-}
-
-/* Grrr... SACK.  Fuck me even harder.  Don't want to fix it on the
-   fly, so blow it away. */
-void
-ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph)
-{
-	unsigned int i;
-	u_int8_t *opt = (u_int8_t *)tcph;
-
-	DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n",
-	       tcph->doff * 4);
-	for (i = sizeof(struct tcphdr); i < tcph->doff * 4;) {
-		DEBUGP("%u ", opt[i]);
-		switch (opt[i]) {
-		case TCPOPT_NOP:
-		case TCPOPT_EOL:
-			i++;
-			break;
+	ip_nat_sack_adjust(skb, ct, ctinfo);
 
-		case TCPOPT_SACK_PERM:
-			goto found_opt;
-
-		default:
-			/* Worst that can happen: it will take us over. */
-			i += opt[i+1] ?: 1;
-		}
-	}
-	DEBUGP("\n");
-	return;
-
- found_opt:
-	DEBUGP("\n");
-	DEBUGP("Found SACKPERM at offset %u.\n", i);
-
-	/* Must be within TCP header, and valid SACK perm. */
-	if (i + opt[i+1] <= tcph->doff*4 && opt[i+1] == 2) {
-		/* Replace with NOPs. */
-		tcph->check
-			= ip_nat_cheat_check(*((u_int16_t *)(opt + i))^0xFFFF,
-					     (TCPOPT_NOP<<8)|TCPOPT_NOP, tcph->check);
-		opt[i] = opt[i+1] = TCPOPT_NOP;
-	}
-	else DEBUGP("Something wrong with SACK_PERM.\n");
+	return 0;
 }
 
 static inline int
@@ -297,10 +361,51 @@
 	return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
 }
 
+#define MODULE_MAX_NAMELEN		32
+
 int ip_nat_helper_register(struct ip_nat_helper *me)
 {
 	int ret = 0;
 
+	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
+		struct ip_conntrack_helper *ct_helper;
+		
+		if ((ct_helper = ip_ct_find_helper(&me->tuple))
+		    && ct_helper->me) {
+			__MOD_INC_USE_COUNT(ct_helper->me);
+		} else {
+
+			/* We are a NAT helper for protocol X.  If we need
+			 * respective conntrack helper for protoccol X, compute
+			 * conntrack helper name and try to load module */
+			char name[MODULE_MAX_NAMELEN];
+			const char *tmp = me->me->name;
+			
+			if (strlen(tmp) + 6 > MODULE_MAX_NAMELEN) {
+				printk(__FUNCTION__ ": unable to "
+				       "compute conntrack helper name "
+				       "from %s\n", tmp);
+				return -EBUSY;
+			}
+			tmp += 6;
+			sprintf(name, "ip_conntrack%s", tmp);
+#ifdef CONFIG_KMOD
+			if (!request_module(name)
+			    && (ct_helper = ip_ct_find_helper(&me->tuple))
+			    && ct_helper->me) {
+				__MOD_INC_USE_COUNT(ct_helper->me);
+			} else {
+				printk("unable to load module %s\n", name);
+				return -EBUSY;
+			}
+#else
+			printk("unable to load module %s automatically "
+			       "because kernel was compiled without kernel "
+			       "module loader support\n", name);
+			return -EBUSY;
+#endif
+		}
+	}
 	WRITE_LOCK(&ip_nat_lock);
 	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
 		ret = -EBUSY;
@@ -327,8 +432,14 @@
 
 void ip_nat_helper_unregister(struct ip_nat_helper *me)
 {
+	int found = 0;
+	
 	WRITE_LOCK(&ip_nat_lock);
-	LIST_DELETE(&helpers, me);
+	/* Autoloading conntrack helper might have failed */
+	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) {
+		LIST_DELETE(&helpers, me);
+		found = 1;
+	}
 	WRITE_UNLOCK(&ip_nat_lock);
 
 	/* Someone could be still looking at the helper in a bh. */
@@ -344,5 +455,19 @@
 	   worse. --RR */
 	ip_ct_selective_cleanup(kill_helper, me);
 
-	MOD_DEC_USE_COUNT;
+	if (found)
+		MOD_DEC_USE_COUNT;
+
+	/* If we are no standalone NAT helper, we need to decrement usage count
+	 * on our conntrack helper */
+	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
+		struct ip_conntrack_helper *ct_helper;
+		
+		if ((ct_helper = ip_ct_find_helper(&me->tuple))
+		    && ct_helper->me) {
+			__MOD_DEC_USE_COUNT(ct_helper->me);
+		} else 
+			printk(__FUNCTION__ ": unable to decrement usage count"
+			       " of conntrack helper %s\n", me->me->name);
+	}
 }
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_irc.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_irc.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_irc.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_irc.c	Mon Aug 12 16:34:17 2002
@@ -51,42 +51,29 @@
 
 /* FIXME: Time out? --RR */
 
-static int
+static unsigned int
 irc_nat_expected(struct sk_buff **pskb,
 		 unsigned int hooknum,
 		 struct ip_conntrack *ct,
-		 struct ip_nat_info *info,
-		 struct ip_conntrack *master,
-		 struct ip_nat_info *masterinfo, unsigned int *verdict)
+		 struct ip_nat_info *info)
 {
 	struct ip_nat_multi_range mr;
 	u_int32_t newdstip, newsrcip, newip;
-	struct ip_ct_irc *ircinfo;
+
+	struct ip_conntrack *master = master_ct(ct);
 
 	IP_NF_ASSERT(info);
 	IP_NF_ASSERT(master);
-	IP_NF_ASSERT(masterinfo);
 
 	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
 
 	DEBUGP("nat_expected: We have a connection!\n");
 
-	/* Master must be an irc connection */
-	ircinfo = &master->help.ct_irc_info;
-	LOCK_BH(&ip_irc_lock);
-	if (ircinfo->is_irc != IP_CONNTR_IRC) {
-		UNLOCK_BH(&ip_irc_lock);
-		DEBUGP("nat_expected: master not irc\n");
-		return 0;
-	}
-
 	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 	newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 	DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
 	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
 
-	UNLOCK_BH(&ip_irc_lock);
-
 	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
 		newip = newsrcip;
 	else
@@ -99,16 +86,14 @@
 	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
 	mr.range[0].min_ip = mr.range[0].max_ip = newip;
 
-	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
-
-	return 1;
+	return ip_nat_setup_info(ct, &mr, hooknum);
 }
 
-static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info,
+static int irc_data_fixup(const struct ip_ct_irc_expect *ct_irc_info,
 			  struct ip_conntrack *ct,
-			  unsigned int datalen,
 			  struct sk_buff **pskb,
-			  enum ip_conntrack_info ctinfo)
+			  enum ip_conntrack_info ctinfo,
+			  struct ip_conntrack_expect *expect)
 {
 	u_int32_t newip;
 	struct ip_conntrack_tuple t;
@@ -121,9 +106,9 @@
 
 	MUST_BE_LOCKED(&ip_irc_lock);
 
-	DEBUGP("IRC_NAT: info (seq %u + %u) packet(seq %u + %u)\n",
-	       ct_irc_info->seq, ct_irc_info->len,
-	       ntohl(tcph->seq), datalen);
+	DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
+	       expect->seq, ct_irc_info->len,
+	       ntohl(tcph->seq));
 
 	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 
@@ -133,13 +118,11 @@
 	   only set in ip_conntrack_irc, with ip_irc_lock held
 	   writable */
 
-	t = ct->expected.tuple;
+	t = expect->tuple;
 	t.dst.ip = newip;
 	for (port = ct_irc_info->port; port != 0; port++) {
 		t.dst.u.tcp.port = htons(port);
-		if (ip_conntrack_expect_related(ct, &t,
-						&ct->expected.mask,
-						NULL) == 0) {
+		if (ip_conntrack_change_expect(expect, &t) == 0) {
 			DEBUGP("using port %d", port);
 			break;
 		}
@@ -166,26 +149,28 @@
 	       buffer, NIPQUAD(newip), port);
 
 	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
-					ct_irc_info->seq - ntohl(tcph->seq),
+					expect->seq - ntohl(tcph->seq),
 					ct_irc_info->len, buffer, 
 					strlen(buffer));
 }
 
 static unsigned int help(struct ip_conntrack *ct,
+			 struct ip_conntrack_expect *exp,
 			 struct ip_nat_info *info,
 			 enum ip_conntrack_info ctinfo,
-			 unsigned int hooknum, struct sk_buff **pskb)
+			 unsigned int hooknum, 
+			 struct sk_buff **pskb)
 {
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
 	unsigned int datalen;
 	int dir;
-	int score;
-	struct ip_ct_irc *ct_irc_info = &ct->help.ct_irc_info;
+	struct ip_ct_irc_expect *ct_irc_info;
 
-	/* Delete SACK_OK on initial TCP SYNs. */
-	if (tcph->syn && !tcph->ack)
-		ip_nat_delete_sack(*pskb, tcph);
+	if (!exp)
+		DEBUGP("ip_nat_irc: no exp!!");
+		
+	ct_irc_info = &exp->help.exp_irc_info;
 
 	/* Only mangle things once: original direction in POST_ROUTING
 	   and reply direction on PRE_ROUTING. */
@@ -202,55 +187,35 @@
 	DEBUGP("got beyond not touching\n");
 
 	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
-	score = 0;
 	LOCK_BH(&ip_irc_lock);
-	if (ct_irc_info->len) {
-		DEBUGP("got beyond ct_irc_info->len\n");
-
-		/* If it's in the right range... */
-		score += between(ct_irc_info->seq, ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		score += between(ct_irc_info->seq + ct_irc_info->len,
-				 ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		if (score == 1) {
-			/* Half a match?  This means a partial retransmisison.
-			   It's a cracker being funky. */
-			if (net_ratelimit()) {
-				printk
-				    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
-				     ct_irc_info->seq, ct_irc_info->len,
-				     ntohl(tcph->seq),
-				     ntohl(tcph->seq) + datalen);
-			}
+	/* Check wether the whole IP/address pattern is carried in the payload */
+	if (between(exp->seq + ct_irc_info->len,
+		    ntohl(tcph->seq),
+		    ntohl(tcph->seq) + datalen)) {
+		if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) {
 			UNLOCK_BH(&ip_irc_lock);
 			return NF_DROP;
-		} else if (score == 2) {
-			DEBUGP("IRC_NAT: score=2, calling fixup\n");
-			if (!irc_data_fixup(ct_irc_info, ct, datalen,
-					    pskb, ctinfo)) {
-				UNLOCK_BH(&ip_irc_lock);
-				return NF_DROP;
-			}
-			/* skb may have been reallocated */
-			iph = (*pskb)->nh.iph;
-			tcph = (void *) iph + iph->ihl * 4;
 		}
+	} else { 
+		/* Half a match?  This means a partial retransmisison.
+		   It's a cracker being funky. */
+		if (net_ratelimit()) {
+			printk
+			    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
+			     exp->seq, ct_irc_info->len,
+			     ntohl(tcph->seq),
+			     ntohl(tcph->seq) + datalen);
+		}
+		UNLOCK_BH(&ip_irc_lock);
+		return NF_DROP;
 	}
-
 	UNLOCK_BH(&ip_irc_lock);
 
-	ip_nat_seq_adjust(*pskb, ct, ctinfo);
-
 	return NF_ACCEPT;
 }
 
 static struct ip_nat_helper ip_nat_irc_helpers[MAX_PORTS];
-static char ip_nih_names[MAX_PORTS][6];
-
-static struct ip_nat_expect irc_expect
-    = { {NULL, NULL}, irc_nat_expected };
-
+static char irc_names[MAX_PORTS][10];
 
 /* This function is intentionally _NOT_ defined as  __exit, because
  * it is needed by init() */
@@ -262,52 +227,54 @@
 		DEBUGP("ip_nat_irc: unregistering helper for port %d\n",
 		       ports[i]);
 		ip_nat_helper_unregister(&ip_nat_irc_helpers[i]);
-	}
-	ip_nat_expect_unregister(&irc_expect);
+	} 
 }
+
 static int __init init(void)
 {
-	int ret;
+	int ret = 0;
 	int i;
 	struct ip_nat_helper *hlpr;
 	char *tmpname;
 
-	ret = ip_nat_expect_register(&irc_expect);
-	if (ret == 0) {
-
-		if (ports[0] == 0) {
-			ports[0] = 6667;
-		}
+	if (ports[0] == 0) {
+		ports[0] = IRC_PORT;
+	}
 
-		for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
-			hlpr = &ip_nat_irc_helpers[i];
-			memset(hlpr, 0,
-			       sizeof(struct ip_nat_helper));
-
-			hlpr->tuple.dst.protonum = IPPROTO_TCP;
-			hlpr->tuple.src.u.tcp.port = htons(ports[i]);
-			hlpr->mask.src.u.tcp.port = 0xFFFF;
-			hlpr->mask.dst.protonum = 0xFFFF;
-			hlpr->help = help;
-
-			tmpname = &ip_nih_names[i][0];
-			sprintf(tmpname, "irc%2.2d", i);
-
-			hlpr->name = tmpname;
-			DEBUGP
-			    ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
-			     ports[i], hlpr->name);
-			ret = ip_nat_helper_register(hlpr);
-
-			if (ret) {
-				printk
-				    ("ip_nat_irc: error registering helper for port %d\n",
-				     ports[i]);
-				fini();
-				return 1;
-			}
-			ports_c++;
+	for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
+		hlpr = &ip_nat_irc_helpers[i];
+		memset(hlpr, 0,
+		       sizeof(struct ip_nat_helper));
+
+		hlpr->tuple.dst.protonum = IPPROTO_TCP;
+		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+		hlpr->mask.src.u.tcp.port = 0xFFFF;
+		hlpr->mask.dst.protonum = 0xFFFF;
+		hlpr->help = help;
+		hlpr->flags = 0;
+		hlpr->me = THIS_MODULE;
+		hlpr->expect = irc_nat_expected;
+
+		tmpname = &irc_names[i][0];
+		if (ports[i] == IRC_PORT)
+			sprintf(tmpname, "irc");
+		else
+			sprintf(tmpname, "irc-%d", i);
+		hlpr->name = tmpname;
+
+		DEBUGP
+		    ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
+		     ports[i], hlpr->name);
+		ret = ip_nat_helper_register(hlpr);
+
+		if (ret) {
+			printk
+			    ("ip_nat_irc: error registering helper for port %d\n",
+			     ports[i]);
+			fini();
+			return 1;
 		}
+		ports_c++;
 	}
 	return ret;
 }
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_proto_tcp.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_proto_tcp.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_proto_tcp.c	Tue Aug  7 08:30:50 2001
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_proto_tcp.c	Mon Aug 12 16:34:17 2002
@@ -4,7 +4,6 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/if.h>
-
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_proto_unknown.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_proto_unknown.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_proto_unknown.c	Fri Mar 17 10:56:20 2000
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_proto_unknown.c	Mon Aug 12 16:34:17 2002
@@ -1,5 +1,5 @@
 /* The "unknown" protocol.  This is what is used for protocols we
- * don't understand.  It's returned by find_proto().
+ * don't understand.  It's returned by ip_ct_find_proto().
  */
 
 #include <linux/types.h>
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_rule.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_rule.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_rule.c	Mon Aug 12 16:34:17 2002
@@ -106,8 +106,6 @@
 = { { NULL, NULL }, "nat", &nat_initial_table.repl,
     NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
-LIST_HEAD(nat_expect_list);
-
 /* Source NAT */
 static unsigned int ipt_snat_target(struct sk_buff **pskb,
 				    unsigned int hooknum,
@@ -254,19 +252,6 @@
 	return ip_nat_setup_info(conntrack, &mr, hooknum);
 }
 
-static inline int call_expect(const struct ip_nat_expect *i,
-			      struct sk_buff **pskb,
-			      unsigned int hooknum,
-			      struct ip_conntrack *ct,
-			      struct ip_nat_info *info,
-			      struct ip_conntrack *master,
-			      struct ip_nat_info *masterinfo,
-			      unsigned int *verdict)
-{
-	return i->expect(pskb, hooknum, ct, info, master, masterinfo,
-			 verdict);
-}
-
 int ip_nat_rule_find(struct sk_buff **pskb,
 		     unsigned int hooknum,
 		     const struct net_device *in,
@@ -276,19 +261,8 @@
 {
 	int ret;
 
-	/* Master won't vanish while this ctrack still alive */
-	if (ct->master.master) {
-		struct ip_conntrack *master;
-
-		master = (struct ip_conntrack *)ct->master.master;
-		if (LIST_FIND(&nat_expect_list,
-			      call_expect,
-			      struct ip_nat_expect *,
-			      pskb, hooknum, ct, info,
-			      master, &master->nat.info, &ret))
-			return ret;
-	}
 	ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);
+
 	if (ret == NF_ACCEPT) {
 		if (!(info->initialized & (1 << HOOK2MANIP(hooknum))))
 			/* NUL mapping */
@@ -297,22 +271,6 @@
 	return ret;
 }
 
-int ip_nat_expect_register(struct ip_nat_expect *expect)
-{
-	WRITE_LOCK(&ip_nat_lock);
-	list_prepend(&nat_expect_list, expect);
-	WRITE_UNLOCK(&ip_nat_lock);
-
-	return 0;
-}
-
-void ip_nat_expect_unregister(struct ip_nat_expect *expect)
-{
-	WRITE_LOCK(&ip_nat_lock);
-	LIST_DELETE(&nat_expect_list, expect);
-	WRITE_UNLOCK(&ip_nat_lock);
-}
-
 static struct ipt_target ipt_snat_reg
 = { { NULL, NULL }, "SNAT", ipt_snat_target, ipt_snat_checkentry, NULL };
 static struct ipt_target ipt_dnat_reg
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_snmp_basic.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_snmp_basic.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_snmp_basic.c	Tue Oct 30 15:08:12 2001
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_snmp_basic.c	Mon Aug 12 16:34:17 2002
@@ -1243,6 +1243,7 @@
  * NAT helper function, packets arrive here from NAT code.
  */
 static unsigned int nat_help(struct ip_conntrack *ct,
+			     struct ip_conntrack_expect *exp,
                              struct ip_nat_info *info,
                              enum ip_conntrack_info ctinfo,
                              unsigned int hooknum,
@@ -1303,19 +1304,27 @@
 	return NF_DROP;
 }
 
-static struct ip_nat_helper snmp = { { NULL, NULL },
+static struct ip_nat_helper snmp = { 
+	{ NULL, NULL },
+	"snmp",
+	IP_NAT_HELPER_F_STANDALONE,
+	THIS_MODULE,
 	{ { 0, { __constant_htons(SNMP_PORT) } },
 	  { 0, { 0 }, IPPROTO_UDP } },
 	{ { 0, { 0xFFFF } },
 	  { 0, { 0 }, 0xFFFF } },
-	  nat_help, "snmp" };
+	nat_help, NULL };
  
-static struct ip_nat_helper snmp_trap = { { NULL, NULL },
+static struct ip_nat_helper snmp_trap = { 
+	{ NULL, NULL },
+	"snmp_trap",
+	IP_NAT_HELPER_F_STANDALONE,
+	THIS_MODULE,
 	{ { 0, { __constant_htons(SNMP_TRAP_PORT) } },
 	  { 0, { 0 }, IPPROTO_UDP } },
 	{ { 0, { 0xFFFF } },
 	  { 0, { 0 }, 0xFFFF } },
-	nat_help, "snmp_trap" };
+	nat_help, NULL };
 
 /*****************************************************************************
  *
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_nat_standalone.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_nat_standalone.c	Mon Aug 12 16:34:17 2002
@@ -5,7 +5,12 @@
 */
 
 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
-   Public Licence. */
+ * Public Licence.
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ * 	- new API and handling of conntrack/nat helpers
+ * 	- now capable of multiple expectations for one master
+ * */
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -44,6 +49,15 @@
 			         : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN"  \
 				    : "*ERROR*")))
 
+static inline int call_expect(struct ip_conntrack *master,
+			      struct sk_buff **pskb,
+			      unsigned int hooknum,
+			      struct ip_conntrack *ct,
+			      struct ip_nat_info *info)
+{
+	return master->nat.info.helper->expect(pskb, hooknum, ct, info);
+}
+
 static unsigned int
 ip_nat_fn(unsigned int hooknum,
 	  struct sk_buff **pskb,
@@ -110,8 +124,16 @@
 			int in_hashes = info->initialized;
 			unsigned int ret;
 
-			ret = ip_nat_rule_find(pskb, hooknum, in, out,
-					       ct, info);
+			if (ct->master
+			    && master_ct(ct)->nat.info.helper
+			    && master_ct(ct)->nat.info.helper->expect) {
+				ret = call_expect(master_ct(ct), pskb, 
+						  hooknum, ct, info);
+			} else {
+				ret = ip_nat_rule_find(pskb, hooknum, in, out,
+						       ct, info);
+			}
+
 			if (ret != NF_ACCEPT) {
 				WRITE_UNLOCK(&ip_nat_lock);
 				return ret;
@@ -334,11 +356,7 @@
 EXPORT_SYMBOL(ip_nat_protocol_unregister);
 EXPORT_SYMBOL(ip_nat_helper_register);
 EXPORT_SYMBOL(ip_nat_helper_unregister);
-EXPORT_SYMBOL(ip_nat_expect_register);
-EXPORT_SYMBOL(ip_nat_expect_unregister);
 EXPORT_SYMBOL(ip_nat_cheat_check);
 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
-EXPORT_SYMBOL(ip_nat_seq_adjust);
-EXPORT_SYMBOL(ip_nat_delete_sack);
 EXPORT_SYMBOL(ip_nat_used_tuple);
 MODULE_LICENSE("GPL");
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ip_tables.c linux-2.4.20-pre2/net/ipv4/netfilter/ip_tables.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ip_tables.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ip_tables.c	Mon Aug 12 16:34:17 2002
@@ -9,6 +9,7 @@
  * 	  a table
  */
 #include <linux/config.h>
+#include <linux/cache.h>
 #include <linux/skbuff.h>
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
@@ -97,7 +98,7 @@
 	unsigned int underflow[NF_IP_NUMHOOKS];
 
 	/* ipt_entry tables: one per CPU */
-	char entries[0] __attribute__((aligned(SMP_CACHE_BYTES)));
+	char entries[0] ____cacheline_aligned;
 };
 
 static LIST_HEAD(ipt_target);
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_DSCP.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_DSCP.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_DSCP.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_DSCP.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,108 @@
+/* iptables module for setting the IPv4 DSCP field, Version 1.8
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * See RFC2474 for a description of the DSCP field within the IP Header.
+ *
+ * ipt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp
+*/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_DSCP.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables DSCP modification module");
+MODULE_LICENSE("GPL");
+
+static unsigned int
+target(struct sk_buff **pskb,
+       unsigned int hooknum,
+       const struct net_device *in,
+       const struct net_device *out,
+       const void *targinfo,
+       void *userinfo)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	const struct ipt_DSCP_info *dinfo = targinfo;
+	u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
+
+
+	if ((iph->tos & IPT_DSCP_MASK) != sh_dscp) {
+		u_int16_t diffs[2];
+
+		/* raw socket (tcpdump) may have clone of incoming
+		 * skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb)
+				return NF_DROP;
+			kfree_skb(*pskb);
+			*pskb = nskb;
+			iph = (*pskb)->nh.iph;
+		}
+
+		diffs[0] = htons(iph->tos) ^ 0xFFFF;
+		iph->tos = (iph->tos & ~IPT_DSCP_MASK) | sh_dscp;
+		diffs[1] = htons(iph->tos);
+		iph->check = csum_fold(csum_partial((char *)diffs,
+		                                    sizeof(diffs),
+		                                    iph->check^0xFFFF));
+		(*pskb)->nfcache |= NFC_ALTERED;
+	}
+	return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+	   const struct ipt_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+	const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) {
+		printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IPT_ALIGN(sizeof(struct ipt_DSCP_info)));
+		return 0;
+	}
+
+	if (strcmp(tablename, "mangle") != 0) {
+		printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+		return 0;
+	}
+
+	if ((dscp > IPT_DSCP_MAX)) {
+		printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_dscp_reg
+= { { NULL, NULL }, "DSCP", target, checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	if (ipt_register_target(&ipt_dscp_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_dscp_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_ECN.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_ECN.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_ECN.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_ECN.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,183 @@
+/* iptables module for the IPv4 and TCP ECN bits, Version 1.2
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ * 
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+ * ipt_ECN.c,v 1.4 2002/08/05 19:36:51 laforge Exp
+*/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ECN.h>
+
+MODULE_LICENSE("GPL");
+
+/* set ECT codepoint from IP header.
+ * 	return 0 in case there was no ECT codepoint
+ * 	return 1 in case ECT codepoint has been overwritten
+ * 	return < 0 in case there was error */
+static int inline
+set_ect_ip(struct sk_buff **pskb, struct iphdr *iph,
+	   const struct ipt_ECN_info *einfo)
+{
+	if ((iph->tos & IPT_ECN_IP_MASK)
+	    != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
+		u_int16_t diffs[2];
+
+		/* raw socket (tcpdump) may have clone of incoming
+		 * skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb)
+				return NF_DROP;
+			kfree_skb(*pskb);
+			*pskb = nskb;
+			iph = (*pskb)->nh.iph;
+		}
+
+		diffs[0] = htons(iph->tos) ^ 0xFFFF;
+		iph->tos = iph->tos & ~IPT_ECN_IP_MASK;
+		iph->tos = iph->tos | (einfo->ip_ect & IPT_ECN_IP_MASK);
+		diffs[1] = htons(iph->tos);
+		iph->check = csum_fold(csum_partial((char *)diffs,
+		                                    sizeof(diffs),
+		                                    iph->check^0xFFFF));
+		(*pskb)->nfcache |= NFC_ALTERED;
+
+		return 1;
+	} 
+	return 0;
+}
+
+static int inline
+set_ect_tcp(struct sk_buff **pskb, struct iphdr *iph,
+	    const struct ipt_ECN_info *einfo)
+{
+
+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
+	u_int16_t *tcpflags = (u_int16_t *)tcph + 6;
+	u_int16_t diffs[2];
+
+	/* raw socket (tcpdump) may have clone of incoming
+	 * skb: don't disturb it --RR */
+	if (skb_cloned(*pskb) && !(*pskb)->sk) {
+		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+		if (!nskb)
+			return NF_DROP;
+		kfree_skb(*pskb);
+		*pskb = nskb;
+		iph = (*pskb)->nh.iph;
+	}
+
+	diffs[0] = *tcpflags;
+
+	if (einfo->operation & IPT_ECN_OP_SET_ECE
+	    && tcph->ece != einfo->proto.tcp.ece) {
+		tcph->ece = einfo->proto.tcp.ece;
+	}
+
+	if (einfo->operation & IPT_ECN_OP_SET_CWR
+	    && tcph->cwr != einfo->proto.tcp.cwr) {
+		tcph->cwr = einfo->proto.tcp.cwr;
+	}
+	
+	if (diffs[0] != *tcpflags) {
+		diffs[0] = htons(diffs[0]) ^ 0xFFFF;
+		diffs[1] = htons(*tcpflags);
+		tcph->check = csum_fold(csum_partial((char *)diffs,
+		                                    sizeof(diffs),
+		                                    tcph->check^0xFFFF));
+		(*pskb)->nfcache |= NFC_ALTERED;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static unsigned int
+target(struct sk_buff **pskb,
+       unsigned int hooknum,
+       const struct net_device *in,
+       const struct net_device *out,
+       const void *targinfo,
+       void *userinfo)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	const struct ipt_ECN_info *einfo = targinfo;
+
+	if (einfo->operation & IPT_ECN_OP_SET_IP)
+		set_ect_ip(pskb, iph, einfo);
+
+	if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
+	    && iph->protocol == IPPROTO_TCP)
+		set_ect_tcp(pskb, iph, einfo);
+
+	return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+	   const struct ipt_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+	const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
+		printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       IPT_ALIGN(sizeof(struct ipt_ECN_info)));
+		return 0;
+	}
+
+	if (strcmp(tablename, "mangle") != 0) {
+		printk(KERN_WARNING "ECN: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+		return 0;
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MASK) {
+		printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
+			einfo->operation);
+		return 0;
+	}
+	if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
+		printk(KERN_WARNING "ECN: new ECT codepoint %x out of mask\n",
+			einfo->ip_ect);
+		return 0;
+	}
+
+	if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
+	    && e->ip.proto != IPPROTO_TCP) {
+		printk(KERN_WARNING "ECN: cannot use TCP operations on a "
+		       "non-tcp rule\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_ecn_reg
+= { { NULL, NULL }, "ECN", target, checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	if (ipt_register_target(&ipt_ecn_reg))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_ecn_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_REJECT.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_REJECT.c	Mon Aug 12 16:34:17 2002
@@ -75,6 +75,7 @@
 #ifdef CONFIG_NETFILTER_DEBUG
 	nskb->nf_debug = 0;
 #endif
+	nskb->nfmark = 0;
 
 	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
 
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_ah.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_ah.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_ah.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_ah.c	Mon Aug 12 16:34:17 2002
@@ -91,12 +91,12 @@
 static struct ipt_match ah_match
 = { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
 
-int __init init(void)
+static int __init init(void)
 {
 	return ipt_register_match(&ah_match);
 }
 
-void __exit cleanup(void)
+static void __exit cleanup(void)
 {
 	ipt_unregister_match(&ah_match);
 }
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_conntrack.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_conntrack.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_conntrack.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_conntrack.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,123 @@
+/* Kernel module to match connection tracking information.
+ * Superset of Rusty's minimalistic state match.
+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_conntrack.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ipt_conntrack_info *sinfo = matchinfo;
+	struct ip_conntrack *ct;
+	enum ip_conntrack_info ctinfo;
+	unsigned int statebit;
+
+	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+
+#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
+
+	statebit = ct ? IPT_CONNTRACK_STATE_INVALID : IPT_CONNTRACK_STATE_BIT(ctinfo);
+	if(sinfo->flags & IPT_CONNTRACK_STATE) {
+		if (ct) {
+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
+				statebit |= IPT_CONNTRACK_STATE_SNAT;
+
+			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
+			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
+				statebit |= IPT_CONNTRACK_STATE_DNAT;
+		}
+
+		if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_PROTO) {
+		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
+                	return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_STATUS) {
+		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
+			return 0;
+	}
+
+	if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
+		unsigned long expires;
+
+		if(!ct)
+			return 0;
+
+		expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
+
+		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int check(const char *tablename,
+		 const struct ipt_ip *ip,
+		 void *matchinfo,
+		 unsigned int matchsize,
+		 unsigned int hook_mask)
+{
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match conntrack_match
+= { { NULL, NULL }, "conntrack", &match, &check, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	/* NULL if ip_conntrack not a module */
+	if (ip_conntrack_module)
+		__MOD_INC_USE_COUNT(ip_conntrack_module);
+	return ipt_register_match(&conntrack_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&conntrack_match);
+	if (ip_conntrack_module)
+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_dscp.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_dscp.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_dscp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_dscp.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,58 @@
+/* IP tables module for matching the value of the IPv4 DSCP field
+ *
+ * ipt_dscp.c,v 1.3 2002/08/05 19:00:21 laforge Exp
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under the terms  GNU GPL
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_dscp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables DSCP matching module");
+MODULE_LICENSE("GPL");
+
+static int match(const struct sk_buff *skb, const struct net_device *in,
+		 const struct net_device *out, const void *matchinfo,
+		 int offset, const void *hdr, u_int16_t datalen,
+		 int *hotdrop)
+{
+	const struct ipt_dscp_info *info = matchinfo;
+	const struct iphdr *iph = skb->nh.iph;
+
+	u_int8_t sh_dscp = ((info->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
+
+	return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
+}
+
+static int checkentry(const char *tablename, const struct ipt_ip *ip,
+		      void *matchinfo, unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_dscp_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match dscp_match = { { NULL, NULL }, "dscp", &match,
+		&checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&dscp_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&dscp_match);
+
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_ecn.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_ecn.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_ecn.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_ecn.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,118 @@
+/* IP tables module for matching the value of the IPv4 and TCP ECN bits
+ *
+ * ipt_ecn.c,v 1.3 2002/05/29 15:09:00 laforge Exp
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This software is distributed under the terms GNU GPL v2
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ecn.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables ECN matching module");
+MODULE_LICENSE("GPL");
+
+static inline int match_ip(const struct sk_buff *skb,
+			   const struct iphdr *iph,
+			   const struct ipt_ecn_info *einfo)
+{
+	return ((iph->tos&IPT_ECN_IP_MASK) == einfo->ip_ect);
+}
+
+static inline int match_tcp(const struct sk_buff *skb,
+			    const struct iphdr *iph,
+			    const struct ipt_ecn_info *einfo)
+{
+	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
+			if (tcph->ece == 1)
+				return 0;
+		} else {
+			if (tcph->ece == 0)
+				return 0;
+		}
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
+			if (tcph->cwr == 1)
+				return 0;
+		} else {
+			if (tcph->cwr == 0)
+				return 0;
+		}
+	}
+
+	return 1;
+}
+
+static int match(const struct sk_buff *skb, const struct net_device *in,
+		 const struct net_device *out, const void *matchinfo,
+		 int offset, const void *hdr, u_int16_t datalen,
+		 int *hotdrop)
+{
+	const struct ipt_ecn_info *info = matchinfo;
+	const struct iphdr *iph = skb->nh.iph;
+
+	if (info->operation & IPT_ECN_OP_MATCH_IP)
+		if (!match_ip(skb, iph, info))
+			return 0;
+
+	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
+		if (iph->protocol != IPPROTO_TCP)
+			return 0;
+		if (!match_tcp(skb, iph, info))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int checkentry(const char *tablename, const struct ipt_ip *ip,
+		      void *matchinfo, unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	const struct ipt_ecn_info *info = matchinfo;
+
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
+		return 0;
+
+	if (info->operation & IPT_ECN_OP_MATCH_MASK)
+		return 0;
+
+	if (info->invert & IPT_ECN_OP_MATCH_MASK)
+		return 0;
+
+	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
+	    && ip->proto != IPPROTO_TCP) {
+		printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
+		       " non-tcp packets\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match ecn_match = { { NULL, NULL }, "ecn", &match,
+		&checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&ecn_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&ecn_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_helper.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_helper.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_helper.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_helper.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,112 @@
+/*
+ * iptables module to match on related connections
+ *   (c) 2001 Martin Josefsson <gandalf@wlug.westbo.se>
+ *
+ * Released under the terms of GNU GPLv2.
+ *
+ *   19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
+ *   		 - Port to newnat infrastructure
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_helper.h>
+
+MODULE_LICENSE("GPL");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ipt_helper_info *info = matchinfo;
+	struct ip_conntrack_expect *exp;
+	struct ip_conntrack *ct;
+	enum ip_conntrack_info ctinfo;
+	
+	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+	if (!ct) {
+		DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
+		return 0;
+	}
+
+	if (!ct->master) {
+		DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
+		return 0;
+	}
+
+	exp = ct->master;
+	if (!exp->expectant) {
+		DEBUGP("ipt_helper: expectation %p without expectant !?!\n", 
+			exp);
+		return 0;
+	}
+
+	if (!exp->expectant->helper) {
+		DEBUGP("ipt_helper: master ct %p has no helper\n", 
+			exp->expectant);
+		return 0;
+	}
+
+	DEBUGP("master's name = %s , info->name = %s\n", 
+		exp->expectant->helper->name, info->name);
+
+	return !strncmp(exp->expectant->helper->name, info->name, 
+			strlen(exp->expectant->helper->name)) ^ info->invert;
+}
+
+static int check(const char *tablename,
+		 const struct ipt_ip *ip,
+		 void *matchinfo,
+		 unsigned int matchsize,
+		 unsigned int hook_mask)
+{
+	struct ipt_helper_info *info = matchinfo;
+
+	info->name[29] = '\0';
+
+	/* verify size */
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_helper_info)))
+		return 0;
+
+	/* verify that we actually should match anything */
+	if ( strlen(info->name) == 0 )
+		return 0;
+	
+	return 1;
+}
+
+static struct ipt_match helper_match
+= { { NULL, NULL }, "helper", &match, &check, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	/* NULL if ip_conntrack not a module */
+	if (ip_conntrack_module)
+		__MOD_INC_USE_COUNT(ip_conntrack_module);
+	return ipt_register_match(&helper_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&helper_match);
+	if (ip_conntrack_module)
+		__MOD_DEC_USE_COUNT(ip_conntrack_module);
+}
+
+module_init(init);
+module_exit(fini);
+
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_owner.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_owner.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_owner.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_owner.c	Mon Aug 12 16:34:17 2002
@@ -12,6 +12,38 @@
 #include <linux/netfilter_ipv4/ip_tables.h>
 
 static int
+match_comm(const struct sk_buff *skb, const char *comm)
+{
+	struct task_struct *p;
+	struct files_struct *files;
+	int i;
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if(strncmp(p->comm, comm, sizeof(p->comm)))
+			continue;
+
+		task_lock(p);
+		files = p->files;
+		if(files) {
+			read_lock(&files->file_lock);
+			for (i=0; i < files->max_fds; i++) {
+				if (fcheck_files(files, i) == skb->sk->socket->file) {
+					read_unlock(&files->file_lock);
+					task_unlock(p);
+					read_unlock(&tasklist_lock);
+					return 1;
+				}
+			}
+			read_unlock(&files->file_lock);
+		}
+		task_unlock(p);
+	}
+	read_unlock(&tasklist_lock);
+	return 0;
+}
+
+static int
 match_pid(const struct sk_buff *skb, pid_t pid)
 {
 	struct task_struct *p;
@@ -115,6 +147,12 @@
 			return 0;
 	}
 
+	if(info->match & IPT_OWNER_COMM) {
+		if (!match_comm(skb, info->comm) ^
+		    !!(info->invert & IPT_OWNER_COMM))
+			return 0;
+	}
+
 	return 1;
 }
 
diff -urN linux-2.4.20-pre1/net/ipv4/netfilter/ipt_pkttype.c linux-2.4.20-pre2/net/ipv4/netfilter/ipt_pkttype.c
--- linux-2.4.20-pre1/net/ipv4/netfilter/ipt_pkttype.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/net/ipv4/netfilter/ipt_pkttype.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,59 @@
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+
+#include <linux/netfilter_ipv4/ipt_pkttype.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+MODULE_LICENSE("GPL");
+
+static int match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+    const struct ipt_pkttype_info *info = matchinfo;
+
+    return (skb->pkt_type == info->pkttype) ^ info->invert;
+}
+
+static int checkentry(const char *tablename,
+		   const struct ipt_ip *ip,
+		   void *matchinfo,
+		   unsigned int matchsize,
+		   unsigned int hook_mask)
+{
+/*
+	if (hook_mask
+	    & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
+		| (1 << NF_IP_FORWARD))) {
+		printk("ipt_pkttype: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
+		return 0;
+	}
+*/
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_pkttype_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match pkttype_match
+= { { NULL, NULL }, "pkttype", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&pkttype_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&pkttype_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.20-pre1/net/ipv4/tcp.c linux-2.4.20-pre2/net/ipv4/tcp.c
--- linux-2.4.20-pre1/net/ipv4/tcp.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv4/tcp.c	Mon Aug 12 16:34:17 2002
@@ -1508,7 +1508,7 @@
 			break;
 
 		/* We need to check signals first, to get correct SIGURG
-		 * handling. FIXME: Need to check this doesnt impact 1003.1g
+		 * handling. FIXME: Need to check this doesn't impact 1003.1g
 		 * and move it down to the bottom of the loop
 		 */
 		if (signal_pending(current)) {
diff -urN linux-2.4.20-pre1/net/ipv6/netfilter/Config.in linux-2.4.20-pre2/net/ipv6/netfilter/Config.in
--- linux-2.4.20-pre1/net/ipv6/netfilter/Config.in	Mon Feb 25 11:38:14 2002
+++ linux-2.4.20-pre2/net/ipv6/netfilter/Config.in	Mon Aug 12 16:34:17 2002
@@ -24,6 +24,10 @@
   fi
 #  dep_tristate '  MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
   dep_tristate '  netfilter MARK match support' CONFIG_IP6_NF_MATCH_MARK $CONFIG_IP6_NF_IPTABLES
+  dep_tristate '  Packet Length match support' CONFIG_IP6_NF_MATCH_LENGTH $CONFIG_IP6_NF_IPTABLES
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  EUI64 address check (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_EUI64 $CONFIG_IP6_NF_IPTABLES
+  fi
 #  dep_tristate '  Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES
 #  dep_tristate '  TOS match support' CONFIG_IP6_NF_MATCH_TOS $CONFIG_IP6_NF_IPTABLES
 #  if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
diff -urN linux-2.4.20-pre1/net/ipv6/netfilter/Makefile linux-2.4.20-pre2/net/ipv6/netfilter/Makefile
--- linux-2.4.20-pre1/net/ipv6/netfilter/Makefile	Mon Feb 25 11:38:14 2002
+++ linux-2.4.20-pre2/net/ipv6/netfilter/Makefile	Mon Aug 12 16:34:17 2002
@@ -15,7 +15,9 @@
 obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
 obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
+obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
+obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
diff -urN linux-2.4.20-pre1/net/ipv6/netfilter/ip6_tables.c linux-2.4.20-pre2/net/ipv6/netfilter/ip6_tables.c
--- linux-2.4.20-pre1/net/ipv6/netfilter/ip6_tables.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/ipv6/netfilter/ip6_tables.c	Mon Aug 12 16:34:17 2002
@@ -743,7 +743,7 @@
 	t = ip6t_get_target(e);
 	target = find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
 	if (!target) {
-	  //		duprintf("check_entry: `%s' not found\n", t->u.name);
+		duprintf("check_entry: `%s' not found\n", t->u.user.name);
 		goto cleanup_matches;
 	}
 	if (target->me)
diff -urN linux-2.4.20-pre1/net/ipv6/netfilter/ip6t_eui64.c linux-2.4.20-pre2/net/ipv6/netfilter/ip6t_eui64.c
--- linux-2.4.20-pre1/net/ipv6/netfilter/ip6t_eui64.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/net/ipv6/netfilter/ip6t_eui64.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,89 @@
+/* Kernel module to match EUI64 address parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/if_ether.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+
+    unsigned char eui64[8];
+    int i=0;
+
+     if ( !(skb->mac.raw >= skb->head
+                && (skb->mac.raw + ETH_HLEN) <= skb->data)
+                && offset != 0) {
+                        *hotdrop = 1;
+                        return 0;
+                }
+    
+    memset(eui64, 0, sizeof(eui64));
+
+    if (skb->mac.ethernet->h_proto == ntohs(ETH_P_IPV6)) {
+      if (skb->nh.ipv6h->version == 0x6) { 
+         memcpy(eui64, skb->mac.ethernet->h_source, 3);
+         memcpy(eui64 + 5, skb->mac.ethernet->h_source + 3, 3);
+	 eui64[3]=0xff;
+	 eui64[4]=0xfe;
+	 eui64[0] |= 0x02;
+
+	 i=0;
+	 while ((skb->nh.ipv6h->saddr.in6_u.u6_addr8[8+i] ==
+			 eui64[i]) && (i<8)) i++;
+
+	 if ( i == 8 )
+	 	return 1;
+      }
+    }
+
+    return 0;
+}
+
+static int
+ip6t_eui64_checkentry(const char *tablename,
+		   const struct ip6t_ip6 *ip,
+		   void *matchinfo,
+		   unsigned int matchsize,
+		   unsigned int hook_mask)
+{
+	if (hook_mask
+	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
+		(1 << NF_IP6_PRE_ROUTING) )) {
+		printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
+		return 0;
+	}
+
+	if (matchsize != IP6T_ALIGN(sizeof(int)))
+		return 0;
+
+	return 1;
+}
+
+static struct ip6t_match eui64_match
+= { { NULL, NULL }, "eui64", &match, &ip6t_eui64_checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&eui64_match);
+}
+
+static void __exit fini(void)
+{
+	ip6t_unregister_match(&eui64_match);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_DESCRIPTION("IPv6 EUI64 address checking match");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
diff -urN linux-2.4.20-pre1/net/ipv6/netfilter/ip6t_length.c linux-2.4.20-pre2/net/ipv6/netfilter/ip6t_length.c
--- linux-2.4.20-pre1/net/ipv6/netfilter/ip6t_length.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-pre2/net/ipv6/netfilter/ip6t_length.c	Mon Aug 12 16:34:17 2002
@@ -0,0 +1,51 @@
+/* Length Match - IPv6 Port */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv6/ip6t_length.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ip6t_length_info *info = matchinfo;
+	u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
+	
+	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
+}
+
+static int
+checkentry(const char *tablename,
+           const struct ip6t_ip6 *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_length_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ip6t_match length_match
+= { { NULL, NULL }, "length", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&length_match);
+}
+
+static void __exit fini(void)
+{
+	ip6t_unregister_match(&length_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.20-pre1/net/irda/af_irda.c linux-2.4.20-pre2/net/irda/af_irda.c
--- linux-2.4.20-pre1/net/irda/af_irda.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/irda/af_irda.c	Mon Aug 12 16:34:17 2002
@@ -414,6 +414,7 @@
  * hint bits), and then wake up any process waiting for answer...
  */
 static void irda_selective_discovery_indication(discovery_t *discovery,
+						DISCOVERY_MODE mode,
 						void *priv)
 {
 	struct irda_sock *self;
@@ -1290,6 +1291,9 @@
 		/* Check if we are still connected */
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
+		/* Handle signals */
+		if (signal_pending(current)) 
+			return -ERESTARTSYS;
 	}
 
 	/* Check that we don't send out to big frames */
diff -urN linux-2.4.20-pre1/net/irda/ircomm/ircomm_tty.c linux-2.4.20-pre2/net/irda/ircomm/ircomm_tty.c
--- linux-2.4.20-pre1/net/irda/ircomm/ircomm_tty.c	Sun Sep 30 12:26:09 2001
+++ linux-2.4.20-pre2/net/irda/ircomm/ircomm_tty.c	Mon Aug 12 16:34:17 2002
@@ -417,7 +417,7 @@
 		self->line = line;
 		self->tqueue.routine = ircomm_tty_do_softint;
 		self->tqueue.data = self;
-		self->max_header_size = 5;
+		self->max_header_size = IRCOMM_TTY_HDR_UNITIALISED;
 		self->max_data_size = 64-self->max_header_size;
 		self->close_delay = 5*HZ/10;
 		self->closing_wait = 30*HZ;
@@ -696,6 +696,20 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
+	/* We may receive packets from the TTY even before we have finished
+	 * our setup. Not cool.
+	 * The problem is that we would allocate a skb with bogus header and
+	 * data size, and when adding data to it later we would get
+	 * confused.
+	 * Better to not accept data until we are properly setup. Use bogus
+	 * header size to check that (safest way to detect it).
+	 * Jean II */
+	if (self->max_header_size == IRCOMM_TTY_HDR_UNITIALISED) {
+		/* TTY will retry */
+		IRDA_DEBUG(2, __FUNCTION__ "() : not initialised\n");
+		return len;
+	}
+
 	save_flags(flags);
 	cli();
 
@@ -792,8 +806,12 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
-	/* Check if we are allowed to transmit any data */
-	if (tty->hw_stopped)
+	/* Check if we are allowed to transmit any data.
+	 * hw_stopped is the regular flow control.
+	 * max_header_size tells us if the channel is initialised or not.
+	 * Jean II */
+	if ((tty->hw_stopped) ||
+	    (self->max_header_size == IRCOMM_TTY_HDR_UNITIALISED))
 		ret = 0;
 	else {
 		save_flags(flags);
diff -urN linux-2.4.20-pre1/net/irda/ircomm/ircomm_tty_attach.c linux-2.4.20-pre2/net/irda/ircomm/ircomm_tty_attach.c
--- linux-2.4.20-pre1/net/irda/ircomm/ircomm_tty_attach.c	Wed Jul 25 14:12:03 2001
+++ linux-2.4.20-pre2/net/irda/ircomm/ircomm_tty_attach.c	Mon Aug 12 16:34:17 2002
@@ -47,6 +47,7 @@
 
 static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
 static void ircomm_tty_discovery_indication(discovery_t *discovery,
+					    DISCOVERY_MODE mode,
 					    void *priv);
 static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
 					struct ias_value *value, void *priv);
@@ -305,6 +306,7 @@
  *
  */
 static void ircomm_tty_discovery_indication(discovery_t *discovery,
+					    DISCOVERY_MODE mode,
 					    void *priv)
 {
 	struct ircomm_tty_cb *self;
@@ -312,6 +314,20 @@
 
 	IRDA_DEBUG(2, __FUNCTION__"()\n");
 
+	/* Important note :
+	 * We need to drop all passive discoveries.
+	 * The LSAP management of IrComm is deficient and doesn't deal
+	 * with the case of two instance connecting to each other
+	 * simultaneously (it will deadlock in LMP).
+	 * The proper fix would be to use the same technique as in IrNET,
+	 * to have one server socket and separate instances for the
+	 * connecting/connected socket.
+	 * The workaround is to drop passive discovery, which drastically
+	 * reduce the probability of this happening.
+	 * Jean II */
+	if(mode == DISCOVERY_PASSIVE)
+		return;
+
 	info.daddr = discovery->daddr;
 	info.saddr = discovery->saddr;
 
diff -urN linux-2.4.20-pre1/net/irda/ircomm/ircomm_tty_ioctl.c linux-2.4.20-pre2/net/irda/ircomm/ircomm_tty_ioctl.c
--- linux-2.4.20-pre1/net/irda/ircomm/ircomm_tty_ioctl.c	Wed Jul  4 11:50:38 2001
+++ linux-2.4.20-pre2/net/irda/ircomm/ircomm_tty_ioctl.c	Mon Aug 12 16:34:17 2002
@@ -94,6 +94,9 @@
 	if (cflag & CRTSCTS) {
 		self->flags |= ASYNC_CTS_FLOW;
 		self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
+		/* This got me. Bummer. Jean II */
+		if (self->service_type == IRCOMM_3_WIRE_RAW)
+			WARNING(__FUNCTION__ "(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n");
 	} else {
 		self->flags &= ~ASYNC_CTS_FLOW;
 		self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
diff -urN linux-2.4.20-pre1/net/irda/irlan/irlan_client.c linux-2.4.20-pre2/net/irda/irlan/irlan_client.c
--- linux-2.4.20-pre1/net/irda/irlan/irlan_client.c	Thu Feb  8 13:08:38 2001
+++ linux-2.4.20-pre2/net/irda/irlan/irlan_client.c	Mon Aug 12 16:34:17 2002
@@ -145,7 +145,9 @@
  *    Remote device with IrLAN server support discovered
  *
  */
-void irlan_client_discovery_indication(discovery_t *discovery, void *priv) 
+void irlan_client_discovery_indication(discovery_t *discovery,
+				       DISCOVERY_MODE mode,
+				       void *priv) 
 {
 	struct irlan_cb *self;
 	__u32 saddr, daddr;
@@ -155,6 +157,15 @@
 	ASSERT(irlan != NULL, return;);
 	ASSERT(discovery != NULL, return;);
 
+	/*
+	 * I didn't check it, but I bet that IrLAN suffer from the same
+	 * deficiency as IrComm and doesn't handle two instances
+	 * simultaneously connecting to each other.
+	 * Same workaround, drop passive discoveries.
+	 * Jean II */
+	if(mode == DISCOVERY_PASSIVE)
+		return;
+
 	saddr = discovery->saddr;
 	daddr = discovery->daddr;
 
diff -urN linux-2.4.20-pre1/net/irda/irlap_event.c linux-2.4.20-pre2/net/irda/irlap_event.c
--- linux-2.4.20-pre1/net/irda/irlap_event.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/irda/irlap_event.c	Mon Aug 12 16:34:17 2002
@@ -174,6 +174,12 @@
 	irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
 }
 
+/*
+ * Calculate and set time before we will have to send back the pf bit
+ * to the peer. Use in primary.
+ * Make sure that state is XMIT_P/XMIT_S when calling this function
+ * (and that nobody messed up with the state). - Jean II
+ */
 void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
 {
 	ASSERT(self != NULL, return;);
@@ -1163,15 +1169,26 @@
 				self->ack_required = TRUE;
 			
 				irlap_wait_min_turn_around(self, &self->qos_tx);
-				/* 
-				 * Important to switch state before calling
-				 * upper layers
-				 */
-				irlap_next_state(self, LAP_XMIT_P);
 
+				/* Call higher layer *before* changing state
+				 * to give them a chance to send data in the
+				 * next LAP frame.
+				 * Jean II */
 				irlap_data_indication(self, skb, FALSE);
 
-				/* This is the last frame */
+				/* XMIT states are the most dangerous state
+				 * to be in, because user requests are
+				 * processed directly and may change state.
+				 * On the other hand, in NDM_P, those
+				 * requests are queued and we will process
+				 * them when we return to irlap_do_event().
+				 * Jean II
+				 */
+				irlap_next_state(self, LAP_XMIT_P);
+
+				/* This is the last frame.
+				 * Make sure it's always called in XMIT state.
+				 * - Jean II */
 				irlap_start_poll_timer(self, self->poll_timeout);
 			}
 			break;
@@ -1309,6 +1326,7 @@
 		} else {
 			del_timer(&self->final_timer);
 			irlap_data_indication(self, skb, TRUE);
+			irlap_next_state(self, LAP_XMIT_P);
 			printk(__FUNCTION__ "(): RECV_UI_FRAME: next state %s\n", irlap_state[self->state]);
 			irlap_start_poll_timer(self, self->poll_timeout);
 		}
diff -urN linux-2.4.20-pre1/net/irda/irlmp.c linux-2.4.20-pre2/net/irda/irlmp.c
--- linux-2.4.20-pre1/net/irda/irlmp.c	Fri Dec 21 09:42:06 2001
+++ linux-2.4.20-pre2/net/irda/irlmp.c	Mon Aug 12 16:34:17 2002
@@ -732,7 +732,9 @@
 	 * On links which are connected, we can't do discovery
 	 * anymore and can't refresh the log, so we freeze the
 	 * discovery log to keep info about the device we are
-	 * connected to. - Jean II
+	 * connected to.
+	 * This info is mandatory if we want irlmp_connect_request()
+	 * to work properly. - Jean II
 	 */
 	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
 	while (lap != NULL) {
@@ -804,7 +806,7 @@
 void irlmp_discovery_request(int nslots)
 {
 	/* Return current cached discovery log */
-	irlmp_discovery_confirm(irlmp->cachelog);
+	irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG);
 
 	/* 
 	 * Start a single discovery operation if discovery is not already
@@ -907,7 +909,8 @@
  * partial/selective discovery based on the hints that it passed to IrLMP.
  */
 static inline void
-irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
+irlmp_notify_client(irlmp_client_t *client,
+		    hashbin_t *log, DISCOVERY_MODE mode)
 {
 	discovery_t *discovery;
 
@@ -930,7 +933,7 @@
 		 * bits ;-)
 		 */
 		if (client->hint_mask & discovery->hints.word & 0x7f7f)
-			client->disco_callback(discovery, client->priv);
+			client->disco_callback(discovery, mode, client->priv);
 
 		discovery = (discovery_t *) hashbin_get_next(log);
 	}
@@ -943,7 +946,7 @@
  *    device it is, and give indication to the client(s)
  * 
  */
-void irlmp_discovery_confirm(hashbin_t *log) 
+void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode) 
 {
 	irlmp_client_t *client;
 	
@@ -957,7 +960,7 @@
 	client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
 	while (client != NULL) {
 		/* Check if we should notify client */
-		irlmp_notify_client(client, log);
+		irlmp_notify_client(client, log, mode);
 			
 		client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
 	}
@@ -987,7 +990,8 @@
 		/* Check if we should notify client */
 		if ((client->expir_callback) &&
 		    (client->hint_mask & expiry->hints.word & 0x7f7f))
-			client->expir_callback(expiry, client->priv);
+			client->expir_callback(expiry, EXPIRY_TIMEOUT,
+					       client->priv);
 
 		/* Next client */
 		client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
diff -urN linux-2.4.20-pre1/net/irda/irlmp_event.c linux-2.4.20-pre2/net/irda/irlmp_event.c
--- linux-2.4.20-pre1/net/irda/irlmp_event.c	Mon Feb 25 11:38:14 2002
+++ linux-2.4.20-pre2/net/irda/irlmp_event.c	Mon Aug 12 16:34:17 2002
@@ -459,6 +459,15 @@
 					    LM_LAP_DISCONNECT_INDICATION,
 					    NULL);
 		}
+
+		/* Force an expiry of the discovery log.
+		 * Now that the LAP is free, the system may attempt to
+		 * connect to another device. Unfortunately, our entries
+		 * are stale. There is a small window (<3s) before the
+		 * normal discovery will run and where irlmp_connect_request()
+		 * can get the wrong info, so make sure things get
+		 * cleaned *NOW* ;-) - Jean II */
+		irlmp_do_expiry();
 		break;
 	default:
 		IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
diff -urN linux-2.4.20-pre1/net/irda/irlmp_frame.c linux-2.4.20-pre2/net/irda/irlmp_frame.c
--- linux-2.4.20-pre1/net/irda/irlmp_frame.c	Fri Nov  9 14:22:17 2001
+++ linux-2.4.20-pre2/net/irda/irlmp_frame.c	Mon Aug 12 16:34:17 2002
@@ -378,7 +378,7 @@
 	
 	/* Just handle it the same way as a discovery confirm,
 	 * bypass the LM_LAP state machine (see below) */
-	irlmp_discovery_confirm(irlmp->cachelog);
+	irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_PASSIVE);
 }
 
 /*
@@ -404,7 +404,7 @@
 	 *	2) It doesn't affect the LM_LAP state
 	 *	3) Faster, slimer, simpler, ...
 	 * Jean II */
-	irlmp_discovery_confirm(irlmp->cachelog);
+	irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_ACTIVE);
 }
 
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
diff -urN linux-2.4.20-pre1/net/irda/irnet/irnet.h linux-2.4.20-pre2/net/irda/irnet/irnet.h
--- linux-2.4.20-pre1/net/irda/irnet/irnet.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/irda/irnet/irnet.h	Mon Aug 12 16:34:17 2002
@@ -211,6 +211,12 @@
  *	o When receiving a disconnect indication, don't reenable the
  *	  PPP Tx queue, this will trigger a reconnect. Instead, close
  *	  the channel, which will kill pppd...
+ *
+ * v11 - 20.3.02 - Jean II
+ *	o Oops ! v10 fix disabled IrNET retries and passive behaviour.
+ *	  Better fix in irnet_disconnect_indication() :
+ *	  - if connected, kill pppd via hangup.
+ *	  - if not connected, reenable ppp Tx, which trigger IrNET retry.
  */
 
 /***************************** INCLUDES *****************************/
diff -urN linux-2.4.20-pre1/net/irda/irnet/irnet_irda.c linux-2.4.20-pre2/net/irda/irnet/irnet_irda.c
--- linux-2.4.20-pre1/net/irda/irnet/irnet_irda.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/irda/irnet/irnet_irda.c	Mon Aug 12 16:34:17 2002
@@ -1070,7 +1070,7 @@
  *	o attempted to connect, timeout
  *	o connected, link is broken, LAP has timeout
  *	o connected, other side close the link
- *	o connection request on the server no handled
+ *	o connection request on the server not handled
  */
 static void
 irnet_disconnect_indication(void *	instance,
@@ -1121,20 +1121,31 @@
       DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n");
       irttp_close_tsap(self->tsap);
       self->tsap = NULL;
-
-      /* Cleanup & close the PPP channel, which will kill pppd and the rest */
-      if(self->ppp_open)
-	ppp_unregister_channel(&self->chan);
-      self->ppp_open = 0;
     }
-  /* Cleanup the socket in case we want to reconnect */
+  /* Cleanup the socket in case we want to reconnect in ppp_output_wakeup() */
   self->stsap_sel = 0;
   self->daddr = DEV_ADDR_ANY;
   self->tx_flow = FLOW_START;
 
-  /* Note : what should we say to ppp ?
-   * It seem the ppp_generic and pppd are happy that way and will eventually
-   * timeout gracefully, so don't bother them... */
+  /* Deal with the ppp instance if it's still alive */
+  if(self->ppp_open)
+    {
+      if(test_open)
+	{
+	  /* If we were connected, cleanup & close the PPP channel,
+	   * which will kill pppd (hangup) and the rest */
+	  ppp_unregister_channel(&self->chan);
+	  self->ppp_open = 0;
+	}
+      else
+	{
+	  /* If we were trying to connect, flush (drain) ppp_generic
+	   * Tx queue (most often we have blocked it), which will
+	   * trigger an other attempt to connect. If we are passive,
+	   * this will empty the Tx queue after last try. */
+	  ppp_output_wakeup(&self->chan);
+	}
+    }
 
   DEXIT(IRDA_TCB_TRACE, "\n");
 }
@@ -1588,8 +1599,9 @@
  * is to messy, so we leave that to user space...
  */
 static void
-irnet_discovery_indication(discovery_t *discovery,
-			   void *	priv)
+irnet_discovery_indication(discovery_t *	discovery,
+			   DISCOVERY_MODE	mode,
+			   void *		priv)
 {
   irnet_socket *	self = &irnet_server.s;
 	
@@ -1627,6 +1639,7 @@
  */
 static void
 irnet_expiry_indication(discovery_t *	expiry,
+			DISCOVERY_MODE	mode,
 			void *		priv)
 {
   irnet_socket *	self = &irnet_server.s;
diff -urN linux-2.4.20-pre1/net/irda/irnet/irnet_irda.h linux-2.4.20-pre2/net/irda/irnet/irnet_irda.h
--- linux-2.4.20-pre1/net/irda/irnet/irnet_irda.h	Mon Jun 11 19:15:27 2001
+++ linux-2.4.20-pre2/net/irda/irnet/irnet_irda.h	Mon Aug 12 16:34:17 2002
@@ -151,9 +151,11 @@
 #ifdef DISCOVERY_EVENTS
 static void
 	irnet_discovery_indication(discovery_t *,
+				   DISCOVERY_MODE,
 				   void *);
 static void
 	irnet_expiry_indication(discovery_t *,
+				DISCOVERY_MODE,
 				void *);
 #endif
 /* -------------------------- PROC ENTRY -------------------------- */
diff -urN linux-2.4.20-pre1/net/irda/irsysctl.c linux-2.4.20-pre2/net/irda/irsysctl.c
--- linux-2.4.20-pre1/net/irda/irsysctl.c	Fri Dec 21 09:42:06 2001
+++ linux-2.4.20-pre2/net/irda/irsysctl.c	Mon Aug 12 16:34:17 2002
@@ -35,17 +35,19 @@
 #define NET_IRDA 412 /* Random number */
 enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS,
        DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME,
-       MAX_NOREPLY_TIME, WARN_NOREPLY_TIME, LAP_KEEPALIVE_TIME };
+       MAX_TX_DATA_SIZE, MAX_NOREPLY_TIME, WARN_NOREPLY_TIME,
+       LAP_KEEPALIVE_TIME };
 
 extern int  sysctl_discovery;
 extern int  sysctl_discovery_slots;
 extern int  sysctl_discovery_timeout;
-extern int  sysctl_slot_timeout;	/* Candidate */
+extern int  sysctl_slot_timeout;
 extern int  sysctl_fast_poll_increase;
 int         sysctl_compression = 0;
 extern char sysctl_devname[];
 extern int  sysctl_max_baud_rate;
 extern int  sysctl_min_tx_turn_time;
+extern int  sysctl_max_tx_data_size;
 extern int  sysctl_max_noreply_time;
 extern int  sysctl_warn_noreply_time;
 extern int  sysctl_lap_keepalive_time;
@@ -65,6 +67,8 @@
 static int min_max_baud_rate = 2400;
 static int max_min_tx_turn_time = 10000;	/* See qos.c - IrLAP spec */
 static int min_min_tx_turn_time = 0;
+static int max_max_tx_data_size = 2048;		/* See qos.c - IrLAP spec */
+static int min_max_tx_data_size = 64;
 static int max_max_noreply_time = 40;		/* See qos.c - IrLAP spec */
 static int min_max_noreply_time = 3;
 static int max_warn_noreply_time = 3;		/* 3s == standard */
@@ -118,6 +122,9 @@
 	{ MIN_TX_TURN_TIME, "min_tx_turn_time", &sysctl_min_tx_turn_time,
 	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
 	  NULL, &min_min_tx_turn_time, &max_min_tx_turn_time },
+	{ MAX_TX_DATA_SIZE, "max_tx_data_size", &sysctl_max_tx_data_size,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_max_tx_data_size, &max_max_tx_data_size },
 	{ MAX_NOREPLY_TIME, "max_noreply_time", &sysctl_max_noreply_time,
 	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
 	  NULL, &min_max_noreply_time, &max_max_noreply_time },
diff -urN linux-2.4.20-pre1/net/irda/qos.c linux-2.4.20-pre2/net/irda/qos.c
--- linux-2.4.20-pre1/net/irda/qos.c	Fri Dec 21 09:42:06 2001
+++ linux-2.4.20-pre2/net/irda/qos.c	Mon Aug 12 16:34:17 2002
@@ -57,10 +57,26 @@
  * Nonzero values (usec) are used as lower limit to the per-connection
  * mtt value which was announced by the other end during negotiation.
  * Might be helpful if the peer device provides too short mtt.
- * Default is 10 which means using the unmodified value given by the peer
- * except if it's 0 (0 is likely a bug in the other stack).
+ * Default is 10us which means using the unmodified value given by the
+ * peer except if it's 0 (0 is likely a bug in the other stack).
  */
 unsigned sysctl_min_tx_turn_time = 10;
+/*
+ * Maximum data size to be used in transmission in payload of LAP frame.
+ * There is a bit of confusion in the IrDA spec :
+ * The LAP spec defines the payload of a LAP frame (I field) to be
+ * 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40).
+ * On the other hand, the PHY mention frames of 2048 bytes max (IrPHY
+ * 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header
+ * (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP
+ * payload), that's only 2042 bytes. Oups !
+ * I've had trouble trouble transmitting 2048 bytes frames with USB
+ * dongles and nsc-ircc at 4 Mb/s, so adjust to 2042... I don't know
+ * if this bug applies only for 2048 bytes frames or all negociated
+ * frame sizes, but all hardware seem to support "2048 bytes" frames.
+ * You can use the sysctl to play with this value anyway.
+ * Jean II */
+unsigned sysctl_max_tx_data_size = 2042;
 
 static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
 static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, 
@@ -355,10 +371,10 @@
 	while ((qos->data_size.value > line_capacity) && (index > 0)) {
 		qos->data_size.value = data_sizes[index--];
 		IRDA_DEBUG(2, __FUNCTION__ 
-			   "(), redusing data size to %d\n",
+			   "(), reducing data size to %d\n",
 			   qos->data_size.value);
 	}
-#else /* Use method descibed in section 6.6.11 of IrLAP */
+#else /* Use method described in section 6.6.11 of IrLAP */
 	while (irlap_requested_line_capacity(qos) > line_capacity) {
 		ASSERT(index != 0, return;);
 
@@ -366,18 +382,24 @@
 		if (qos->window_size.value > 1) {
 			qos->window_size.value--;
 			IRDA_DEBUG(2, __FUNCTION__ 
-				   "(), redusing window size to %d\n",
+				   "(), reducing window size to %d\n",
 				   qos->window_size.value);
 		} else if (index > 1) {
 			qos->data_size.value = data_sizes[index--];
 			IRDA_DEBUG(2, __FUNCTION__ 
-				   "(), redusing data size to %d\n",
+				   "(), reducing data size to %d\n",
 				   qos->data_size.value);
 		} else {
 			WARNING(__FUNCTION__ "(), nothing more we can do!\n");
 		}
 	}
 #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
+	/*
+	 * Fix tx data size according to user limits - Jean II
+	 */
+	if (qos->data_size.value > sysctl_max_tx_data_size)
+		/* Allow non discrete adjustement to avoid loosing capacity */
+		qos->data_size.value = sysctl_max_tx_data_size;
 }
 
 /*
diff -urN linux-2.4.20-pre1/net/netsyms.c linux-2.4.20-pre2/net/netsyms.c
--- linux-2.4.20-pre1/net/netsyms.c	Mon Aug 12 16:34:13 2002
+++ linux-2.4.20-pre2/net/netsyms.c	Mon Aug 12 16:34:17 2002
@@ -493,6 +493,7 @@
 EXPORT_SYMBOL(skb_clone);
 EXPORT_SYMBOL(skb_copy);
 EXPORT_SYMBOL(netif_rx);
+EXPORT_SYMBOL(netif_receive_skb);
 EXPORT_SYMBOL(dev_add_pack);
 EXPORT_SYMBOL(dev_remove_pack);
 EXPORT_SYMBOL(dev_get);
@@ -591,4 +592,10 @@
 EXPORT_SYMBOL(net_call_rx_atomic);
 EXPORT_SYMBOL(softnet_data);
 
+#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
+/* Don't include the whole header mess for a single function */
+extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra);
+EXPORT_SYMBOL(wireless_send_event);
+#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+
 #endif  /* CONFIG_NET */
diff -urN linux-2.4.20-pre1/net/sched/sch_ingress.c linux-2.4.20-pre2/net/sched/sch_ingress.c
--- linux-2.4.20-pre1/net/sched/sch_ingress.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/sched/sch_ingress.c	Mon Aug 12 16:34:17 2002
@@ -106,7 +106,7 @@
 #endif
 	DPRINTK("ingress_change(sch %p,[qdisc %p],classid %x,parent %x),"
 		"arg 0x%lx\n", sch, p, classid, parent, *arg);
-	DPRINTK("No effect. sch_ingress doesnt maintain classes at the moment");
+	DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment");
 	return 0;
 }
 
@@ -118,7 +118,7 @@
 	struct ingress_qdisc_data *p = PRIV(sch);
 #endif
 	DPRINTK("ingress_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
-	DPRINTK("No effect. sch_ingress doesnt maintain classes at the moment");
+	DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment");
 }
 
 
diff -urN linux-2.4.20-pre1/net/sunrpc/clnt.c linux-2.4.20-pre2/net/sunrpc/clnt.c
--- linux-2.4.20-pre1/net/sunrpc/clnt.c	Fri Sep 21 11:24:50 2001
+++ linux-2.4.20-pre2/net/sunrpc/clnt.c	Mon Aug 12 16:34:17 2002
@@ -78,10 +78,6 @@
 	dprintk("RPC: creating %s client for %s (xprt %p)\n",
 		program->name, servname, xprt);
 
-#ifdef RPC_DEBUG
-	rpc_register_sysctl();
-#endif
-
 	if (!xprt)
 		goto out;
 	if (vers >= program->nrvers || !(version = program->version[vers]))
@@ -103,7 +99,7 @@
 	clnt->cl_vers     = version->number;
 	clnt->cl_prot     = xprt->prot;
 	clnt->cl_stats    = program->stats;
-	clnt->cl_bindwait = RPC_INIT_WAITQ("bindwait");
+	INIT_RPC_WAITQ(&clnt->cl_bindwait, "bindwait");
 
 	if (!clnt->cl_port)
 		clnt->cl_autobind = 1;
diff -urN linux-2.4.20-pre1/net/sunrpc/sched.c linux-2.4.20-pre2/net/sunrpc/sched.c
--- linux-2.4.20-pre1/net/sunrpc/sched.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/sunrpc/sched.c	Mon Aug 12 16:34:17 2002
@@ -41,23 +41,23 @@
  * handler, or while executing another RPC task, it is put on
  * schedq, and rpciod is woken up.
  */
-static struct rpc_wait_queue	schedq = RPC_INIT_WAITQ("schedq");
+static RPC_WAITQ(schedq, "schedq");
 
 /*
  * RPC tasks that create another task (e.g. for contacting the portmapper)
  * will wait on this queue for their child's completion
  */
-static struct rpc_wait_queue	childq = RPC_INIT_WAITQ("childq");
+static RPC_WAITQ(childq, "childq");
 
 /*
  * RPC tasks sit here while waiting for conditions to improve.
  */
-static struct rpc_wait_queue	delay_queue = RPC_INIT_WAITQ("delayq");
+static RPC_WAITQ(delay_queue, "delayq");
 
 /*
  * All RPC tasks are linked into this list
  */
-static struct rpc_task *	all_tasks;
+static LIST_HEAD(all_tasks);
 
 /*
  * rpciod-related stuff
@@ -194,9 +194,9 @@
 		return -EWOULDBLOCK;
 	}
 	if (RPC_IS_SWAPPER(task))
-		rpc_insert_list(&queue->task, task);
+		list_add(&task->tk_list, &queue->tasks);
 	else
-		rpc_append_list(&queue->task, task);
+		list_add_tail(&task->tk_list, &queue->tasks);
 	task->tk_rpcwait = queue;
 
 	dprintk("RPC: %4d added to queue %p \"%s\"\n",
@@ -228,7 +228,7 @@
 	if (!queue)
 		return;
 
-	rpc_remove_list(&queue->task, task);
+	list_del(&task->tk_list);
 	task->tk_rpcwait = NULL;
 
 	dprintk("RPC: %4d removed from queue %p \"%s\"\n",
@@ -450,11 +450,11 @@
 struct rpc_task *
 rpc_wake_up_next(struct rpc_wait_queue *queue)
 {
-	struct rpc_task	*task;
+	struct rpc_task	*task = NULL;
 
 	dprintk("RPC:      wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue));
 	spin_lock_bh(&rpc_queue_lock);
-	if ((task = queue->task) != 0)
+	task_for_first(task, &queue->tasks)
 		__rpc_wake_up_task(task);
 	spin_unlock_bh(&rpc_queue_lock);
 
@@ -470,9 +470,12 @@
 void
 rpc_wake_up(struct rpc_wait_queue *queue)
 {
+	struct rpc_task *task;
+
 	spin_lock_bh(&rpc_queue_lock);
-	while (queue->task)
-		__rpc_wake_up_task(queue->task);
+	while (!list_empty(&queue->tasks))
+		task_for_first(task, &queue->tasks)
+			__rpc_wake_up_task(task);
 	spin_unlock_bh(&rpc_queue_lock);
 }
 
@@ -486,12 +489,14 @@
 void
 rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
 {
-	struct rpc_task	*task;
+	struct rpc_task *task;
 
 	spin_lock_bh(&rpc_queue_lock);
-	while ((task = queue->task) != NULL) {
-		task->tk_status = status;
-		__rpc_wake_up_task(task);
+	while (!list_empty(&queue->tasks)) {
+		task_for_first(task, &queue->tasks) {
+			task->tk_status = status;
+			__rpc_wake_up_task(task);
+		}
 	}
 	spin_unlock_bh(&rpc_queue_lock);
 }
@@ -700,23 +705,25 @@
 	dprintk("RPC:      rpc_schedule enter\n");
 	while (1) {
 		spin_lock_bh(&rpc_queue_lock);
-		if (!(task = schedq.task)) {
-			spin_unlock_bh(&rpc_queue_lock);
-			break;
-		}
-		if (task->tk_lock) {
-			spin_unlock_bh(&rpc_queue_lock);
-			printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n");
+
+		task_for_first(task, &schedq.tasks) {
+			if (task->tk_lock) {
+				spin_unlock_bh(&rpc_queue_lock);
+				printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n");
 #ifdef RPC_DEBUG			
-			rpc_debug = ~0;
-			rpc_show_tasks();
+				rpc_debug = ~0;
+				rpc_show_tasks();
 #endif			
+				break;
+			}
+			__rpc_remove_wait_queue(task);
+			spin_unlock_bh(&rpc_queue_lock);
+
+			__rpc_execute(task);
+		} else {
+			spin_unlock_bh(&rpc_queue_lock);
 			break;
 		}
-		__rpc_remove_wait_queue(task);
-		spin_unlock_bh(&rpc_queue_lock);
-
-		__rpc_execute(task);
 
 		if (++count >= 200 || current->need_resched) {
 			count = 0;
@@ -812,11 +819,7 @@
 
 	/* Add to global list of all tasks */
 	spin_lock(&rpc_sched_lock);
-	task->tk_next_task = all_tasks;
-	task->tk_prev_task = NULL;
-	if (all_tasks)
-		all_tasks->tk_prev_task = task;
-	all_tasks = task;
+	list_add(&task->tk_task, &all_tasks);
 	spin_unlock(&rpc_sched_lock);
 
 	if (clnt)
@@ -875,8 +878,6 @@
 void
 rpc_release_task(struct rpc_task *task)
 {
-	struct rpc_task	*next, *prev;
-
 	dprintk("RPC: %4d release task\n", task->tk_pid);
 
 #ifdef RPC_DEBUG
@@ -890,15 +891,7 @@
 
 	/* Remove from global task list */
 	spin_lock(&rpc_sched_lock);
-	prev = task->tk_prev_task;
-	next = task->tk_next_task;
-	if (next)
-		next->tk_prev_task = prev;
-	if (prev)
-		prev->tk_next_task = next;
-	else
-		all_tasks = next;
-	task->tk_next_task = task->tk_prev_task = NULL;
+	list_del(&task->tk_task);
 	spin_unlock(&rpc_sched_lock);
 
 	/* Protect the execution below. */
@@ -952,14 +945,13 @@
 rpc_find_parent(struct rpc_task *child)
 {
 	struct rpc_task	*task, *parent;
+	struct list_head *le;
 
 	parent = (struct rpc_task *) child->tk_calldata;
-	if ((task = childq.task) != NULL) {
-		do {
-			if (task == parent)
-				return parent;
-		} while ((task = task->tk_next) != childq.task);
-	}
+	task_for_each(task, le, &childq.tasks)
+		if (task == parent)
+			return parent;
+
 	return NULL;
 }
 
@@ -1013,7 +1005,8 @@
 void
 rpc_killall_tasks(struct rpc_clnt *clnt)
 {
-	struct rpc_task	**q, *rovr;
+	struct rpc_task	*rovr;
+	struct list_head *le;
 
 	dprintk("RPC:      killing all tasks for client %p\n", clnt);
 
@@ -1021,13 +1014,12 @@
 	 * Spin lock all_tasks to prevent changes...
 	 */
 	spin_lock(&rpc_sched_lock);
-	for (q = &all_tasks; (rovr = *q); q = &rovr->tk_next_task) {
+	alltask_for_each(rovr, le, &all_tasks)
 		if (!clnt || rovr->tk_client == clnt) {
 			rovr->tk_flags |= RPC_TASK_KILLED;
 			rpc_exit(rovr, -EIO);
 			rpc_wake_up_task(rovr);
 		}
-	}
 	spin_unlock(&rpc_sched_lock);
 }
 
@@ -1036,7 +1028,7 @@
 static inline int
 rpciod_task_pending(void)
 {
-	return schedq.task != NULL;
+	return !list_empty(&schedq.tasks);
 }
 
 
@@ -1088,7 +1080,7 @@
 	}
 
 	dprintk("RPC: rpciod shutdown commences\n");
-	if (all_tasks) {
+	if (!list_empty(&all_tasks)) {
 		printk(KERN_ERR "rpciod: active tasks at shutdown?!\n");
 		rpciod_killall();
 	}
@@ -1106,11 +1098,11 @@
 {
 	unsigned long flags;
 
-	while (all_tasks) {
+	while (!list_empty(&all_tasks)) {
 		current->sigpending = 0;
 		rpc_killall_tasks(NULL);
 		__rpc_schedule();
-		if (all_tasks) {
+		if (!list_empty(&all_tasks)) {
 			dprintk("rpciod_killall: waiting for tasks to exit\n");
 			current->policy |= SCHED_YIELD;
 			schedule();
@@ -1207,25 +1199,23 @@
 #ifdef RPC_DEBUG
 void rpc_show_tasks(void)
 {
-	struct rpc_task *t = all_tasks, *next;
+	struct list_head *le;
+	struct rpc_task *t;
 
 	spin_lock(&rpc_sched_lock);
-	t = all_tasks;
-	if (!t) {
+	if (list_empty(&all_tasks)) {
 		spin_unlock(&rpc_sched_lock);
 		return;
 	}
 	printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
 		"-rpcwait -action- --exit--\n");
-	for (; t; t = next) {
-		next = t->tk_next_task;
+	alltask_for_each(t, le, &all_tasks)
 		printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n",
 			t->tk_pid, t->tk_msg.rpc_proc, t->tk_flags, t->tk_status,
 			t->tk_client, t->tk_client->cl_prog,
 			t->tk_rqstp, t->tk_timeout,
 			t->tk_rpcwait ? rpc_qname(t->tk_rpcwait) : " <NULL> ",
 			t->tk_action, t->tk_exit);
-	}
 	spin_unlock(&rpc_sched_lock);
 }
 #endif
diff -urN linux-2.4.20-pre1/net/sunrpc/stats.c linux-2.4.20-pre2/net/sunrpc/stats.c
--- linux-2.4.20-pre1/net/sunrpc/stats.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/sunrpc/stats.c	Mon Aug 12 16:34:17 2002
@@ -15,6 +15,7 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -182,10 +183,9 @@
 	}
 }
 
-#ifdef MODULE
 
-int
-init_module(void)
+static int __init
+init_sunrpc(void)
 {
 #ifdef RPC_DEBUG
 	rpc_register_sysctl();
@@ -194,13 +194,14 @@
 	return 0;
 }
 
-void
-cleanup_module(void)
+static void __exit
+cleanup_sunrpc(void)
 {
 #ifdef RPC_DEBUG
 	rpc_unregister_sysctl();
 #endif
 	rpc_proc_exit();
 }
-#endif
 MODULE_LICENSE("GPL");
+module_init(init_sunrpc);
+module_exit(cleanup_sunrpc);
diff -urN linux-2.4.20-pre1/net/sunrpc/sunrpc_syms.c linux-2.4.20-pre2/net/sunrpc/sunrpc_syms.c
--- linux-2.4.20-pre1/net/sunrpc/sunrpc_syms.c	Thu Sep 20 21:02:01 2001
+++ linux-2.4.20-pre2/net/sunrpc/sunrpc_syms.c	Mon Aug 12 16:34:17 2002
@@ -77,6 +77,7 @@
 EXPORT_SYMBOL(svc_recv);
 EXPORT_SYMBOL(svc_wake_up);
 EXPORT_SYMBOL(svc_makesock);
+EXPORT_SYMBOL(svc_reserve);
 
 /* RPC statistics */
 #ifdef CONFIG_PROC_FS
diff -urN linux-2.4.20-pre1/net/sunrpc/svc.c linux-2.4.20-pre2/net/sunrpc/svc.c
--- linux-2.4.20-pre1/net/sunrpc/svc.c	Fri Sep  7 10:48:39 2001
+++ linux-2.4.20-pre2/net/sunrpc/svc.c	Mon Aug 12 16:34:17 2002
@@ -31,10 +31,6 @@
 {
 	struct svc_serv	*serv;
 
-#ifdef RPC_DEBUG
-	rpc_register_sysctl();
-#endif
-
 	if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL)))
 		return NULL;
 
@@ -44,6 +40,10 @@
 	serv->sv_stats     = prog->pg_stats;
 	serv->sv_bufsz	   = bufsize? bufsize : 4096;
 	serv->sv_xdrsize   = xdrsize;
+	INIT_LIST_HEAD(&serv->sv_threads);
+	INIT_LIST_HEAD(&serv->sv_sockets);
+	INIT_LIST_HEAD(&serv->sv_tempsocks);
+	INIT_LIST_HEAD(&serv->sv_permsocks);
 	spin_lock_init(&serv->sv_lock);
 
 	serv->sv_name      = prog->pg_name;
@@ -67,13 +67,25 @@
 				serv->sv_nrthreads);
 
 	if (serv->sv_nrthreads) {
-		if (--(serv->sv_nrthreads) != 0)
+		if (--(serv->sv_nrthreads) != 0) {
+			svc_sock_update_bufs(serv);
 			return;
+		}
 	} else
 		printk("svc_destroy: no threads for serv=%p!\n", serv);
 
-	while ((svsk = serv->sv_allsocks) != NULL)
+	while (!list_empty(&serv->sv_tempsocks)) {
+		svsk = list_entry(serv->sv_tempsocks.next,
+				  struct svc_sock,
+				  sk_list);
+		svc_delete_socket(svsk);
+	}
+	while (!list_empty(&serv->sv_permsocks)) {
+		svsk = list_entry(serv->sv_permsocks.next,
+				  struct svc_sock,
+				  sk_list);
 		svc_delete_socket(svsk);
+	}
 
 	/* Unregister service with the portmapper */
 	svc_register(serv, 0, 0);
@@ -138,6 +150,7 @@
 	error = kernel_thread((int (*)(void *)) func, rqstp, 0);
 	if (error < 0)
 		goto out_thread;
+	svc_sock_update_bufs(serv);
 	error = 0;
 out:
 	return error;
@@ -296,6 +309,12 @@
 	memset(rqstp->rq_argp, 0, procp->pc_argsize);
 	memset(rqstp->rq_resp, 0, procp->pc_ressize);
 
+	/* un-reserve some of the out-queue now that we have a 
+	 * better idea of reply size
+	 */
+	if (procp->pc_xdrressize)
+		svc_reserve(rqstp, procp->pc_xdrressize<<2);
+
 	/* Call the function that processes the request. */
 	if (!versp->vs_dispatch) {
 		/* Decode arguments */
diff -urN linux-2.4.20-pre1/net/sunrpc/svcsock.c linux-2.4.20-pre2/net/sunrpc/svcsock.c
--- linux-2.4.20-pre1/net/sunrpc/svcsock.c	Wed Jul  4 11:50:38 2001
+++ linux-2.4.20-pre2/net/sunrpc/svcsock.c	Mon Aug 12 16:34:17 2002
@@ -44,10 +44,19 @@
 
 /* SMP locking strategy:
  *
- * 	svc_sock->sk_lock and svc_serv->sv_lock protect their
- *	respective structures.
+ * 	svc_serv->sv_lock protects most stuff for that service.
+ *
+ *	Some flags can be set to certain values at any time
+ *	providing that certain rules are followed:
+ *
+ *	SK_BUSY  can be set to 0 at any time.  
+ *		svc_sock_enqueue must be called afterwards
+ *	SK_CONN, SK_DATA, can be set or cleared at any time.
+ *		after a set, svc_sock_enqueue must be called.	
+ *		after a clear, the socket must be read/accepted
+ *		 if this succeeds, it must be set again.
+ *	SK_CLOSE can set at any time. It is never cleared.
  *
- *	Antideadlock ordering is sk_lock --> sv_lock.
  */
 
 #define RPCDBG_FACILITY	RPCDBG_SVCSOCK
@@ -62,11 +71,14 @@
 
 /*
  * Queue up an idle server thread.  Must have serv->sv_lock held.
+ * Note: this is really a stack rather than a queue, so that we only
+ * use as many different threads as we need, and the rest don't polute
+ * the cache.
  */
 static inline void
 svc_serv_enqueue(struct svc_serv *serv, struct svc_rqst *rqstp)
 {
-	rpc_append_list(&serv->sv_threads, rqstp);
+	list_add(&rqstp->rq_list, &serv->sv_threads);
 }
 
 /*
@@ -75,7 +87,7 @@
 static inline void
 svc_serv_dequeue(struct svc_serv *serv, struct svc_rqst *rqstp)
 {
-	rpc_remove_list(&serv->sv_threads, rqstp);
+	list_del(&rqstp->rq_list);
 }
 
 /*
@@ -98,7 +110,6 @@
  * Queue up a socket with data pending. If there are idle nfsd
  * processes, wake 'em up.
  *
- * This must be called with svsk->sk_lock held.
  */
 static void
 svc_sock_enqueue(struct svc_sock *svsk)
@@ -106,26 +117,44 @@
 	struct svc_serv	*serv = svsk->sk_server;
 	struct svc_rqst	*rqstp;
 
-	/* NOTE: Local BH is already disabled by our caller. */
-	spin_lock(&serv->sv_lock);
+	if (!(svsk->sk_flags &
+	      ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)) ))
+		return;
+
+	spin_lock_bh(&serv->sv_lock);
 
-	if (serv->sv_threads && serv->sv_sockets)
+	if (!list_empty(&serv->sv_threads) && 
+	    !list_empty(&serv->sv_sockets))
 		printk(KERN_ERR
 			"svc_sock_enqueue: threads and sockets both waiting??\n");
 
-	if (svsk->sk_busy) {
+	if (test_bit(SK_BUSY, &svsk->sk_flags)) {
 		/* Don't enqueue socket while daemon is receiving */
 		dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk);
 		goto out_unlock;
 	}
 
+	if (((svsk->sk_reserved + serv->sv_bufsz)*2
+	     > sock_wspace(svsk->sk_sk))
+	    && !test_bit(SK_CLOSE, &svsk->sk_flags)
+	    && !test_bit(SK_CONN, &svsk->sk_flags)) {
+		/* Don't enqueue while not enough space for reply */
+		dprintk("svc: socket %p  no space, %d > %ld, not enqueued\n",
+			svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz,
+			sock_wspace(svsk->sk_sk));
+		goto out_unlock;
+	}
+
 	/* Mark socket as busy. It will remain in this state until the
 	 * server has processed all pending data and put the socket back
 	 * on the idle list.
 	 */
-	svsk->sk_busy = 1;
+	set_bit(SK_BUSY, &svsk->sk_flags);
 
-	if ((rqstp = serv->sv_threads) != NULL) {
+	if (!list_empty(&serv->sv_threads)) {
+		rqstp = list_entry(serv->sv_threads.next,
+				   struct svc_rqst,
+				   rq_list);
 		dprintk("svc: socket %p served by daemon %p\n",
 			svsk->sk_sk, rqstp);
 		svc_serv_dequeue(serv, rqstp);
@@ -135,15 +164,17 @@
 				rqstp, rqstp->rq_sock);
 		rqstp->rq_sock = svsk;
 		svsk->sk_inuse++;
+		rqstp->rq_reserved = serv->sv_bufsz;
+		svsk->sk_reserved += rqstp->rq_reserved;
 		wake_up(&rqstp->rq_wait);
 	} else {
 		dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
-		rpc_append_list(&serv->sv_sockets, svsk);
-		svsk->sk_qued = 1;
+		list_add_tail(&svsk->sk_ready, &serv->sv_sockets);
+		set_bit(SK_QUED, &svsk->sk_flags);
 	}
 
 out_unlock:
-	spin_unlock(&serv->sv_lock);
+	spin_unlock_bh(&serv->sv_lock);
 }
 
 /*
@@ -154,71 +185,69 @@
 {
 	struct svc_sock	*svsk;
 
-	if ((svsk = serv->sv_sockets) != NULL)
-		rpc_remove_list(&serv->sv_sockets, svsk);
+	if (list_empty(&serv->sv_sockets))
+		return NULL;
 
-	if (svsk) {
-		dprintk("svc: socket %p dequeued, inuse=%d\n",
-			svsk->sk_sk, svsk->sk_inuse);
-		svsk->sk_qued = 0;
-	}
+	svsk = list_entry(serv->sv_sockets.next,
+			  struct svc_sock, sk_ready);
+	list_del(&svsk->sk_ready);
+
+	dprintk("svc: socket %p dequeued, inuse=%d\n",
+		svsk->sk_sk, svsk->sk_inuse);
+	clear_bit(SK_QUED, &svsk->sk_flags);
 
 	return svsk;
 }
 
 /*
- * Having read count bytes from a socket, check whether it
+ * Having read something from a socket, check whether it
  * needs to be re-enqueued.
+ * Note: SK_DATA only gets cleared when a read-attempt finds
+ * no (or insufficient) data.
  */
 static inline void
-svc_sock_received(struct svc_sock *svsk, int count)
+svc_sock_received(struct svc_sock *svsk)
 {
-	spin_lock_bh(&svsk->sk_lock);
-	if ((svsk->sk_data -= count) < 0) {
-		printk(KERN_NOTICE "svc: sk_data negative!\n");
-		svsk->sk_data = 0;
-	}
-	svsk->sk_rqstp = NULL; /* XXX */
-	svsk->sk_busy = 0;
-	if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) {
-		dprintk("svc: socket %p re-enqueued after receive\n",
-						svsk->sk_sk);
-		svc_sock_enqueue(svsk);
-	}
-	spin_unlock_bh(&svsk->sk_lock);
+	clear_bit(SK_BUSY, &svsk->sk_flags);
+	svc_sock_enqueue(svsk);
 }
 
-/*
- * Dequeue a new connection.
+
+/**
+ * svc_reserve - change the space reserved for the reply to a request.
+ * @rqstp:  The request in question
+ * @space: new max space to reserve
+ *
+ * Each request reserves some space on the output queue of the socket
+ * to make sure the reply fits.  This function reduces that reserved
+ * space to be the amount of space used already, plus @space.
+ *
  */
-static inline void
-svc_sock_accepted(struct svc_sock *svsk)
+void svc_reserve(struct svc_rqst *rqstp, int space)
 {
-	spin_lock_bh(&svsk->sk_lock);
-        svsk->sk_busy = 0;
-        svsk->sk_conn--;
-        if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) {
-                dprintk("svc: socket %p re-enqueued after accept\n",
-						svsk->sk_sk);
-                svc_sock_enqueue(svsk);
-        }
-	spin_unlock_bh(&svsk->sk_lock);
+	space += rqstp->rq_resbuf.len<<2;
+
+	if (space < rqstp->rq_reserved) {
+		struct svc_sock *svsk = rqstp->rq_sock;
+		spin_lock_bh(&svsk->sk_server->sv_lock);
+		svsk->sk_reserved -= (rqstp->rq_reserved - space);
+		rqstp->rq_reserved = space;
+		spin_unlock_bh(&svsk->sk_server->sv_lock);
+
+		svc_sock_enqueue(svsk);
+	}
 }
 
 /*
  * Release a socket after use.
  */
 static inline void
-svc_sock_release(struct svc_rqst *rqstp)
+svc_sock_put(struct svc_sock *svsk)
 {
-	struct svc_sock	*svsk = rqstp->rq_sock;
-	struct svc_serv	*serv = svsk->sk_server;
-
-	svc_release_skb(rqstp);
-	rqstp->rq_sock = NULL;
+	struct svc_serv *serv = svsk->sk_server;
 
 	spin_lock_bh(&serv->sv_lock);
-	if (!--(svsk->sk_inuse) && svsk->sk_dead) {
+	if (!--(svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) {
 		spin_unlock_bh(&serv->sv_lock);
 		dprintk("svc: releasing dead socket\n");
 		sock_release(svsk->sk_sock);
@@ -228,6 +257,31 @@
 		spin_unlock_bh(&serv->sv_lock);
 }
 
+static void
+svc_sock_release(struct svc_rqst *rqstp)
+{
+	struct svc_sock	*svsk = rqstp->rq_sock;
+
+	svc_release_skb(rqstp);
+
+	/* Reset response buffer and release
+	 * the reservation.
+	 * But first, check that enough space was reserved
+	 * for the reply, otherwise we have a bug!
+	 */
+	if ((rqstp->rq_resbuf.len<<2) >  rqstp->rq_reserved)
+		printk(KERN_ERR "RPC request reserved %d but used %d\n",
+		       rqstp->rq_reserved,
+		       rqstp->rq_resbuf.len<<2);
+
+	rqstp->rq_resbuf.buf = rqstp->rq_resbuf.base;
+	rqstp->rq_resbuf.len = 0;
+	svc_reserve(rqstp, 0);
+	rqstp->rq_sock = NULL;
+
+	svc_sock_put(svsk);
+}
+
 /*
  * External function to wake up a server waiting for data
  */
@@ -237,7 +291,10 @@
 	struct svc_rqst	*rqstp;
 
 	spin_lock_bh(&serv->sv_lock);
-	if ((rqstp = serv->sv_threads) != NULL) {
+	if (!list_empty(&serv->sv_threads)) {
+		rqstp = list_entry(serv->sv_threads.next,
+				   struct svc_rqst,
+				   rq_list);
 		dprintk("svc: daemon %p woken up.\n", rqstp);
 		/*
 		svc_serv_dequeue(serv, rqstp);
@@ -270,7 +327,13 @@
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
 
-	msg.msg_flags	= MSG_DONTWAIT;
+	/* This was MSG_DONTWAIT, but I now want it to wait.
+	 * The only thing that it would wait for is memory and
+	 * if we are fairly low on memory, then we aren't likely
+	 * to make much progress anyway.
+	 * sk->sndtimeo is set to 30seconds just in case.
+	 */
+	msg.msg_flags	= 0;
 
 	oldfs = get_fs(); set_fs(KERNEL_DS);
 	len = sock_sendmsg(sock, &msg, buflen);
@@ -340,6 +403,32 @@
 }
 
 /*
+ * Set socket snd and rcv buffer lengths
+ */
+static inline void
+svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv)
+{
+#if 0
+	mm_segment_t	oldfs;
+	oldfs = get_fs(); set_fs(KERNEL_DS);
+	sock_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
+			(char*)&snd, sizeof(snd));
+	sock_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+			(char*)&rcv, sizeof(rcv));
+#else
+	/* sock_setsockopt limits use to sysctl_?mem_max,
+	 * which isn't acceptable.  Until that is made conditional
+	 * on not having CAP_SYS_RESOURCE or similar, we go direct...
+	 * DaveM said I could!
+	 */
+	lock_sock(sock->sk);
+	sock->sk->sndbuf = snd * 2;
+	sock->sk->rcvbuf = rcv * 2;
+	sock->sk->userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK;
+	release_sock(sock->sk);
+#endif
+}
+/*
  * INET callback when data has been received on the socket.
  */
 static void
@@ -350,17 +439,36 @@
 	if (!svsk)
 		goto out;
 	dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",
-		svsk, sk, count, svsk->sk_busy);
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_data = 1;
+		svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags));
+	set_bit(SK_DATA, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
 }
 
 /*
+ * INET callback when space is newly available on the socket.
+ */
+static void
+svc_write_space(struct sock *sk)
+{
+	struct svc_sock	*svsk = (struct svc_sock *)(sk->user_data);
+
+	if (svsk) {
+		dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
+			svsk, sk, test_bit(SK_BUSY, &svsk->sk_flags));
+		svc_sock_enqueue(svsk);
+	}
+
+	if (sk->sleep && waitqueue_active(sk->sleep)) {
+		printk(KERN_WARNING "RPC svc_write_space: some sleeping on %p\n",
+		       svsk);
+		wake_up_interruptible(sk->sleep);
+	}
+}
+
+/*
  * Receive a datagram from a UDP socket.
  */
 static int
@@ -372,20 +480,31 @@
 	u32		*data;
 	int		err, len;
 
-	svsk->sk_data = 0;
+	if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+		/* udp sockets need large rcvbuf as all pending
+		 * requests are still in that buffer.  sndbuf must
+		 * also be large enough that there is enough space
+		 * for one reply per thread.
+		 */
+		svc_sock_setbufsize(svsk->sk_sock,
+				    (serv->sv_nrthreads+3)* serv->sv_bufsz,
+				    (serv->sv_nrthreads+3)* serv->sv_bufsz);
+
+	clear_bit(SK_DATA, &svsk->sk_flags);
 	while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
-		svc_sock_received(svsk, 0);
+		svc_sock_received(svsk);
 		if (err == -EAGAIN)
 			return err;
 		/* possibly an icmp error */
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
+	set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
 
 	/* Sorry. */
 	if (skb_is_nonlinear(skb)) {
 		if (skb_linearize(skb, GFP_KERNEL) != 0) {
 			kfree_skb(skb);
-			svc_sock_received(svsk, 0);
+			svc_sock_received(svsk);
 			return 0;
 		}
 	}
@@ -393,13 +512,11 @@
 	if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
 		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
 			skb_free_datagram(svsk->sk_sk, skb);
-			svc_sock_received(svsk, 0);
+			svc_sock_received(svsk);
 			return 0;
 		}
 	}
 
-	/* There may be more data */
-	svsk->sk_data = 1;
 
 	len  = skb->len - sizeof(struct udphdr);
 	data = (u32 *) (skb->data + sizeof(struct udphdr));
@@ -421,7 +538,7 @@
 
 	/* One down, maybe more to go... */
 	svsk->sk_sk->stamp = skb->stamp;
-	svc_sock_received(svsk, 0);
+	svc_sock_received(svsk);
 
 	return len;
 }
@@ -444,9 +561,6 @@
 	if (error == -ECONNREFUSED)
 		/* ICMP error on earlier request. */
 		error = svc_sendto(rqstp, bufp->iov, bufp->nriov);
-	else if (error == -EAGAIN)
-		/* Ignore and wait for re-xmit */
-		error = 0;
 
 	return error;
 }
@@ -455,8 +569,10 @@
 svc_udp_init(struct svc_sock *svsk)
 {
 	svsk->sk_sk->data_ready = svc_udp_data_ready;
+	svsk->sk_sk->write_space = svc_write_space;
 	svsk->sk_recvfrom = svc_udp_recvfrom;
 	svsk->sk_sendto = svc_udp_sendto;
+	set_bit(SK_CHNGBUF, &svsk->sk_flags);
 
 	return 0;
 }
@@ -481,10 +597,8 @@
 		printk("svc: socket %p: no user data\n", sk);
 		goto out;
 	}
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_conn++;
+	set_bit(SK_CONN, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible_all(sk->sleep);
@@ -505,10 +619,8 @@
 		printk("svc: socket %p: no user data\n", sk);
 		goto out;
 	}
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_close = 1;
+	set_bit(SK_CLOSE, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible_all(sk->sleep);
@@ -523,10 +635,8 @@
 			sk, sk->user_data);
 	if (!(svsk = (struct svc_sock *)(sk->user_data)))
 		goto out;
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_data++;
+	set_bit(SK_DATA, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
@@ -559,13 +669,14 @@
 	newsock->type = sock->type;
 	newsock->ops = ops = sock->ops;
 
+	clear_bit(SK_CONN, &svsk->sk_flags);
 	if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) {
-		if (net_ratelimit())
+		if (err != -EAGAIN && net_ratelimit())
 			printk(KERN_WARNING "%s: accept failed (err %d)!\n",
 				   serv->sv_name, -err);
 		goto failed;		/* aborted connection or whatever */
 	}
-
+	set_bit(SK_CONN, &svsk->sk_flags);
 	slen = sizeof(sin);
 	err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1);
 	if (err < 0) {
@@ -593,14 +704,45 @@
 	if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0)))
 		goto failed;
 
+	/* make sure that a write doesn't block forever when
+	 * low on memory
+	 */
+	newsock->sk->sndtimeo = HZ*30;
+
 	/* Precharge. Data may have arrived on the socket before we
 	 * installed the data_ready callback. 
 	 */
-	spin_lock_bh(&newsvsk->sk_lock);
-	newsvsk->sk_data = 1;
-	newsvsk->sk_temp = 1;
+	set_bit(SK_DATA, &newsvsk->sk_flags);
 	svc_sock_enqueue(newsvsk);
-	spin_unlock_bh(&newsvsk->sk_lock);
+
+	/* make sure that we don't have too many active connections.
+	 * If we have, something must be dropped.
+	 * We randomly choose between newest and oldest (in terms
+	 * of recent activity) and drop it.
+	 */
+	if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*10) {
+		struct svc_sock *svsk = NULL;
+		spin_lock_bh(&serv->sv_lock);
+		if (!list_empty(&serv->sv_tempsocks)) {
+			if (net_random()&1)
+				svsk = list_entry(serv->sv_tempsocks.prev,
+						  struct svc_sock,
+						  sk_list);
+			else
+				svsk = list_entry(serv->sv_tempsocks.next,
+						  struct svc_sock,
+						  sk_list);
+			set_bit(SK_CLOSE, &svsk->sk_flags);
+			svsk->sk_inuse ++;
+		}
+		spin_unlock_bh(&serv->sv_lock);
+
+		if (svsk) {
+			svc_sock_enqueue(svsk);
+			svc_sock_put(svsk);
+		}
+
+	}
 
 	if (serv->sv_stats)
 		serv->sv_stats->nettcpconn++;
@@ -621,23 +763,38 @@
 	struct svc_sock	*svsk = rqstp->rq_sock;
 	struct svc_serv	*serv = svsk->sk_server;
 	struct svc_buf	*bufp = &rqstp->rq_argbuf;
-	int		len, ready, used;
+	int		len;
 
 	dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
-			svsk, svsk->sk_data, svsk->sk_conn, svsk->sk_close);
+		svsk, test_bit(SK_DATA, &svsk->sk_flags),
+		test_bit(SK_CONN, &svsk->sk_flags),
+		test_bit(SK_CLOSE, &svsk->sk_flags));
 
-	if (svsk->sk_close) {
+	if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
 		svc_delete_socket(svsk);
 		return 0;
 	}
 
-	if (svsk->sk_conn) {
+	if (test_bit(SK_CONN, &svsk->sk_flags)) {
 		svc_tcp_accept(svsk);
-		svc_sock_accepted(svsk);
+		svc_sock_received(svsk);
 		return 0;
 	}
 
-	ready = svsk->sk_data;
+	if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+		/* sndbuf needs to have room for one request
+		 * per thread, otherwise we can stall even when the
+		 * network isn't a bottleneck.
+		 * rcvbuf just needs to be able to hold a few requests.
+		 * Normally they will be removed from the queue 
+		 * as soon as a complete request arrives.
+		 */
+		svc_sock_setbufsize(svsk->sk_sock,
+				    (serv->sv_nrthreads+3) *
+				    serv->sv_bufsz,
+				    3 * serv->sv_bufsz);
+
+	clear_bit(SK_DATA, &svsk->sk_flags);
 
 	/* Receive data. If we haven't got the record length yet, get
 	 * the next four bytes. Otherwise try to gobble up as much as
@@ -652,6 +809,8 @@
 		if ((len = svc_recvfrom(rqstp, &iov, 1, want)) < 0)
 			goto error;
 		svsk->sk_tcplen += len;
+		if (len < want)
+			return 0;
 
 		svsk->sk_reclen = ntohl(svsk->sk_reclen);
 		if (!(svsk->sk_reclen & 0x80000000)) {
@@ -660,13 +819,17 @@
 			 *  bit set in the fragment length header.
 			 *  But apparently no known nfs clients send fragmented
 			 *  records. */
-			/* FIXME: shutdown socket */
-			printk(KERN_NOTICE "RPC: bad TCP reclen %08lx",
+			printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (non-terminal)\n",
 			       (unsigned long) svsk->sk_reclen);
-			return -EIO;
+			goto err_delete;
 		}
 		svsk->sk_reclen &= 0x7fffffff;
 		dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
+		if (svsk->sk_reclen > (bufp->buflen<<2)) {
+			printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (large)\n",
+			       (unsigned long) svsk->sk_reclen);
+			goto err_delete;
+		}
 	}
 
 	/* Check whether enough data is available */
@@ -675,21 +838,12 @@
 		goto error;
 
 	if (len < svsk->sk_reclen) {
-		/* FIXME: if sk_reclen > window-size, then we will
-		 * never be able to receive the record, so should
-		 * shutdown the connection
-		 */
 		dprintk("svc: incomplete TCP record (%d of %d)\n",
 			len, svsk->sk_reclen);
-		svc_sock_received(svsk, ready);
+		svc_sock_received(svsk);
 		return -EAGAIN;	/* record not complete */
 	}
-	/* if we think there is only one more record to read, but
-	 * it is bigger than we expect, then two records must have arrived
-	 * together, so pretend we aren't using the record.. */
-	if (len > svsk->sk_reclen && ready == 1)
-		used = 0;
-	else	used = 1;
+	set_bit(SK_DATA, &svsk->sk_flags);
 
 	/* Frob argbuf */
 	bufp->iov[0].iov_base += 4;
@@ -716,20 +870,24 @@
 	svsk->sk_reclen = 0;
 	svsk->sk_tcplen = 0;
 
-	svc_sock_received(svsk, used);
+	svc_sock_received(svsk);
 	if (serv->sv_stats)
 		serv->sv_stats->nettcpcnt++;
 
 	return len;
 
-error:
+ err_delete:
+	svc_delete_socket(svsk);
+	return -EAGAIN;
+
+ error:
 	if (len == -EAGAIN) {
 		dprintk("RPC: TCP recvfrom got EAGAIN\n");
-		svc_sock_received(svsk, ready); /* Clear data ready */
+		svc_sock_received(svsk);
 	} else {
 		printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
 					svsk->sk_server->sv_name, -len);
-		svc_sock_received(svsk, 0);
+		svc_sock_received(svsk);
 	}
 
 	return len;
@@ -737,8 +895,6 @@
 
 /*
  * Send out data on TCP socket.
- * FIXME: Make the sendto call non-blocking in order not to hang
- * a daemon on a dead client. Requires write queue maintenance.
  */
 static int
 svc_tcp_sendto(struct svc_rqst *rqstp)
@@ -756,13 +912,11 @@
 
 	sent = svc_sendto(rqstp, bufp->iov, bufp->nriov);
 	if (sent != bufp->len<<2) {
-		printk(KERN_NOTICE "rpc-srv/tcp: %s: sent only %d bytes of %d - should shutdown socket\n",
+		printk(KERN_NOTICE "rpc-srv/tcp: %s: sent only %d bytes of %d - shutting down socket\n",
 		       rqstp->rq_sock->sk_server->sv_name,
 		       sent, bufp->len << 2);
-		/* FIXME: should shutdown the socket, or allocate more memort
-		 * or wait and try again or something.  Otherwise
-		 * client will get confused
-		 */
+		svc_delete_socket(rqstp->rq_sock);
+		sent = -EAGAIN;
 	}
 	return sent;
 }
@@ -782,21 +936,50 @@
 		dprintk("setting up TCP socket for reading\n");
 		sk->state_change = svc_tcp_state_change;
 		sk->data_ready = svc_tcp_data_ready;
+		sk->write_space = svc_write_space;
 
 		svsk->sk_reclen = 0;
 		svsk->sk_tcplen = 0;
+
+		set_bit(SK_CHNGBUF, &svsk->sk_flags);
 	}
 
 	return 0;
 }
 
+void
+svc_sock_update_bufs(struct svc_serv *serv)
+{
+	/*
+	 * The number of server threads has changed. 
+	 * flag all socket to the snd/rcv buffer sizes
+	 * updated.
+	 * We don't just do it, as the locking is rather
+	 * awkward at this point
+	 */
+	struct list_head *le;
+
+	spin_lock_bh(&serv->sv_lock);
+	list_for_each(le, &serv->sv_permsocks) {
+		struct svc_sock *svsk = 
+			list_entry(le, struct svc_sock, sk_list);
+		set_bit(SK_CHNGBUF, &svsk->sk_flags);
+	}
+	list_for_each(le, &serv->sv_tempsocks) {
+		struct svc_sock *svsk =
+			list_entry(le, struct svc_sock, sk_list);
+		set_bit(SK_CHNGBUF, &svsk->sk_flags);
+	}
+	spin_unlock_bh(&serv->sv_lock);
+}
+
 /*
  * Receive the next request on any socket.
  */
 int
 svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
 {
-	struct svc_sock		*svsk;
+	struct svc_sock		*svsk =NULL;
 	int			len;
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -820,9 +1003,28 @@
 		return -EINTR;
 
 	spin_lock_bh(&serv->sv_lock);
-	if ((svsk = svc_sock_dequeue(serv)) != NULL) {
+	if (!list_empty(&serv->sv_tempsocks)) {
+		svsk = list_entry(serv->sv_tempsocks.next,
+				  struct svc_sock, sk_list);
+		/* apparently the "standard" is that clients close
+		 * idle connections after 5 minutes, servers after
+		 * 6 minutes
+		 *   http://www.connectathon.org/talks96/nfstcp.pdf 
+		 */
+		if (CURRENT_TIME - svsk->sk_lastrecv < 6*60
+		    || test_bit(SK_BUSY, &svsk->sk_flags))
+			svsk = NULL;
+	}
+	if (svsk) {
+		set_bit(SK_BUSY, &svsk->sk_flags);
+		set_bit(SK_CLOSE, &svsk->sk_flags);
+		rqstp->rq_sock = svsk;
+		svsk->sk_inuse++;
+	} else if ((svsk = svc_sock_dequeue(serv)) != NULL) {
 		rqstp->rq_sock = svsk;
 		svsk->sk_inuse++;
+		rqstp->rq_reserved = serv->sv_bufsz;	
+		svsk->sk_reserved += rqstp->rq_reserved;
 	} else {
 		/* No data pending. Go to sleep */
 		svc_serv_enqueue(serv, rqstp);
@@ -859,6 +1061,14 @@
 		svc_sock_release(rqstp);
 		return -EAGAIN;
 	}
+	svsk->sk_lastrecv = CURRENT_TIME;
+	if (test_bit(SK_TEMP, &svsk->sk_flags)) {
+		/* push active sockets to end of list */
+		spin_lock_bh(&serv->sv_lock);
+		list_del(&svsk->sk_list);
+		list_add_tail(&svsk->sk_list, &serv->sv_tempsocks);
+		spin_unlock_bh(&serv->sv_lock);
+	}
 
 	rqstp->rq_secure  = ntohs(rqstp->rq_addr.sin_port) < 1024;
 	rqstp->rq_userset = 0;
@@ -935,8 +1145,9 @@
 	svsk->sk_sk = inet;
 	svsk->sk_ostate = inet->state_change;
 	svsk->sk_odata = inet->data_ready;
+	svsk->sk_owspace = inet->write_space;
 	svsk->sk_server = serv;
-	spin_lock_init(&svsk->sk_lock);
+	svsk->sk_lastrecv = CURRENT_TIME;
 
 	/* Initialize the socket */
 	if (sock->type == SOCK_DGRAM)
@@ -956,9 +1167,16 @@
 		return NULL;
 	}
 
+
 	spin_lock_bh(&serv->sv_lock);
-	svsk->sk_list = serv->sv_allsocks;
-	serv->sv_allsocks = svsk;
+	if (!pmap_register) {
+		set_bit(SK_TEMP, &svsk->sk_flags);
+		list_add(&svsk->sk_list, &serv->sv_tempsocks);
+		serv->sv_tmpcnt++;
+	} else {
+		clear_bit(SK_TEMP, &svsk->sk_flags);
+		list_add(&svsk->sk_list, &serv->sv_permsocks);
+	}
 	spin_unlock_bh(&serv->sv_lock);
 
 	dprintk("svc: svc_setup_socket created %p (inet %p)\n",
@@ -993,6 +1211,7 @@
 		return error;
 
 	if (sin != NULL) {
+		sock->sk->reuse = 1; /* allow address reuse */
 		error = sock->ops->bind(sock, (struct sockaddr *) sin,
 						sizeof(*sin));
 		if (error < 0)
@@ -1019,7 +1238,6 @@
 void
 svc_delete_socket(struct svc_sock *svsk)
 {
-	struct svc_sock	**rsk;
 	struct svc_serv	*serv;
 	struct sock	*sk;
 
@@ -1030,23 +1248,18 @@
 
 	sk->state_change = svsk->sk_ostate;
 	sk->data_ready = svsk->sk_odata;
+	sk->write_space = svsk->sk_owspace;
 
 	spin_lock_bh(&serv->sv_lock);
 
-	for (rsk = &serv->sv_allsocks; *rsk; rsk = &(*rsk)->sk_list) {
-		if (*rsk == svsk)
-			break;
-	}
-	if (!*rsk) {
-		spin_unlock_bh(&serv->sv_lock);
-		return;
-	}
-	*rsk = svsk->sk_list;
-	if (svsk->sk_qued)
-		rpc_remove_list(&serv->sv_sockets, svsk);
+	list_del(&svsk->sk_list);
+	if (test_bit(SK_TEMP, &svsk->sk_flags))
+		serv->sv_tmpcnt--;
+	if (test_bit(SK_QUED, &svsk->sk_flags))
+		list_del(&svsk->sk_ready);
 
 
-	svsk->sk_dead = 1;
+	set_bit(SK_DEAD, &svsk->sk_flags);
 
 	if (!svsk->sk_inuse) {
 		spin_unlock_bh(&serv->sv_lock);
diff -urN linux-2.4.20-pre1/net/sunrpc/xprt.c linux-2.4.20-pre2/net/sunrpc/xprt.c
--- linux-2.4.20-pre1/net/sunrpc/xprt.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/sunrpc/xprt.c	Mon Aug 12 16:34:17 2002
@@ -370,7 +370,7 @@
 
 	sock_release(sock);
 	/*
-	 *	TCP doesnt require the rpciod now - other things may
+	 *	TCP doesn't require the rpciod now - other things may
 	 *	but rpciod handles that not us.
 	 */
 	if(xprt->stream)
@@ -498,25 +498,15 @@
 static inline struct rpc_rqst *
 xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
 {
-	struct rpc_task	*head, *task;
 	struct rpc_rqst	*req;
-	int		safe = 0;
+	struct list_head *le;
+	struct rpc_task *task;
 
 	spin_lock_bh(&rpc_queue_lock);
-	if ((head = xprt->pending.task) != NULL) {
-		task = head;
-		do {
-			if ((req = task->tk_rqstp) && req->rq_xid == xid)
-				goto out;
-			task = task->tk_next;
-			if (++safe > 100) {
-				printk("xprt_lookup_rqst: loop in Q!\n");
-				goto out_bad;
-			}
-		} while (task != head);
-	}
+	task_for_each(task, le, &xprt->pending.tasks)
+		if ((req = task->tk_rqstp) && req->rq_xid == xid)
+			goto out;
 	dprintk("RPC:      unknown XID %08x in reply.\n", xid);
- out_bad:
 	req = NULL;
  out:
 	if (req && !__rpc_lock_task(req->rq_task))
@@ -1344,9 +1334,9 @@
 	} else
 		xprt_default_timeout(&xprt->timeout, xprt->prot);
 
-	xprt->pending = RPC_INIT_WAITQ("xprt_pending");
-	xprt->sending = RPC_INIT_WAITQ("xprt_sending");
-	xprt->backlog = RPC_INIT_WAITQ("xprt_backlog");
+	INIT_RPC_WAITQ(&xprt->pending, "xprt_pending");
+	INIT_RPC_WAITQ(&xprt->sending, "xprt_sending");
+	INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog");
 
 	/* initialize free list */
 	for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++)
diff -urN linux-2.4.20-pre1/net/unix/af_unix.c linux-2.4.20-pre2/net/unix/af_unix.c
--- linux-2.4.20-pre1/net/unix/af_unix.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-pre2/net/unix/af_unix.c	Mon Aug 12 16:34:17 2002
@@ -183,7 +183,7 @@
 		/*
 		 *	This may look like an off by one error but it is
 		 *	a bit more subtle. 108 is the longest valid AF_UNIX
-		 *	path for a binding. sun_path[108] doesnt as such
+		 *	path for a binding. sun_path[108] doesn't as such
 		 *	exist. However in kernel space we are guaranteed that
 		 *	it is a valid memory location in our kernel
 		 *	address buffer.
